Reputation: 4490
Can the Jackson code that handles annotation mixins be reused by third-parties to mixin non-Jackson annotations?
What are the core Jackson classes that process mixins?
Upvotes: 0
Views: 758
Reputation: 4724
You have to implement the interface com.fasterxml.jackson.databind.ser.ContextualSerializer
and/or com.fasterxml.jackson.databind.deser.ContextualDeserializer
. Jackson serializes and deserializes JSON. If this is not your intention, you will get some overhead and another approach could be better (e.g. a solution with AspectJ).
If you are interested in the implementation of Jackson and how the (de)serializers are used:
This project contains the general-purpose data-binding functionality and tree-model for Jackson Data Processor. It builds on core streaming parser/generator package, and uses Jackson Annotations for configuration.
A good entry point for analysis: ObjectMapper
This code demonstrates the use of a custom annotation (used in a mixin) and how a suitable (de)serializer could be implemented:
public class MyBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
/////
import com.fasterxml.jackson.annotation.JacksonAnnotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation // important so that it will get included!
public @interface MyAnnotation {
public String value();
}
/////
public abstract class MyMixin {
@MyAnnotation("Hello")
public abstract String getValue();
}
/////
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
import java.io.IOException;
public class MyDeserializer extends JsonDeserializer<String> implements ContextualDeserializer {
private String annoValue;
public MyDeserializer(){}
public MyDeserializer(MyAnnotation ann) {
annoValue = ann.value();
}
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String serializedValue = p.getText();
return serializedValue.substring(annoValue.length() + 1, serializedValue.length() - 1);
}
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty prop) throws JsonMappingException {
MyAnnotation ann = prop.getAnnotation(MyAnnotation.class);
if (ann == null) {
ann = prop.getContextAnnotation(MyAnnotation.class);
}
if (ann == null) {
return new StringDeserializer();
}
return new MyDeserializer(ann);
}
}
/////
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StringSerializer;
import java.io.IOException;
public class MySerializer extends JsonSerializer<String> implements ContextualSerializer {
private String annoValue;
public MySerializer() {}
public MySerializer(MyAnnotation ann) {
annoValue = ann.value();
}
@Override
public void serialize(String toSerialize, JsonGenerator gen, SerializerProvider prov) throws IOException {
gen.writeString(annoValue + " " + toSerialize + "!");
}
public JsonSerializer createContextual(SerializerProvider prov, BeanProperty prop) throws JsonMappingException {
MyAnnotation ann = prop.getAnnotation(MyAnnotation.class);
if (ann == null) {
ann = prop.getContextAnnotation(MyAnnotation.class);
}
if (ann == null) {
return new StringSerializer();
}
return new MySerializer(ann);
}
}
/////
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(String.class, new MySerializer());
module.addDeserializer(String.class, new MyDeserializer());
mapper.registerModule(module);
mapper.addMixIn(MyBean.class, MyMixin.class);
MyBean bean = new MyBean();
bean.setValue("World");
String jsonInString = mapper.writeValueAsString(bean);
System.out.println(jsonInString);
MyBean deserialized = mapper.readValue(jsonInString, MyBean.class);
System.out.println(deserialized.getValue());
}
}
Upvotes: 1