Jackson Serialize Field to Different Name
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.
There is a far easier way to do this - create an objectmapper that uses the "addMixin" function.
Class to be serialized:
Class YouWantToSerializeMe {
public String firstName;
public String lastName;
public String gender;
@JsonProperty("firstName")
public String getFirstNameCC() {
return firstName;
}
@JsonProperty("lastName")
public String getLastNameCC() {
return lastName;
}
}
Now, to serialize using both the built-in field names and custom field names, you can do this:
Class DoTheSerializing {
String serializeNormally(YouWantToSerializeMe me) {
ObjectMapper objectMapper = new ObjectMapper();
ObjectWriter objectWriter = objectMapper.writer();
return objectWriter(me)
}
String serializeWithMixin(YouWantToSerializeMe me) {
ObjectMapper objectMapper = new ObjectMapper();
ObjectWriter objectWriter = objectMapper
.addMixIn(YouWantToSerializeMe.class, MyMixin.class)
.writer();
return objectWriter(me)
}
interface MyMixin {
@JsonProperty("first-name")
public String getFirstNameCC();
@JsonProperty("last-name")
public String getLastNameCC();
}
}
This uses an embedded interface in the class to keep things very local. You can make lots of optimizations around this, such as creating a static ObjectMapper and loading/unloading the mixin.
Using the interface as a "template" to control the mapping function is really powerful. You can add things at both the field and class level.