2012-09-20 13 views
26

Chciałbym wiedzieć, w jaki sposób można uzyskać biblioteki Jackson JSON do deserializacji JSON do istniejącego obiektu? Próbowałem znaleźć jak to zrobić; ale wydaje się, że jest w stanie wziąć klasę i sam ją utworzyć.Deserializować JSON do istniejącego obiektu (Java)

Jeśli nie jest to możliwe, chciałbym wiedzieć, czy może to zrobić dowolna biblioteka deserializacji JSON Java. Jest to odpowiednie pytanie dla języka C#: Overlay data from JSON string to existing object instance. Wygląda na to, że JSON.NET ma PopulateObject (ciąg, obiekt).

+0

Czy obejrzałeś Gsona? http://code.google.com/p/google-gson/ – yodamad

+0

Tylko pobieżnie. Czy może to zrobić powyżej? –

+0

Wygląda na to, że nie ma problemu z Gsonem "Problem 431: Wypełnij istniejący obiekt" pod adresem http://code.google.com/p/google-gson/issues/detail?id=431 –

Odpowiedz

39

Można to zrobić przy użyciu Jackson:

mapper.readerForUpdating(object).readValue(json); 

Zobacz także Merging Two JSON Documents Using Jackson

+0

Dzięki, @boberj - Dziwne, że nikt nie zdołał tego znaleźć wcześniej; ta funkcja musiała być w Jackson w czasie, o który prosiłem, ponieważ twój link jest do starszej odpowiedzi opisującej to. –

+1

Ale niestety w tym przypadku "readValue" nie będzie generować wyjątków, jeśli nie można parsować 'json'. Czy można przywrócić normalne zachowanie? – Hubbitus

0

Jednym z rozwiązań jest przeanalizowanie nowego wykresu obiektów/drzewa, a następnie ujednolicenie-kopiowanie do istniejącego grafu/drzewa obiektów. Ale to oczywiście mniej wydajne i więcej pracy, zwłaszcza jeśli konkretne typy różnią się ze względu na mniejszą dostępność informacji o typie. (Tak naprawdę nie jest to odpowiedź.) Mam nadzieję, że jest lepsza odpowiedź, po prostu chcę uniknąć odpowiedzi innych w ten sposób.)

1

Jeśli możesz użyć innej biblioteki zamiast Jacksona, możesz wypróbować Genson http://owlike.github.io/genson/. Poza kilkoma innymi ciekawymi funkcjami (takimi jak deserializacja przy użyciu niepustego konstruktora bez adnotacji, przekształcanie do postaci polimorficznych itp.), Obsługa deseni JavaBeans odbywa się w istniejącej instancji. Oto przykład:

BeanDescriptorProvider provider = new Genson().getBeanDescriptorFactory(); 
BeanDescriptor<MyClass> descriptor = provider.provide(MyClass.class, genson); 
ObjectReader reader = new JsonReader(jsonString); 
MyClass existingObject = descriptor.deserialize(existingObject, reader, new Context(genson)); 

Jeśli masz jakieś pytania nie wahaj się wykorzystać swoją listę mailingową http://groups.google.com/group/genson.

+0

Dzięki, na pewno popatrzę! Oto ich pierwszy cel i wygląda obiecująco: "Bądź jak najbardziej rozszerzalny, pozwalając użytkownikom dodawać nowe funkcje w czysty i łatwy sposób. Genson stosuje filozofię, że "nie możemy myśleć o każdym przypadku użycia, więc dajemy użytkownikom możliwość robienia tego samodzielnie w łatwy sposób". " –

+0

Świetnie, mam nadzieję, że ci się spodoba, w rzeczywistości jestem autorem gensonów =) – eugen

0

FlexJson może również pomóc Ci zrobić to samo.

Oto przykład skopiowane z FlexJson Doc

Funkcja deserializeInto bierze swój ciąg i odniesienie do istniejącego obiektu.

