I got a class that looks like this:
public class Content {
public enum Type {
TEXT, URL, FILE
}
public enum Rendering {
MARKDOWN, HTML, PLAIN, AUTO
}
public final Type type;
public final Rendering rendering;
public final String content;
public Content(Type type, Rendering rendering, String content) {
this.type = type;
this.rendering = (rendering != null ? rendering : Rendering.AUTO);
this.content = content;
}
}
And I got a JSON string that looks like this:
{
"type": "TEXT",
"rendering": "AUTO",
"content": "Lorem ipsum"
}
Now, because fields in Content
class is final, Jackson won't work, so I use MixIns:
public abstract static class ContentMixIn {
@JsonCreator
public ContentMixIn(@JsonProperty("type") Type type,
@JsonProperty("rendering") Rendering rendering,
@JsonProperty("content") String content) {
}
}
Note: I could have annotated the original class using the constructor parameters, but Content
is from a library which I cannot modify
And this is how I use them:
// ...
SimpleModule module = new SimpleModule();
module.setMixInAnnotation(Content.class, ContentMixIn.class);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
mapper.readValue("<the json>", Content.class);
This would throw:
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.foo.Content]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: {
"type": "TEXT",
"rendering": "AUTO",
"content": "Lorem ipsum"
}; line: 2, column: 2]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1063)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:264)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:124)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3051)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2146)
Why? By simpley looking at the line number, I assume It's complaining about the enum Type
, but how do I correct this?
PS: MixIn is setup correctly because when I replace my Content constructor's enum paramater with String values, it works(although not the way I want it):
// ... in the Content class
public Content(String type, String rendering, String content) {
this.type = null;
this.rendering = null;
this.content = content;
}
// ... in the mixin class
@JsonCreator
public ContentMixIn(@JsonProperty("type") String type,
@JsonProperty("rendering") String rendering,
@JsonProperty("content") String content) {
}
Basically, I imported the wrong type because I was using Intellij and didn't pay attention when it asked which type to import.
When working with Jackson, it is extremely important to pay attention to the types.
Special thanks to @Sotirios, he gave me various suggestions on this question which helped me a lot on debugging. It turns out that I got another class that looks like this:
public static class Image {
public enum Display {
COVER, CONTAIN, START, END
}
public enum Type {
BASE64, FILE, URL
}
public final Type type; // <-- this!
public final Display display;
public final int padding;
public final String content;
public Image(Type type, Display display, int padding, String content) {
this.type = type;
this.display = display;
this.padding = padding;
this.content = content;
}
}
Jackson failed because I was using Image.Type
in my MixIn class and Content.Type
in my actual class. (They looked identical in code because Intellij did a static import)
I also discovered that you should always use List<T>
for JSON arrays([...]
) instead of T[]
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments