2013-08-14 15 views
12

Ich benutze Jackson für JSON (de) Serialisierung in Verbindung mit Spring. Allerdings habe ich in einigen Fällen ein Problem mit einem Feld.Doppeltes JSON Feld mit Jackson

Ich habe eine abstrakte Klasse:

@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); 
     } 
    } 
} 

Und eine konkrete Klasse die abstrakte erweitern:

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

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

Das Problem ist, dass, wenn ich dieses JSON serialisiert, ich ein Duplikat mimeType Feld erhalten:

{ 
    "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" 
} 

ich habe versucht, die Empfehlung vonmitanswers Verwenden Sie die @JsonAutoDetect Annotation, um anzugeben, dass nur Felder in einer Klasse verwendet werden sollen, und setzen Sie dasselbe auf ObjectMapper, das behebt das Problem jedoch nicht.

Annotation:

@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

Ich weiß nicht, ob es hilfreich ist oder nicht, aber wenn Sie die Anmerkung entfernen '@JsonTypeInfo (use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "mimeType") 'von' AbstractBookmarkJsonModel' dann wirst du nur einen 'mimeType' in deinem json haben – Katona

Antwort

5

Dieses Verhalten wird durch die auf Klasse platziert Anmerkungen verursacht wird 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 Jackson erzählt die logischen Typnamen zur Serialisierung (JsonTypeInfo.Id.NAME) als Profi perty (JsonTypeInfo.As.PROPERTY) mit dem Namen mimeType (property = "mimeType"). Mit @JsonSubTypes.Type ordnen Sie den logischen Namen application/epub+zip der EpubBookmarkJsonModel zu.

Wenn es um die Serialisierung kommt, Jackson serialisiert die logischen Namen als Eigenschaft mimeType = "application/epub+zip" dann die Eigenschaften des Objekts unter ihnen mimeType, die den gleichen Wert wie der logische Name application/epub+zip (im Konstruktor zugewiesen) haben, geschieht.

Ich denke, mimeType sollte objectType im @JsonTypeInfo Anmerkung oder noch besser geändert werden, um das mimeType Feld zu entfernen, da Jackson kümmert, dass durch Art Info-Serialisierung nehmen.

+1

+1 das ist die richtige Antwort, Jackson fügt dem serialisierten JSON-Ausgang eine zusätzliche Eigenschaft hinzu Identifizieren Sie den Subtyp. In Ihrem Fall versuchen Sie, eine vorhandene Eigenschaft zu verwenden, das sollten Sie nicht tun. Ich weiß, dass Sie die Eigenschaft 'mimeType' nicht aus der Klasse entfernen können, weil ich denke, dass Sie sie brauchen. Verwenden Sie einfach einen anderen Subtype-Info-Property-Namen wie "SubtypName" und verwenden Sie als Subtyp-Namen etwas wie "ImageBookmark" und "EpubBookmark". Dies ist die beabsichtigte Verwendung von Jacksons Polymorphic Type Handling. –

6

Ich hatte genau dieses Problem mit der doppelten Ausgabe. Ich fand eine Lösung, die keine andere Eigenschaft beinhaltete, und erlaubte mir, die ursprüngliche Eigenschaft nicht zu entfernen. Zuerst setze ich das sichtbare Flag für JsonTypeInfo auf True. Dann fügte ich der Eigenschaftsdeklaration und dem Getter (aber nicht dem Setter) eine JsonIgnore-Annotation hinzu. Dies ist bisher die korrekte Ausgabe von JSON mit nur einem Schlüssel für die Eigenschaft 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; 
    } 

} 

Zu beachten ist dies mit fasterxml Jackson-databind 2.1.1

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

ich dies löste die JsonTypeInfo.As.EXISTING_PROPERTY in der @JsonTypeInfo Anmerkung unter Verwendung.

Das Projekt ist Open Source, überprüfen Sie es hier heraus: ANS.java

+1

Gute Lösung, mit visible = true auf @JsonTypeInfo (wenn nicht, ist die Eigenschaft null nach der Serialisierung) –

+0

Dies sollte meiner Meinung nach die akzeptierte Antwort sein. Es ist die sauberste Verwendung von Jackson. –

+0

Es funktionierte auf "toJson()", aber wenn ich "fromJson()" versuchte, wurde das Feld mit "Null" Wert verlassen. Irgendwelche Gedanken? – ozma

Verwandte Themen