Reputation: 3389
In my DTO class, there could be fields which might have same @JsonAlias values, but this seems not working with Jackson ObjectMapper.
It seems that ObjectMapper only works for the first occurrence of @JsonAlias and it don't work for the rest @JsonAlias which has same value. I have tried to create an example below for the reference and in that example, Person class has the two fields with name @JsonAlias value.
Code snippet:
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<String, String> values = new HashMap<>();
values.put("name", "TEST NAME");
Person person = new ObjectMapper().convertValue(values, Person.class);
System.out.println("name1: " + person.getName1());
System.out.println("name2: " + person.getName2());
}
static class Person {
@JsonAlias("name")
String name1;
@JsonAlias("name")
String name2;
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
}
}
}
Output:
name1: TEST NAME
name2: null
In the above output. I was expecting the "TEST NAME" for the name2 variable in Person class.
Is there any configuration in Jackson ObjectMapper which will help me to achieve this?
Jackson version - jackson-databind-2.11.4.jar
Upvotes: 0
Views: 3446
Reputation: 6015
Solution 1, @JsonGetter
@JsonSetter
point out to the custom getter\setter
We can use @JsonGetter("name") and @JsonSetter("name") annotations to map one JSON property value to the setter which has handling two properties
public class Person {
@JsonIgnore
private String name1;
@JsonIgnore
private String name2;
@JsonSetter("name")
public void setName(String name) {
this.name1 = name;
this.name2 = name;
}
@JsonGetter("name")
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
}
}
Solution 2, @JsonAlias
with the specific setter
We can ignore one field, the second mark with an alias, and add a custom setName
setter that maps one JSON value to several fields.
public class Person {
@JsonAlias("name")
private String name1;
@JsonIgnore
private String name2;
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name1) {
this.name1 = name1;
}
public void setName(String name) {
this.name1 = name;
this.name2 = name;
}
}
Or just add a custom setName
setter to your original code
public class Person {
@JsonAlias("name")
String name1;
@JsonAlias("name")
String name2;
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name1) {
this.name1 = name1;
}
public void setName(String name) {
this.name1 = name;
this.name2 = name;
}
}
Solution 3, @JsonProperty
with the specific setter
The same like Solution 2, but instead use @JsonProperty("name")
public class Person {
@JsonProperty("name")
private String name1;
@JsonIgnore
private String name2;
public String getName1() {
return name1;
}
@JsonIgnore
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name1) {
this.name1 = name1;
}
public void setName(String name) {
this.name1 = name;
this.name2 = name;
}
}
UPDATE:
In case you do not have the ability to modify DTO object, custom deserializer resolve the problem.
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
public class PersonDeserializer extends StdDeserializer<Person> {
public PersonDeserializer() {
this(null);
}
public PersonDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Person deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
Person person = new Person();
JsonNode node = jp.getCodec().readTree(jp);
String name = node.get("name").asText();
person.setName1(name);
person.setName2(name);
return person;
}
}
Apply deserializer to the DTO object:
@JsonDeserialize(using = PersonDeserializer.class)
public class Person {
private String name1;
private String name2;
//getters and setters
}
OR register custom deserializer on ObjectMapper
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Person.class, new PersonDeserializer());
mapper.registerModule(module);
Upvotes: 2