Ich habe eine Java-Klasse MyPojo
, die mich für die Deserialisierung von JSON interessiert. Ich habe eine spezielle MixIn-Klasse, MyPojoDeMixIn
, konfiguriert, um mich bei der Deserialisierung zu unterstützen. MyPojo
enthält nur int
- und String
-Instanzvariablen, die mit richtigen Gettern und Setters kombiniert werden. MyPojoDeMixIn
sieht ungefähr so aus:
public abstract class MyPojoDeMixIn {
MyPojoDeMixIn(
@JsonProperty("JsonName1") int prop1,
@JsonProperty("JsonName2") int prop2,
@JsonProperty("JsonName3") String prop3) {}
}
In meinem Testclient mache ich Folgendes, aber es funktioniert natürlich nicht zur Kompilierzeit, da es eine JsonMappingException
gibt, die mit einem Typenkonflikt zusammenhängt.
ObjectMapper m = new ObjectMapper();
m.getDeserializationConfig().addMixInAnnotations(MyPojo.class,MyPojoDeMixIn.class);
try { ArrayList<MyPojo> arrayOfPojo = m.readValue(response, MyPojo.class); }
catch (Exception e) { System.out.println(e) }
Ich bin mir bewusst, dass ich dieses Problem durch das Erstellen eines "Antwort" -Objekts lösen könnte, das nur einen ArrayList<MyPojo>
enthält, aber dann müsste ich diese etwas nutzlosen Objekte für jeden einzelnen Typ erstellen, den ich zurückgeben möchte.
Ich habe auch online nach JacksonInFiveMinutes nachgesehen -, hatte aber eine schreckliche Zeit, um das Zeug über Map<A,B>
zu verstehen und wie es sich auf mein Problem bezieht. Wenn Sie es nicht wissen können, bin ich mit Java völlig neu und komme aus einem Obj-C-Hintergrund. Sie erwähnen ausdrücklich:
Neben der Bindung an POJOs und "einfache" Typen gibt es einen zusätzliche Variante: die Bindung an generische (typisierte) Container . Dieser Fall erfordert eine besondere Behandlung aufgrund der sogenannten Typenlöschung (Wird von Java verwendet, um Generics in etwas abwärtskompatibler Weise zu implementieren), was die Verwendung von etwas wie .__ verhindert. Collection.class (wird nicht kompiliert).
Wenn Sie also Daten in eine Map einbinden möchten, müssen Sie Folgendes verwenden:
Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });
Wie kann ich direkt zu ArrayList
deserialisiert werden?
Mit dem Wrapper TypeReference
können Sie direkt zu einer Liste deserialisieren. Eine Beispielmethode:
public static <T> T fromJSON(final TypeReference<T> type,
final String jsonPacket) {
T data = null;
try {
data = new ObjectMapper().readValue(jsonPacket, type);
} catch (Exception e) {
// Handle the problem
}
return data;
}
Und wird so verwendet:
final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);
.
Eine andere Möglichkeit ist die Verwendung eines Arrays als Typ, z.
ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);
Auf diese Weise vermeiden Sie den Ärger mit dem Type-Objekt. Wenn Sie wirklich eine Liste benötigen, können Sie das Array jederzeit in eine Liste konvertieren:
List<MyPojo> pojoList = Arrays.asList(pojos);
IMHO ist das viel lesbarer.
Und damit es eine tatsächliche Liste ist (die geändert werden kann, siehe Einschränkungen von Arrays.asList()
), führen Sie einfach Folgendes aus:
List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));
Diese Variante wirkt einfacher und eleganter.
CollectionType typeReference =
TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);
Ich habe auch das gleiche Problem. Ich habe einen Json, der in ArrayList konvertiert werden soll.
Konto sieht so aus.
Account{
Person p ;
Related r ;
}
Person{
String Name ;
Address a ;
}
Alle oben genannten Klassen wurden ordnungsgemäß kommentiert Ich habe TypeReference> () {} Ausprobiert, funktioniert aber nicht.
Es gibt mir Arraylist, aber ArrayList hat eine linkedHashMap, die einige weitere verknüpfte Hashmaps enthält, die endgültige Werte enthalten.
Mein Code lautet wie folgt:
public T unmarshal(String responseXML,String c)
{
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);
mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
try
{
this.targetclass = (T) mapper.readValue(responseXML, new TypeReference<ArrayList<T>>() {});
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return this.targetclass;
}
Ich habe das Problem endlich gelöst. Ich kann die Liste in Json String wie folgt direkt in ArrayList konvertieren:
JsonMarshallerUnmarshaller<T>{
T targetClass ;
public ArrayList<T> unmarshal(String jsonString)
{
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);
mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
JavaType type = mapper.getTypeFactory().
constructCollectionType(ArrayList.class, targetclass.getClass()) ;
try
{
Class c1 = this.targetclass.getClass() ;
Class c2 = this.targetclass1.getClass() ;
ArrayList<T> temp = (ArrayList<T>) mapper.readValue(jsonString, type);
return temp ;
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null ;
}
}
Das funktioniert für mich.
@Test
public void cloneTest() {
List<Part> parts = new ArrayList<Part>();
Part part1 = new Part(1);
parts.add(part1);
Part part2 = new Part(2);
parts.add(part2);
try {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(parts);
List<Part> cloneParts = objectMapper.readValue(jsonStr, new TypeReference<ArrayList<Part>>() {});
} catch (Exception e) {
//fail("failed.");
e.printStackTrace();
}
//TODO: Assert: compare both list values.
}