web-dev-qa-db-fra.com

Désérialiser JSON en objet existant (Java)

Je voudrais savoir comment obtenir la bibliothèque Jackson JSON pour désérialiser JSON en un objet existant? J'ai essayé de trouver comment faire cela; mais il semble pouvoir seulement prendre une classe et l'instancier elle-même.

Sinon, j'aimerais savoir si des bibliothèques de désérialisation JSON Java Java peuvent le faire).

Cela semble être une question correspondante pour C #: superposer les données de la chaîne JSON à l'instance d'objet existante . Il semble que JSON.NET ait un PopulateObject (chaîne, objet).

36
Jonas N

Vous pouvez le faire en utilisant Jackson:

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

Voir aussi Fusion de deux documents JSON à l'aide de Jackson

67
Johan Boberg

Si vous utilisez Spring Framework, vous pouvez utiliser la bibliothèque BeanUtils pour cette tâche. Désérialisez d'abord votre chaîne json normalement, puis utilisez BeanUtils pour définir cet objet dans un objet parent. Il s'attend également à ce que le nom de variable de l'objet soit défini à l'intérieur de l'objet parent. Voici l'extrait de code:

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

Si vous pouvez utiliser une autre bibliothèque au lieu de Jackson, vous pouvez essayer Genson http://owlike.github.io/genson/ . En plus de certaines autres fonctionnalités de Nice (telles que la désérialisation en utilisant un constructeur non vide sans aucune annotation, la désérialisation en types polymorphes, etc.), il prend en charge la désérialisation de JavaBean dans une instance existante. Voici un exemple:

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));

Si vous avez des questions, n'hésitez pas à utiliser sa liste de diffusion http://groups.google.com/group/genson .

1
eugen

Vous pouvez utiliser mes référentiels :).

Object yo = //yourObject
String js = //json source

Map remote = Object$.remoteMap(yo, false); //or you can use Bean.forInstance(yo);
Reader reader = new StringReader(js);//you can replace this with any reader :)
AtomicReference buffer = new AtomicReference(remote);

try {
    JSON.global.parse(buffer, reader, null, null);
} catch (IOException ignored) {
    //If any exception got thrown by the reader
}

de cette façon, JSON analysera les valeurs de la carte qu'il trouve dans le tampon. Et si la carte contient une liste et que la valeur JSON a également une liste. La liste sur la carte ne sera pas remplacée. à la place, il sera utilisé pour contenir les valeurs.

Si vous avez utilisé Bean.forInstance(yo) la carte distante renvoyée aura quelques fonctionnalités supplémentaires.

référentiels:

utiliser repo (obligatoire): github.com/cufyorg/util

dépôt de base (obligatoire): github.com/cufyorg/base

Repo JSON (obligatoire): github.com/cufyorg/json

repo de haricots (facultatif): github.com/cufyorg/beans

0
LSafer SE

J'ai utilisé le DataBinder de Jackson + Spring pour accomplir quelque chose comme ça. Ce code gère les tableaux mais pas les objets imbriqués.

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
splashout

flexJson peut également vous aider à faire de même.

Voici un exemple copié de FlexJson Doc

La fonction deserializeInto prend votre chaîne et référence à un objet existant.

 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);

Notez que la référence retournée dans p est la même que charlieClone avec seulement des valeurs mises à jour.

0
faizan

pourrait toujours se charger dans un objet factice et utiliser la réflexion pour transférer les données. si votre cœur est prêt à utiliser gson

exemple. en supposant que ce code se trouve dans l'objet dans lequel vous souhaitez copier les données

    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;
}
0
Jordan Haynes

Une solution consiste à analyser un nouveau graphique/arbre d'objets, puis à unifier-copier dans le graphique/arbre d'objets existant. Mais c'est bien sûr moins efficace et plus de travail, surtout si les types de béton diffèrent en raison de la disponibilité moindre des informations de type. (Donc pas vraiment une réponse. J'espère qu'il y a une meilleure réponse, je veux juste éviter que d'autres répondent de cette façon.)

0
Jonas N