2013-08-14 31 views
12

Sto usando Jackson per la serializzazione JSON (de) in congiunzione con Spring. Tuttavia, sto avendo un problema con un campo che è in alcuni casi due volte.Duplicate JSON Field con Jackson

devo una classe astratta:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "mimeType") 
@JsonSubTypes({ 
    @JsonSubTypes.Type(value = ImageBookmarkJsonModel.class, name = "image/jpeg"), 
    @JsonSubTypes.Type(value = EpubBookmarkJsonModel.class, name = "application/epub+zip") 
}) 
public abstract class AbstractBookmarkJsonModel extends AbstractJsonModel { 
    protected String mimeType; 
    // Removed other fields for brevity 

    public String getMimeType() { 
     return mimeType; 
    } 

    public void setMimeType(String mimeType) { 
     this.mimeType = mimeType; 
    } 

    @Override 
    public String toString() { 
     ObjectMapper mapper = new ObjectMapper(); 

     try { 
      return mapper.writeValueAsString(this); 
     } catch (IOException e) { 
      throw new IllegalStateException("Cannot convert object of type " + this.getClass().toString() + " to JSON", e); 
     } 
    } 
} 

E una classe concreta estendere l'astratto:

public class EpubBookmarkJsonModel extends AbstractBookmarkJsonModel { 
    private static final long serialVersionUID = 1L; 
    // Removed other fields for brevity 

    public EpubBookmarkJsonModel() { 
     this.mimeType = "application/epub+zip"; 
    } 
} 

Il problema è che quando ho serializzare questo JSON, ottengo un duplicato mimeType campo:

{ 
    "mimeType": "application/epub+zip", 
    "mimeType": "application/epub+zip", 
    "userId": 24, 
    "acid": "ACID-000000000029087", 
    "added": "2013-08-14T12:02:17Z", 
    "epubBookmarkId": 34, 
    "cfi": "epubcfi(/6/4!/2/68)", 
    "context": "CONTEXT" 
} 

Ho provato a utilizzare la raccomandazione di previousanswers per utilizzare l'annotazione @JsonAutoDetect per specificare che devono essere utilizzati solo i campi di una classe e impostare lo stesso su ObjectMapper, tuttavia ciò non risolve il problema.

della nota:

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, 
     setterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE, 
     isGetterVisibility = JsonAutoDetect.Visibility.NONE) 

ObjectMapper:

ObjectMapper mapper = new ObjectMapper(); 
    mapper.getSerializationConfig().getDefaultVisibilityChecker() 
      .withFieldVisibility(JsonAutoDetect.Visibility.ANY) 
      .withGetterVisibility(JsonAutoDetect.Visibility.NONE) 
      .withSetterVisibility(JsonAutoDetect.Visibility.NONE) 
      .withCreatorVisibility(JsonAutoDetect.Visibility.NONE); 
+0

Non so se è utile o meno, ma se si rimuove l'annotazione '@JsonTypeInfo (uso = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, proprietà = "mimeType") 'da' AbstractBookmarkJsonModel', allora avrai solo un 'mimeType' nel tuo json – Katona

risposta

5

Questo comportamento è causato dalle annotazioni immessi sul classe AbstractBookmarkJsonModel:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "mimeType") 
@JsonSubTypes({ 
    @JsonSubTypes.Type(value = ImageBookmarkJsonModel.class, name = "image/jpeg"), 
    @JsonSubTypes.Type(value = EpubBookmarkJsonModel.class, name = "application/epub+zip") 
}) 

@JsonTypeInfo dice Jackson per serializzare il nome del tipo di logica (JsonTypeInfo.Id.NAME) come professionista perty (JsonTypeInfo.As.PROPERTY) con nome mimeType (property = "mimeType"). Con @JsonSubTypes.Type si assegna il nome logico application/epub+zip a EpubBookmarkJsonModel.

Quando si tratta di serializzazione, Jackson serializza il nome logico come proprietà mimeType = "application/epub+zip" quindi le proprietà dell'oggetto tra loro mimeType che succede ad avere lo stesso valore come il nome logico application/epub+zip (assegnato nel costruttore).

Penso mimeType dovrebbe essere cambiata a objectType nel @JsonTypeInfo annotazione o ancora meglio per rimuovere il campo mimeType dal Jackson si prenderà cura di che, attraverso informazioni Gruppo serializzazione.

+1

+1 questa è la risposta giusta, Jackson aggiunge una proprietà addizionale all'output JSON serializzato a identificare il sottotipo. Nel tuo caso provi a usare una proprietà esistente, non dovresti farlo. So che non puoi rimuovere la proprietà 'mimeType' dalla classe perché penso che ne hai bisogno. È sufficiente utilizzare un altro nome di proprietà di informazioni di sottotipo come "subtypeName" e come nomi di sottotipo usare qualcosa come "' ImageBookmark' "e" 'EpubBookmark'". Questo è l'uso previsto di Jacksons Polymorphic Type Handling. –

6

Stavo avendo lo stesso identico problema con l'output duplicato. Ho trovato una soluzione che non coinvolge un'altra proprietà e mi ha permesso di non rimuovere la proprietà originale. Per prima cosa, ho impostato il flag visibile su true per JsonTypeInfo. Quindi, ho aggiunto un'annotazione JsonIgnore alla dichiarazione di proprietà e al getter (ma non al setter). Si tratta di un output di JSON che funziona correttamente con una sola chiave per la proprietà type.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "mimeType") 
@JsonSubTypes({ 
    @JsonSubTypes.Type(value = ImageBookmarkJsonModel.class, name = "image/jpeg"), 
    @JsonSubTypes.Type(value = EpubBookmarkJsonModel.class, name = "application/epub+zip") 
}) 
public abstract class AbstractBookmarkJsonModel extends AbstractJsonModel { 
    @JsonIgnore 
    @JsonProperty("mimeType") 
    protected String mimeType; 

    @JsonIgnore 
    @JsonProperty("mimeType") 
    public String getMimeType() { 
     return mimeType; 
    } 

    @JsonProperty("mimeType") 
    public void setMimeType(String mimeType) { 
     this.mimeType = mimeType; 
    } 

} 

Da notare, questo è con fasterxml Jackson-databind 2.1.1

<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-databind</artifactId> 
    <version>2.1.1</version> 
</dependency> 
15

Ho risolto questo utilizzando il JsonTypeInfo.As.EXISTING_PROPERTY nella nota @JsonTypeInfo.

Il progetto è open source, verificarlo qui: ANS.java

+1

Buona soluzione, con visible = true su @JsonTypeInfo (in caso contrario, la proprietà è nullo dopo la serializzazione) –

+0

Questa dovrebbe essere la risposta accettata, secondo me. È l'uso più pulito di Jackson. –

+0

Ha funzionato su "toJson()" ma quando ho provato "fromJson()" il campo è stato lasciato con valore "null". qualche idea? – ozma

Problemi correlati