No matching constructor found for type when we use Enum-Jackson JSON
I have 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 have a JSON string that looks like this:
{
"type": "TEXT",
"rendering": "AUTO",
"content": "Lorem ipsum"
}
Now, since the fields in the class Content
are 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 annotate the original class using the constructor parameters, but Content
- from a library that I cannot change
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 will 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? Just by looking at the line number I suppose it is complaining about enum Type
, but how can I fix it?
PS: MixIn is set up correctly, because when I replace my enum paramer constructor with a String value, 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) {
}
source to share
Basically, I was importing the wrong type, because I was using Intellij and was oblivious when it asked which type to import.
It is extremely important to pay attention to types when working with Jackson.
Special thanks to @Sotirios, he gave me various suggestions on the matter which helped me a lot in debugging. It turns out I have 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
MixIn in my class and Content.Type
in my actual class. (They looked the same in code because Intellij was doing static imports)
I also found that you should always use List<T>
JSON ( [...]
) for arrays instead ofT[]
source to share