Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson Serialize Field to Different Name

I have this JSON to deserialize:

{
    "first-name": "Alpha",
    "last-name": "Beta",
    "gender": "m"
}

I want to serialize it to 2 different formats:

[A]

{
    "first-name": "Alpha",
    "last-name": "Beta",
    "gender": "m"
}

[B]

{
    "firstName": "Alpha",
    "lastName": "Beta",
    "gender": "m"
}

I'm able to serialize it to 1 format: [A] only or [B] only. Here's my code to serialize it to [B]:

public String firstName;
public String lastName;
public String gender;

@JsonProperty("firstName")
public String getFirstNameCC() {
    return firstName;
}

@JsonProperty("first-name")
public void setFirstNameD(String firstName) {
    this.firstName = firstName;
}

@JsonProperty("lastName")
public String getLastNameCC() {
    return lastName;
}

@JsonProperty("last-name")
public void setLastNameD(String lastName) {
    this.lastName = lastName;
}

public String getGender() {
    return gender;
}

public void setGender(String gender) {
    this.gender = gender;
}

I read about JsonView here http://www.baeldung.com/jackson-json-view-annotation (section '5. Customize JSON Views') but it only changes its value. I want to change field name as example above. Can anyone give insight on this?

like image 774
shankshera Avatar asked Apr 15 '16 11:04

shankshera


People also ask

What is the difference between JsonProperty and JsonAlias?

@JsonProperty can change the visibility of logical property using its access element during serialization and deserialization of JSON. @JsonAlias defines one or more alternative names for a property to be accepted during deserialization.

What is JsonAlias?

The @JsonAlias annotation can define one or more alternate names for the attributes accepted during the deserialization, setting the JSON data to a Java object. But when serializing, i.e. getting JSON from a Java object, only the actual logical property name is used instead of the alias.

What is the use of @JsonProperty annotation?

The @JsonProperty annotation is used to map property names with JSON keys during serialization and deserialization. By default, if you try to serialize a POJO, the generated JSON will have keys mapped to the fields of the POJO.

How do you serialize with Jackson?

let's serialize a java object to a json file and then read that json file to get the object back. In this example, we've created Student class. We'll create a student. json file which will have a json representation of Student object.


Video Answer


1 Answers

I am not sure I completly understand your question, but for what I could understand you can do something like this to achieve different serializtions.

Create a custom annotation to hold all possible different serialization options:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomJsonProperty {
    String propertyName();

    String format();

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        CustomJsonProperty[] value();
    }

}

Annotate your class accordingly:

@JsonSerialize(using = CustomJsonPropertySerializer.class)
public class Bar {

    @CustomJsonProperty.List({
        @CustomJsonProperty(propertyName = "first-name", format = "A"),
        @CustomJsonProperty(propertyName = "firstName", format = "B")
    })
    private String firstName;

    @CustomJsonProperty.List({
            @CustomJsonProperty(propertyName = "last-name", format = "A"),
            @CustomJsonProperty(propertyName = "lastName", format = "B")
    })
    private String lastName;

    @CustomJsonProperty.List({
            @CustomJsonProperty(propertyName = "gender-x", format = "A"),
            @CustomJsonProperty(propertyName = "gender", format = "B")
    })
    private String gender;

    @JsonIgnore
    private String format;

    //getters & setters

}

Create a custom serializer to interpret your new annotation:

public class CustomJsonPropertySerializer extends JsonSerializer<Bar> {

    @Override
    public void serialize(Bar bar, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
            throws IOException {
        jsonGenerator.writeStartObject();

        Field[] fields = bar.getClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);
            Object value = null;

            try {
                value = field.get(bar);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

            if (field.isAnnotationPresent(CustomJsonProperty.List.class)) {
                CustomJsonProperty[] properties = field.getAnnotation(CustomJsonProperty.List.class).value();
                CustomJsonProperty chosenProperty = null;

                for (CustomJsonProperty c : properties) {
                    if (c.format().equalsIgnoreCase(bar.getFormat())) {
                        chosenProperty = c;
                        break;
                    }
                }

                if (chosenProperty == null) {
                    //invalid format given, use first format then
                    chosenProperty = properties[0];
                }

                jsonGenerator.writeStringField(chosenProperty.propertyName(), value.toString());
            }
        }

        jsonGenerator.writeEndObject();
    }
}

Now you can serialize your objects taking into consideration different formats for the property names:

public static void main(String[] args) throws IOException {
    Bar bar1 = new Bar("first", "last", "m", "A");
    Bar bar2 = new Bar("first", "last", "m", "B");

    ObjectMapper mapper = new ObjectMapper();
    String json1 = mapper.writeValueAsString(bar1);
    String json2 = mapper.writeValueAsString(bar2);

    System.out.println(json1);
    System.out.println(json2);

}

Output:

{"first-name":"first","last-name":"last","gender-x":"m"}
{"firstName":"first","lastName":"last","gender":"m"}

Of course the above serializer only works for Bar objects, but that can easily be solved using inheritance with abstract String getFormat(); on the super class and changing the custom serializer to accept the super class type, instead of Bar.

Maybe there is a simpler way than creating your own stuff, but I don't know about it. Let me know if something wasn't clear and I can elaborate it again.

like image 84
dambros Avatar answered Sep 22 '22 22:09

dambros