Person charlie = new Person("Charlie", "Hubbard", cal.getTime(), home, work); 
Person charlieClone = new Person("Chauncy", "Beauregard", null, null, null); 
Phone fakePhone = new Phone(PhoneNumberType.MOBILE, "303 555 1234"); 
charlieClone.getPhones().add(fakePhone); 
String json = new JSONSerializer().include("hobbies").exclude("firstname", "lastname").serialize(charlie); 
Person p = new JSONDeserializer<Person>().deserializeInto(json, charlieClone); 

Należy pamiętać, że wartość referencyjna zwrócona w punkcie p jest taka sama jak wartość charlieClone tylko z zaktualizowanymi wartościami.

0

Użyłem Jackson DataBinder firmy Jackson + Spring, aby osiągnąć coś takiego. Ten kod obsługuje tablice, ale nie zagnieżdżone obiekty.

private void bindJSONToObject(Object obj, String json) throws IOException, JsonProcessingException { 
    MutablePropertyValues mpv = new MutablePropertyValues(); 
    JsonNode rootNode = new ObjectMapper().readTree(json); 
    for (Iterator<Entry<String, JsonNode>> iter = rootNode.getFields(); iter.hasNext();) { 
     Entry<String, JsonNode> entry = iter.next(); 
     String name = entry.getKey(); 
     JsonNode node = entry.getValue(); 
     if (node.isArray()) { 
      List<String> values = new ArrayList<String>(); 
      for (JsonNode elem : node) { 
       values.add(elem.getTextValue()); 
      } 
      mpv.addPropertyValue(name, values); 
      if (logger.isDebugEnabled()) { 
       logger.debug(name + "=" + ArrayUtils.toString(values)); 
      } 
     } 
     else { 
      mpv.addPropertyValue(name, node.getTextValue()); 
      if (logger.isDebugEnabled()) { 
       logger.debug(name + "=" + node.getTextValue()); 
      } 
     } 
    } 
    DataBinder dataBinder = new DataBinder(obj); 
    dataBinder.bind(mpv); 
} 
0

zawsze mógł załadować do fikcyjny obiekt i użyć refleksji do przesyłania danych. jeśli twoje serce jest ustawione na używaniu przykładu Gona

. zakładając ten kod znajduje się na obiekt, który chcesz skopiować dane do

public void loadObject(){ 
Gson gson = new Gson(); 
//make temp object 
YourObject tempStorage = (YourObject) gson.fromJson(new FileReader(theJsonFile), YourObject.class); 
//get the fields for that class 
ArrayList<Field> tempFields = new ArrayList<Field>(); 
ArrayList<Field> ourFields = new ArrayList<Field>(); 
getAllFields(tempFields, tempStorage.getClass()); 
getAllFields(thisObjectsFields, this.getClass()); 
for(Field f1 : tempFields){ 
    for(Field f2 : thisObjectsFields){ 
     //find matching fields 
     if(f1.getName().equals(f2.getName()) && f1.getType().equals(f2.getType())){ 
      //transient and statics dont get serialized and deserialized. 
      if(!Modifier.isTransient(f1.getModifiers())&&!Modifier.isStatic(f1.getModifiers())){ 
       //make sure its a loadable thing 
       f2.set(this, f1.get(tempStorage)); 
      } 
     } 
    } 
} 

}

public static List<Field> getAllFields(List<Field> fields, Class<?> type) { 
    for (Field field : type.getDeclaredFields()) { 
     fields.add(field); 
    } 
    if (type.getSuperclass() != null) { 
     fields = getAllFields(fields, type.getSuperclass()); 
    } 
    return fields; 
} 

1

Jeśli używasz ramy wiosny można użyć biblioteki BeanUtils dla tego zadania. Najpierw zendrializuj swój ciąg json, a następnie użyj obiektu BeanUtils, aby ustawić ten obiekt wewnątrz obiektu nadrzędnego. Oczekuje również, że nazwa zmiennej obiektu zostanie ustawiona w obiekcie nadrzędnym. Oto fragment kodu:

childObject = gson.fromJson("your json string",class.forName(argType)) 
BeanUtils.setProperty(mainObject, "childObjectName", childObject); 
+0

Dzięki. Obawiam się, że tak naprawdę nie robię tego, co zamierzałem. To wygląda jak "ręcznie" ustawiając pole/właściwość. –