Deserialiser JSON dans un objet existant (Java)
j'aimerais savoir comment on peut amener la bibliothèque Jackson JSON à desérialiser JSON en un objet existant? J'ai essayé de trouver comment le faire, mais il semble être seulement en mesure de prendre un cours et instanciate lui-même.
ou si ce n'est pas possible, j'aimerais savoir si des bibliothèques de desérialisation Java JSON peuvent le faire.
cela semble être une question correspondante pour C#: données de superposition de la chaîne JSON à l'instance d'objet existante . Il semble JSON.NET a un objet PopulateObject (string,object).
7 réponses
vous pouvez le faire en utilisant Jackson:
mapper.readerForUpdating(object).readValue(json);
Voir aussi la Fusion des Deux Documents JSON à l'Aide de Jackson
si vous pouvez utiliser une autre bibliothèque au lieu de Jackson, vous pouvez essayer Genson http://owlike.github.io/genson / . En plus de quelques autres fonctionnalités intéressantes (telles que deserialize utilisant un constructeur non vide sans aucune annotation, deserialize à des types polymorphiques, etc) il supporte la desé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 .
si vous utilisez spring framework, vous pouvez utiliser la bibliothèque BeanUtils pour cette tâche. Tout d'abord, désérialisez votre chaîne json normalement, puis utilisez BeanUtils pour placer cet objet à l'intérieur d'un objet parent. Il attend également de la variable nom de l'objet à définir à 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);
Une solution consiste à analyser un nouvel objet graphique/arbre, et ensuite unifier-copie de l'objet graphique/arbre. Mais c'est évidemment moins efficace, et plus de travail, surtout si les types concrets diffèrent en raison de la moins grande disponibilité de l'information sur les types. (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.)
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 à l'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 en p est la même que charlieClone juste avec les valeurs mises à jour.
j'ai utilisé la base de données 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);
}
peut toujours charger dans un objet factice et utiliser la réflexion pour transférer les données. si votre cœur est mis sur juste en utilisant gson
exemple. en supposant que ce code est dans l'objet que vous voulez copier les données dans
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;
}