-
-
Save sscovil/8788339 to your computer and use it in GitHub Desktop.
public class Asset { | |
private AssetType type; | |
@JsonTypeInfo( | |
use = JsonTypeInfo.Id.NAME, | |
include = JsonTypeInfo.As.EXTERNAL_PROPERTY, | |
property = "type" | |
) | |
@JsonSubTypes({ | |
@JsonSubTypes.Type(value = ImageAssetProperties.class, name = "image"), | |
@JsonSubTypes.Type(value = DocumentAssetProperties.class, name = "document") | |
}) | |
private AssetProperties properties; | |
public String getType() { | |
return type.toString(); | |
} | |
@JsonProperty("type") | |
public void setType(String type) { | |
this.type = AssetType.fromString(type); | |
} | |
@JsonIgnore | |
public void setType(AssetType type) { | |
this.type = type; | |
} | |
public AssetProperties getProperties() { | |
return properties; | |
} | |
public void setProperties(AssetProperties properties) { | |
this.properties = properties; | |
} | |
} |
public interface AssetProperties { | |
String getSource(); | |
AssetProperties setSource(String source); | |
String getProxy(); | |
AssetProperties setProxy(String proxy); | |
} |
public enum AssetType { | |
IMAGE("image"), | |
DOCUMENT("document"); | |
private String string; | |
AssetType(String string) { | |
this.string = string; | |
} | |
public static AssetType fromString(String string) { | |
// Enum.valueOf() method is case sensitive; this method is not. | |
if (string != null) | |
for (AssetType assetType : AssetType.values()) | |
if (string.equalsIgnoreCase(assetType.toString())) | |
return assetType; | |
throw new IllegalArgumentException(String.format("%s is not a valid AssetType.", string); | |
} | |
public String toString() { | |
return this.string; | |
} | |
} |
public class DocumentAssetProperties implements AssetProperties { | |
private String source; | |
private String proxy; | |
public String getSource() { | |
return source; | |
} | |
public DocumentAssetProperties setSource(String source) { | |
this.source = source; | |
return this; | |
} | |
public String getProxy() { | |
return proxy; | |
} | |
public DocumentAssetProperties setProxy(String proxy) { | |
this.proxy = proxy; | |
return this; | |
} | |
} |
public class ImageAssetProperties implements AssetProperties { | |
private String source; | |
private String proxy; | |
private Integer height; | |
private Integer width; | |
public String getSource() { | |
return source; | |
} | |
public ImageAssetProperties setSource(String source) { | |
this.source = source; | |
return this; | |
} | |
public String getProxy() { | |
return proxy; | |
} | |
public ImageAssetProperties setProxy(String proxy) { | |
this.proxy = proxy; | |
return this; | |
} | |
public Integer getHeight() { | |
return height; | |
} | |
public ImageAssetProperties setHeight(Integer height) { | |
this.height = height; | |
return this; | |
} | |
public Integer getWidth() { | |
return width; | |
} | |
public ImageAssetProperties setWidth(Integer width) { | |
this.width = width; | |
return this; | |
} | |
} |
public class PolymorphicDeserializationTests { | |
@Test | |
public void deserializeJsonSucceeds() { | |
Asset asset = deserializeJson("{ \"type\": \"document\", \"properties\": { \"source\": \"foo\", \"proxy\": \"bar\" } }"); | |
Assert.assertTrue(asset.getProperties() instanceof DocumentAssetProperties); | |
} | |
public Asset deserializeJson(String json) { | |
ObjectMapper mapper = new ObjectMapper(); | |
try { | |
return mapper.readValue(json, Asset.class); | |
} | |
catch(IOException e) { | |
Assert.fail("Could not deserialize JSON.", e); | |
} | |
return null; | |
} | |
} |
I also had some difficulty getting this to work. I was receiving the following exception
com.fasterxml.jackson.databind.JsonMappingException: Missing property 'content'
for external type id 'contentType
I ended up having to add the @JsonTypeId
annotation to the type field referenced as the EXTERNAL_PROPERTY
public interface Content {
}
public class Post implements Content {
public String content = "bar";
}
public class Foo {
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "contentType")
@JsonSubTypes({
@JsonSubTypes.Type(value = Post.class, name = "post")
})
public Content content;
@JsonTypeId
public ContentType contentType;
public enum ContentType {
"post"
}
}
I believe this Stack Exchange question is a similar issue.
Any idea how you'd do this without using an external property?
I've got a setup that looks like this:
1st request
{
"foo": "bar",
"a": {
"spam": "lots of spam",
}
}
2nd request
{
"foo": "bar",
"b": {
"eggs": "lots of eggs",
}
}
public interface AB { }
@JsonTypeName("b")
public class A implements AB {
@JsonProperty("spam")
public String spam:
}
@JsonTypeName("b")
public class B implements AB {
@JsonProperty("eggs")
public String eggs;
}
public class Container {
@JsonProperty("foo")
public String foo;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({@JsonSubTypes.Type(value = A.class), @JsonSubTypes.Type(value = B.class)})
public AB ab;
}
However my tests trying to deserialize a container end with Unrecognized field "a", not marked as ignorable (2 known properties: "foo", "ab") ...
:\
I'm trying serialize java object to JSON by skipping the interface class name in the serialized string. Is there a way we can do it?
The details are at: https://stackoverflow.com/questions/45270140/how-to-serialize-java-to-json-without-including-the-interface-name-in-the-serial
I've tried to use this approach and unfortunately this does not work for me. So now instead of having 1 instance there are two. One precedes the object and after that follows it. When I'm trying to de-serialize the first object causes a problem like:
"Missing property 'name' for external type id"