{
vendors: [
{
vendor: {
id: 367,
name: "Kuhn-Pollich",
company_id: 1,
}
},
{
vendor: {
id: 374,
name: "Sawayn-Hermann",
company_id: 1,
}
}]
}
J'ai un objet Vendor qui peut être correctement désérialisé à partir d'un seul json "vendor", mais je souhaite le désérialiser dans un Vendor[]
, Je n'arrive pas à comprendre comment faire coopérer Jackson. Des conseils?
Vos données sont problématiques car vous avez des objets wrapper internes dans votre tableau. Vraisemblablement, votre objet Vendor
est conçu pour gérer id
, name
, company_id
, mais chacun de ces objets est également encapsulé dans un objet avec une propriété unique vendor
.
Je suppose que vous utilisez le modèle de Jackson Data Binding .
Si oui, il y a deux choses à considérer:
Le premier utilise une propriété spéciale de configuration de Jackson. Jackson - depuis la version 1.9, cela n’est peut-être pas disponible si vous utilisez une ancienne version de Jackson - fournit UNWRAP_ROOT_VALUE
. Il est conçu pour les cas où vos résultats sont encapsulés dans un objet de propriété unique de niveau supérieur que vous souhaitez supprimer.
Alors, jouez avec:
objectMapper.configure(SerializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
La seconde utilise des objets wrapper. Même après avoir supprimé l'objet enveloppe externe, le problème de vos objets Vendor
est toujours encapsulé dans un objet à propriété unique. Utilisez un wrapper pour contourner ceci:
class VendorWrapper
{
Vendor vendor;
// gettors, settors for vendor if you need them
}
De même, au lieu d'utiliser UNWRAP_ROOT_VALUES
, vous pouvez également définir une classe wrapper pour gérer l’objet externe. En supposant que vous ayez le bon objet Vendor
, VendorWrapper
, vous pouvez définir:
class VendorsWrapper
{
List<VendorWrapper> vendors = new ArrayList<VendorWrapper>();
// gettors, settors for vendors if you need them
}
// in your deserialization code:
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readValue(jsonInput, VendorsWrapper.class);
L'arborescence des objets de VendorsWrapper est analogue à votre JSON:
VendorsWrapper:
vendors:
[
VendorWrapper
vendor: Vendor,
VendorWrapper:
vendor: Vendor,
...
]
Enfin, vous pouvez utiliser le modèle d'arbre de ) de Jackson pour analyser ceci dans JsonNodes
, en ignorant le nœud externe, et pour chaque JsonNode
dans le ArrayNode
, appelez:
mapper.readValue(node.get("vendor").getTextValue(), Vendor.class);
Cela pourrait entraîner moins de code, mais cela ne semble pas moins maladroit que d'utiliser deux wrappers.
Voici une solution brute mais plus déclarative. Je n'ai pas réussi à le résumer à une seule annotation, mais cela semble bien fonctionner. Aussi pas sûr de la performance sur les grands ensembles de données.
Étant donné ce JSON:
{
"list": [
{
"wrapper": {
"name": "Jack"
}
},
{
"wrapper": {
"name": "Jane"
}
}
]
}
Et ces objets modèles:
public class RootObject {
@JsonProperty("list")
@JsonDeserialize(contentUsing = SkipWrapperObjectDeserializer.class)
@SkipWrapperObject("wrapper")
public InnerObject[] innerObjects;
}
et
public class InnerObject {
@JsonProperty("name")
public String name;
}
Où le voodoo de Jackson est implémenté comme:
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface SkipWrapperObject {
String value();
}
et
public class SkipWrapperObjectDeserializer extends JsonDeserializer<Object> implements
ContextualDeserializer {
private Class<?> wrappedType;
private String wrapperKey;
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property) throws JsonMappingException {
SkipWrapperObject skipWrapperObject = property
.getAnnotation(SkipWrapperObject.class);
wrapperKey = skipWrapperObject.value();
JavaType collectionType = property.getType();
JavaType collectedType = collectionType.containedType(0);
wrappedType = collectedType.getRawClass();
return this;
}
@Override
public Object deserialize(JsonParser parser, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
ObjectNode objectNode = mapper.readTree(parser);
JsonNode wrapped = objectNode.get(wrapperKey);
Object mapped = mapIntoObject(wrapped);
return mapped;
}
private Object mapIntoObject(JsonNode node) throws IOException,
JsonProcessingException {
JsonParser parser = node.traverse();
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(parser, wrappedType);
}
}
J'espère que cela est utile à quelqu'un!
@ Patrick j'améliorerais un peu votre solution
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectNode objectNode = jp.readValueAsTree();
JsonNode wrapped = objectNode.get(wrapperKey);
JsonParser parser = node.traverse();
parser.setCodec(jp.getCodec());
Vendor mapped = parser.readValueAs(Vendor.class);
return mapped;
}
Ça marche plus vite :)