2016-06-24 4 views
0

Ich habe eine große JSON-Datei, die aus Strukturen besteht, die ich in POJOs zuordnen und dann in einer Sammlung speichern. Die Struktur ist ähnlich wie folgt aus:Benutzerdefinierte Jackson Deserializer, um die Zuordnung bestimmter Objekte zu vermeiden

[ 
{ 
    "id": 1234, 
    "file": "C:\\Programs\\Program1.exe", 
    "exists": true 
} 
{ 
    "id": 5678, 
    "file": "C:\\Programs\\Program2.exe", 
    "exists": false 
} 
... 
] 

die Jackson-Streaming-API Ich habe alle haben diese Strukturen zu lesen, und die POJOs in einer Sammlung erfolgreich gespeichert. Meine POJO Klasse sieht wie folgt aus:

public class Programs 
{ 
    @JsonProperty("id") 
    private Integer id; 

    @JsonProperty("file") 
    private String file; 

    @JsonProperty("exists") 
    private Boolean exists; 

    @JsonGetter("id") 
    public Integer getId() 
    { 
     return id; 
    } 

    @JsonGetter("file") 
    public String getFile() 
    { 
     return file; 
    } 

    @JsonGetter("exists") 
    public Boolean getExists() 
    { 
     return exists; 
    } 
} 

Allerdings habe ich keine Strukturen verzichten möchten, die "exists" Satz false während der Deserialisierung haben, so dass kein POJO jemals für sie erstellt wird. Also schrieb ich einen benutzerdefinierten Deserializer mit Hilfe dieser Frage SO [How do I call the default deserializer from a custom deserializer in Jackson], mit meiner außer Kraft gesetzt deserialize sieht aus wie:

@Override 
public Programs deserialize(JsonParser parser, DeserializationContext context) 
    throws IOException 
{ 
    Programs programs = (Programs)defaultDeserializer.deserialize(parser, context); 

    if (!programs.getExists()) 
    { 
     throw context.mappingException("[exists] value is false."); 
    } 
    return programs; 
} 

Allerdings, wenn ich einige Unit-Tests laufen lasse, erhalte ich folgende Fehlermeldung:

"Can not deserialize instance of java.util.ArrayList out of START_OBJECT token" 
message was "Class com.myprogram.serializer.ProgramsJsonDeserializer 
has no default (no arg) constructor" 

(Hinzufügen eines nicht arg Konstruktor erhält man die Fehlermeldung, dass StdDeserializer keinen Default-Konstruktor hat.)

Ist das der richtige Ansatz, um zu erreichen, was ich tun möchte? Und weiß jemand, warum ich diese Fehlermeldung bekomme?

Antwort

1

I want to omit any structures that have "exists" set to false during the deserialization process so that no POJO is ever created for them.

Ich denke, Ihr Ziel ist es, eine Liste von Programs Instanz abzurufen, die nur exists Satz true nach derserialization haben. Eine maßgeschneiderte CollectionDeserializer filtern die unerwünschten Beispiel helfen können:

public class ProgramsCollectionHandler extends SimpleModule { 
    private static class ProgramsCollectionDeserializer extends CollectionDeserializer { 

     public ProgramsCollectionDeserializer(CollectionDeserializer deserializer) { 
      super(deserializer); 
     } 

     private static final long serialVersionUID = 1L; 

     @Override 
     public Collection<Object> deserialize(JsonParser parser, DeserializationContext context) 
       throws IOException, JsonProcessingException { 
      Collection<Object> result = super.deserialize(parser, context); 
      Collection<Object> filteredResult = new ArrayList<Object>(); 
      for (Object o : result) { 
       if (o instanceof Programs) { 
        final Programs programs = (Programs) o; 
        if (programs.exists) { 
         filteredResult.add(programs); 
        } 
       } 
      } 
      return filteredResult; 
     } 

     @Override 
     public CollectionDeserializer createContextual(
       DeserializationContext context, 
       BeanProperty property) throws JsonMappingException { 
      return new ProgramsCollectionDeserializer(super.createContextual(context, property)); 
     } 
    } 

    private static final long serialVersionUID = 1L; 

    @Override 
    public void setupModule(Module.SetupContext context) { 
     super.setupModule(context); 
     context.addBeanDeserializerModifier(new BeanDeserializerModifier() { 
      @Override 
      public JsonDeserializer<?> modifyCollectionDeserializer(
        DeserializationConfig config, CollectionType type, 
        BeanDescription beanDesc, JsonDeserializer<?> deserializer) { 
       if (deserializer instanceof CollectionDeserializer) { 
        return new ProgramsCollectionDeserializer(
          (CollectionDeserializer) deserializer); 
       } else { 
        return super.modifyCollectionDeserializer(config, type, beanDesc, 
          deserializer); 
       } 
      } 
     }); 
    } 
} 

Danach wird Ihr es in Ihrem Objekt-Mapper registrieren:

ObjectMapper mapper = new ObjectMapper(); 
mapper.registerModule(new ProgramsCollectionHandler()); 

"Can not deserialize instance of java.util.ArrayList out of START_OBJECT token" message was "Class com.myprogram.serializer.ProgramsJsonDeserializer has no default (no arg) constructor" (Adding a no arg constructor gives the error that StdDeserializer does not have a default constructor.)

Dies kann, weil Ihr Konstruktor nicht zugegriffen werden kann. Zum Beispiel ist Ihr Deserializer als eine nicht statische innere Klasse implementiert.

+0

Vielen Dank, das scheint der Trick! – MeanwhileInHell

Verwandte Themen