Why when a constructor is annotated with @JsonCreator, its arguments must be annotated with @JsonProperty?
Jackson has to know in what order to pass fields from a JSON object to the constructor.
It is not possible to access parameter names in Java using reflection - that's why you have to repeat this information in annotations.
Is use of @JsonCreator necessary when using @JsonProperty?
Jackson has to know in what order to pass fields from a JSON object to the constructor. Because you have a single argument constructor, the creation works without @JsonCreator
From javadoc
Marker annotation that can be used to define constructors and factory
methods as one to use for instantiating new instances of the
associated class.NOTE: when annotating creator methods (constructors, factory methods),
method must either be:Single-argument constructor/factory method without JsonProperty
annotation for the argument: if so, this is so-called "delegate
creator", in which case Jackson first binds JSON into type of the
argument, and then calls creator Constructor/factory method where
every argument is annotated with either JsonProperty or JacksonInject,
to indicate name of property to bind to
Constructor annotated with Jackson @JsonCreator not being called in POJO?
After investigating some more I discovered the issue lies with the Spring Framework implementation of @JsonCreator - I removed the imports for org.springframework.cloud.cloudfoundry.com.fasterxml.jackson.annotation
and replaced them with com.fasterxml.jackson.annotation
. The above implementation now functions as expected.
I have been unable to find an explanation online as to why the spring version isn't working, so if anyone has any ideas please let me/ others know
Deserialize JSON with Jackson and @JsonCreator
From jackson annotations javadoc, @JsonPropertyOrder
is used for serialization, not deserialization:
Annotation that can be used to define ordering (possibly partial) to use when serializing object properties.
Also, when the constructor is annotated with @JsonCreator
, constructor must either be:
- Single-argument constructor/factory method without JsonProperty annotation for the argument: if so, this is so-called "delegate creator", in which case Jackson first binds JSON into type of the argument, and then calls creator.
- Constructor/factory method where every argument is annotated with either JsonProperty or JacksonInject, to indicate name of property to bind to.
The problem is that you try to deserialize from a json list ["17", 19561093, ".", ..]
to a PojoVariant
. Jackson is smart but not that smart. Here he needs some help and you can help him implementing a custom deserializer. We don't wanna do that, so let's hope we can find something else.
The hint comes from the @JsonCreator
javadoc (first bullet, bold text). And, because Jackson knows how to bind the list into an array of objects, we can rewrite PojoVariant
constructor like this:
@JsonCreator
public PojoVariant(Object[] params) {
this.chr = (String) params[0];
this.pos = (int) params[1];
this.id = (String) params[2];
this.ref = (String) params[3];
this.alt = (String) params[4];
this.quality = (int) params[5];
this.filter = (String) params[6];
this.type = (String) params[7];
this.genotype = (String) params[8];
this.alignPos = (int) params[9];
this.basePos = (int) params[10];
this.signalPos = (int) params[11];
}
How to deserialize a class with overloaded constructors using JsonCreator
Though its not properly documented, you can only have one creator per type. You can have as many constructors as you want in your type, but only one of them should have a @JsonCreator
annotation on it.
Flat JSON in Jackson for class/record/value object with one field
The combination of @JsonUnwrapped
and @JsonCreator
is not supported yet, so we can generate a solution like this:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.util.UUID;
public class AggregateTest {
static record AggregateId(@JsonProperty("aggregateId") UUID id) {}
static class Aggregate {
@JsonUnwrapped
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public final AggregateId _aggregateId;
public final String otherField;
@JsonCreator
public Aggregate(@JsonProperty("aggregateId") UUID aggregateId,
@JsonProperty("otherField") String otherField) {
this._aggregateId = new AggregateId(aggregateId);
this.otherField = otherField;
}
}
public static void main(String[] args) throws JsonProcessingException {
String rawJson =
"{\"aggregateId\": \"1f61aede-83dd-4049-a6ff-337887b6b807\"," +
"\"otherField\": \"İsmail Y.\"}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
Aggregate aggregate = objectMapper
.readValue(rawJson, Aggregate.class);
System.out.println(objectMapper
.writeValueAsString(aggregate));
}
}
Here we briefly get rid of the @JsonUnwrapped
field.
We get the UUID
with the name aggregateId
and create an AggregateId
record.
Detailed explanations about it:
- https://github.com/FasterXML/jackson-databind/issues/1467
- https://github.com/FasterXML/jackson-databind/issues/1497
Related Topics
Cannot Resolve Constructor Firefoxdriver(Org.Openqa.Selenium.Firefox.Firefoxprofile)
How to Have a Jtabbedpane with a Jmenubar
What Goes into the "Controller" in "Mvc"
Intellij Show Javadocs Tooltip on Mouse Over
Difference Between Arrays.Aslist(Array) and New Arraylist<Integer>(Arrays.Aslist(Array))
Java Equivalent of an Openssl Aes Cbc Encryption
How to Get My Maven Integration Tests to Run
Checking If a String Is Empty or Null in Java
Static VS. Dynamic Binding in Java
In Java, When Does an Object Become Unreachable
How to Get the Threadpoolexecutor to Increase Threads to Max Before Queueing
Difference Between & and && in Java
Selenium Many Logs (How to Remove)