2011-06-22 5 views
13

J'essaye de désérialiser un tableau JSON dans une collection Java en utilisant Jackson. Cela motivé par les réponses à cette question que j'ai demandé hier soir Can I instantiate a superclass and have a particular subclass be instantiated based on the parameters supplied.Désérialisation de Jackson ... Jeton inattendu (END_OBJECT),

L'erreur que je suis Gettings est (sauts de ligne ajoutée pour la lisibilité):

org.codehaus.jackson.map.JsonMappingException: 
    Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'type' 
    that is to contain type id (for class sempedia.model.query.QueryValue) 
at [Source: [email protected]; line: 1, column: 175] 
    (through reference chain: sempedia.model.query.QueryProperty["values"]) 

Ma situation est assez compliquée. Mon tableau contient des objets qui eux-mêmes contiennent une valeur qui est un tableau. Ce tableau contient à son tour des valeurs qui sont aussi des objets mais ne sont pas nécessairement les mêmes (donc polymorphisme).

Voici une chaîne JSON exemple:

[ 
    { 
     "id":"74562", 
     "uri":"http://dbpedia.org/ontology/family", 
     "name":"family", 
     "values":[ 
     { 
      "id":"74563", 
      "uri":"http://dbpedia.org/resource/Orycteropodidae", 
      "name":"Orycteropodidae" 
     } 
     ], 
     "selected":false 
    }, 
    { 
     "id":"78564", 
     "uri":"http://dbpedia.org/ontology/someNumber", 
     "name":"someNumber", 
     "values":[ 
     { 
      "lower":"45", 
      "upper":"975", 
     } 
     ], 
     "selected":true 
    } 
] 

Je voudrais utiliser (ci-dessous) code ou quelque chose de similaire pour obtenir un objet qui est une instance de Collection<QueryProperty> que j'ai appelé queryProperties

ObjectMapper mapper = new ObjectMapper(); 
Collection<QueryProperty> queryProperties = 
    queryProperties = mapper.readValue(query, 
     new TypeReference<Collection<QueryProperty>>(){}); 

Mes classes pour désérialisation (ils ont getters publics/setters que je ne suis pas l'impression) sont énumérés ci-dessous:

public class QueryProperty {  
    int id; 
    String uri; 
    String name; 
    Set<QueryValue> values; 
    String selected; 
} 

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") 
@JsonSubTypes({ 
    @Type(value = ResourceQueryValue.class), 
    @Type(value = NumericQueryValue.class) 
    }) 
public abstract class QueryValue { 
    String type; 
} 

ResourceQueryValue

public class ResourceQueryValue extends QueryValue{ 
    int id; 
    String uri; 
    String name; 
} 

NumericQueryValue même JSON ne comprend pas un objet de ce type.

public class NumericQueryValue extends QueryValue{ 
    double lower; 
    double upper; 
} 

partie initiale de la trace de pile:

org.codehaus.jackson.map.JsonMappingException: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'type' that is to contain type id (for class sempedia.model.query.QueryValue) 
at [Source: [email protected]; line: 1, column: 175] (through reference chain: sempedia.model.query.QueryProperty["values"]) 
    at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163) 
    at org.codehaus.jackson.map.deser.StdDeserializationContext.wrongTokenException(StdDeserializationContext.java:240) 
    at org.codehaus.jackson.map.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:86) 
    at org.codehaus.jackson.map.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:89) 

Répondre

15

Comme il arrive souvent, l'écriture sur une question que vous aide à voir la solution. Donc j'ai besoin de faire deux choses. Premièrement, j'ai besoin d'ajouter les informations de type dans le JSON - ce qui n'est pas ce que je voulais vraiment faire, mais je suppose que vous devez fournir cette information quelque part.

Et je besoin de modifier l'annotation sur QueryValue être:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") 
@JsonSubTypes({ 
    @Type(value = ResourceQueryValue.class, name = "ResourceQueryValue"), 
    @Type(value = NumericQueryValue.class, name= "NumericQueryValue") 
    }) 
+0

Oui, une information de type supplémentaire doit être ajouté d'une certaine façon. Pour ce que cela vaut, le nom par défaut pour les sous-types doit être un nom de type non qualifié (ce que vous avez). Mais c'est probablement une bonne idée d'être explicite, juste au cas où. – StaxMan

+2

Comment avez-vous ajouté le type d'information @ankur. J'essaye de faire ça avec angularJS. Merci beaucoup. –