Jackson: How to add custom property to the JSON without modifying the POJO
Asked Answered
S

12

83

I am developing a REST interface for my app using Jackson to serialize my POJO domain objects to JSON representation. I want to customize the serialization for some types to add additional properties to the JSON representation that do not exist in POJOs (e.g. add some metadata, reference data, etc). I know how to write my own JsonSerializer, but in that case I would need to explicitly call JsonGenerator.writeXXX(..) methods for each property of my object while all I need is just to add an additional property. In other words I would like to be able to write something like:

@Override
public void serialize(TaxonomyNode value, JsonGenerator jgen, SerializerProvider provider) {
    jgen.writeStartObject();
    jgen.writeAllFields(value); // <-- The method I'd like to have
    jgen.writeObjectField("my_extra_field", "some data");
    jgen.writeEndObject();
}

or (even better) to somehow intercept the serialization before the jgen.writeEndObject() call, e.g.:

@Override void beforeEndObject(....) {
    jgen.writeObjectField("my_extra_field", "some data");
}

I thought I could extend BeanSerializer and override its serialize(..) method but it's declared final and also I couldn't find an easy way to create a new instance of BeanSerializer without providing it with all the type metadata details practically duplicating a good portion of Jackson. So I've given up on doing that.

My question is - how to customize Jackson's serialization to add additional stuff to the JSON output for particular POJOs without introducing too much of the boilerplate code and reusing as much as possible of the default Jackson behaviour.

Samuele answered 5/2, 2013 at 18:28 Comment(1)
Since Jackson-2.5 JsonAppend annotation can solve this problem. See @Henrik answer belowChild
S
-2

After looking more on the Jackson source code I concluded that it's simply impossible to achieve without writing my own BeanSerializer, BeanSerializerBuilder and BeanSerializerFactory and provide some extension points like:

/*
/**********************************************************
/* Extension points
/**********************************************************
 */

protected void beforeEndObject(T bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JSONException {
    // May be overridden
}

protected void afterStartObject(T bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JSONException {
    // May be overridden
}

Unfortunately I had to copy and paste entire Jackson's BeanSerializer source code to MyCustomBeanSerializer because the former is not developed for extensions declaring all the fields and some important methods (like serialize(...)) as final

Samuele answered 7/2, 2013 at 13:28 Comment(2)
Improper use of final is for Code-Nazis. Often I faced it myself not being able to extend existing code, just because of final methods or classes. And don't argue with performance: #4279920Deliladelilah
@Deliladelilah I wouldn't jump to conclusions there. If a developer choose to make a class final then that may very well be a well thought-out decision. Opening up classes for extension is a decision that shouldn't be made lightly.Sardonyx
M
49

Jackson 2.5 introduced the @JsonAppend annotation, which can be used to add "virtual" properties during serialization. It can be used with the mixin functionality to avoid modifying the original POJO.

The following example adds an ApprovalState property during serialization:

@JsonAppend(
    attrs = {
        @JsonAppend.Attr(value = "ApprovalState")
    }
)
public static class ApprovalMixin {}

Register the mixin with the ObjectMapper:

mapper.addMixIn(POJO.class, ApprovalMixin.class);

Use an ObjectWriter to set the attribute during serialization:

ObjectWriter writer = mapper.writerFor(POJO.class)
                          .withAttribute("ApprovalState", "Pending");

Using the writer for serialization will add the ApprovalState field to the ouput.

Minta answered 25/2, 2017 at 11:22 Comment(6)
This is the actual answer to the question. Looks like the Jackson-way to do it!Prem
This solves a specific facet of the problem but not the issue itself. In my case, I need to wrap an object with the value of a variable, which means an annotation won't work. (Something similar to OP's example code, like startObject(); fieldName(myVariable);, allFields(obj); endObject();, endObject(); is what I need).Burglar
this value: Pending is a static value. how to get the runtime value from another field? any solution ? I am looking forward to your replySimferopol
@user3033075: You should create a new ObjectWriter instance for each write, and setting the attribute with the value that is current for that particular write.Vellicate
@HenrikAastedSørensen thanks for your reply. it seems to work for general contidtion. but my problem is to return spring REST API data. because javascript can't deserialize the long type java field. we want to add a dynamic value for the long type value (like mysql table primary key : id) .Simferopol
Why did they make you do both withAttribute(..) and @JsonAppend? If I just want to append an attribute, why can't I do a @JsonAppend to specify what I want and be done with it?Boyar
M
37

Since (I think) Jackson 1.7 you can do this with a BeanSerializerModifier and extending BeanSerializerBase. I've tested the example below with Jackson 2.0.4.

import java.io.IOException;

import org.junit.Test;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.ser.impl.ObjectIdWriter;
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;


public class JacksonSerializeWithExtraField {

    @Test
    public void testAddExtraField() throws Exception
    {
        ObjectMapper mapper = new ObjectMapper();

        mapper.registerModule(new SimpleModule() {

            public void setupModule(SetupContext context) {
                super.setupModule(context);

                context.addBeanSerializerModifier(new BeanSerializerModifier() {

                    public JsonSerializer<?> modifySerializer(
                            SerializationConfig config,
                            BeanDescription beanDesc,
                            JsonSerializer<?> serializer) {
                        if (serializer instanceof BeanSerializerBase) { 
                              return new ExtraFieldSerializer(
                                   (BeanSerializerBase) serializer);
                        } 
                        return serializer; 

                    }                   
                });
            }           
        });

        mapper.writeValue(System.out, new MyClass());       
        //prints {"classField":"classFieldValue","extraField":"extraFieldValue"}
    }


    class MyClass {

        private String classField = "classFieldValue";

        public String getClassField() { 
            return classField; 
        }
        public void setClassField(String classField) { 
            this.classField = classField; 
        }
    }


    class ExtraFieldSerializer extends BeanSerializerBase {

        ExtraFieldSerializer(BeanSerializerBase source) {
            super(source);
        }

        ExtraFieldSerializer(ExtraFieldSerializer source, 
                ObjectIdWriter objectIdWriter) {
            super(source, objectIdWriter);
        }

        ExtraFieldSerializer(ExtraFieldSerializer source, 
                String[] toIgnore) {
            super(source, toIgnore);
        }

        protected BeanSerializerBase withObjectIdWriter(
                ObjectIdWriter objectIdWriter) {
            return new ExtraFieldSerializer(this, objectIdWriter);
        }

        protected BeanSerializerBase withIgnorals(String[] toIgnore) {
            return new ExtraFieldSerializer(this, toIgnore);
        }

        public void serialize(Object bean, JsonGenerator jgen,
                SerializerProvider provider) throws IOException,
                JsonGenerationException {           
            jgen.writeStartObject();                        
            serializeFields(bean, jgen, provider);
            jgen.writeStringField("extraField", "extraFieldValue"); 
            jgen.writeEndObject();
        }
    }
}
Maxma answered 12/3, 2013 at 15:55 Comment(2)
confirmed that it works with 2.0.4. In 2.4.1 there are two new abstract methods to implement (just copy from BeanSerializer), and modifySerializer gets a StringSerializer, too, which cannot be cast. So you must do an instanceof check before you cast to BeanSerializerBaseExtrasensory
I think people should know about "virtual property" feature in Jackson appeared since 2.5. This feature had been explained in answer belowChild
U
25

You can do this (previous version did not work with Jackson after 2.6, but this works with Jackson 2.7.3):

public static class CustomModule extends SimpleModule {
    public CustomModule() {
        addSerializer(CustomClass.class, new CustomClassSerializer());
    }

    private static class CustomClassSerializer extends JsonSerializer {
        @Override
        public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
            //Validate.isInstanceOf(CustomClass.class, value);
            jgen.writeStartObject();
            JavaType javaType = provider.constructType(CustomClass.class);
            BeanDescription beanDesc = provider.getConfig().introspect(javaType);
            JsonSerializer<Object> serializer = BeanSerializerFactory.instance.findBeanSerializer(provider,
                    javaType,
                    beanDesc);
            // this is basically your 'writeAllFields()'-method:
            serializer.unwrappingSerializer(null).serialize(value, jgen, provider);
            jgen.writeObjectField("my_extra_field", "some data");
            jgen.writeEndObject();
        }
    }
}

Update:

I tried it out with Jackson 2.9.0 and 2.9.6 and it worked as expected with both. Perhaps try this out: http://jdoodle.com/a/z99 (run it locally - jdoodle apparently can't handle Jackson).

Urbina answered 18/8, 2014 at 9:58 Comment(17)
it's works, but i don't understand why you use null values in findValueSerializer and unwrappingSerializer methodsSino
@herau: The first null is to indicate that I am serializing a root object. The second null is because I do not want to apply a name-transformation.Urbina
is it possible to select a custom JsonSerializer ?Sino
I tried this, but the findValueSerializer always returns the same CustomClassSerializer, so it goes into an infinite recursion. Also, findValueSerializer won't work with 'value' as it requires a type, not an Ojbect.Upstage
i get the infinite loop too, am i missing something?Claro
I have the same issue, it gets into infinite loop with latest jackson code.Churchy
@DavidA: The code was broken with Jackson 2.5, but I have added a fixed version that works with Jackson 2.7.Urbina
@LasseJacobs I tried it out with Jackson 2.9.0 and 2.9.6 and it worked as expected with both. Perhaps try this out: jdoodle.com/a/z99 (run it locally - jdoodle apparently can't handle Jackson).Urbina
Just a heads up: This is as good, the only one that worked for me, but it didn't honor options like objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);.Eustacia
@acdcjunior, I had issue that this code skipped null value. I added extra line: ((BeanSerializerBase) serializer).resolve(provider); Maybe it helps you with JsonInclude.Include. I did not testedIrreligious
Hi @RasmusFaber, I need to edit the name of "existing field" in POJO instead of adding "extra_field". Is it possible with this approach? Please note I do not want to use JsonProperty annotation. Requirement is, I have a POJO and want to use different field name every time without change in POJO. For example I have a field "c_id" in POJO and some times it need to write as "cust_id" and another time it would be "my_id". Could you please suggest? Thanks.Structural
@Feku279, not directly. But if you make a new question, I will take a look.Urbina
@RasmusFaber #62066114Structural
instead of null in unwrappingSerializer(null) you could use: unwrappingSerializer(NameTransformer.NOP) - looks betterRevolutionary
also instead of creating new Serializer in constructor you should inject default serializer through BeanSerializerModifier as shown here: https://mcmap.net/q/244191/-how-to-access-default-jackson-serialization-in-a-custom-serializerRevolutionary
@devstructor, he's not creating the default serializer there, but the custom one. He's looking up the default serializer through the factory.Aquitaine
I get the error Type id handling not implemented for type package.Class (by serializer of type package.CustomModule$CustomClassSerializer). I have added all the required packages from latest Jackson 4.13.2: jackson-core, jackson-databind, jackson-annotations, jackson-datatype-jdk8Decree
E
23

Though this question is already answered, I found another way that requires no special Jackson hooks.

static class JsonWrapper<T> {
    @JsonUnwrapped
    private T inner;
    private String extraField;

    public JsonWrapper(T inner, String field) {
        this.inner = inner;
        this.extraField = field;
    }

    public T getInner() {
        return inner;
    }

    public String getExtraField() {
        return extraField;
    }
}

static class BaseClass {
    private String baseField;

    public BaseClass(String baseField) {
        this.baseField = baseField;
    }

    public String getBaseField() {
        return baseField;
    }
}

public static void main(String[] args) throws JsonProcessingException {
    Object input = new JsonWrapper<>(new BaseClass("inner"), "outer");
    System.out.println(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(input));
}

Outputs:

{
  "baseField" : "inner",
  "extraField" : "outer"
}

For writing collections, you can simply use a view:

public static void main(String[] args) throws JsonProcessingException {
    List<BaseClass> inputs = Arrays.asList(new BaseClass("1"), new BaseClass("2"));
    //Google Guava Library <3
    List<JsonWrapper<BaseClass>> modInputs = Lists.transform(inputs, base -> new JsonWrapper<>(base, "hello"));
    System.out.println(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(modInputs));
}

Output:

[ {
  "baseField" : "1",
  "extraField" : "hello"
}, {
  "baseField" : "2",
  "extraField" : "hello"
} ]
Enquire answered 31/3, 2016 at 12:40 Comment(2)
If using Kotlin, annotate the property to unwrap using @get:JsonUnwrapped.Reiss
This is the best answer -- one shouldn't forget about view models just because JSON is involved.Joby
B
6

Another and perhaps the most simple solution:

Make serialisation a 2-step process. First create a Map<String,Object> like:

Map<String,Object> map = req.mapper().convertValue( result, new TypeReference<Map<String,Object>>() {} );

then add the properties you want like:

map.put( "custom", "value" );

then serialise this to json:

String json = req.mapper().writeValueAsString( map );
Berkeleianism answered 20/2, 2018 at 12:44 Comment(0)
C
3

For my use case, I could use a much simpler way. In a the base class I have for all my "Jackson Pojos" I add:

protected Map<String,Object> dynamicProperties = new HashMap<String,Object>();

...


public Object get(String name) {
    return dynamicProperties.get(name);
}

// "any getter" needed for serialization    
@JsonAnyGetter
public Map<String,Object> any() {
    return dynamicProperties;
}

@JsonAnySetter
public void set(String name, Object value) {
    dynamicProperties.put(name, value);
}

I can now deserialize to Pojo, work with fields and reserialize witjout losing any properties. I can also add/change non pojo properties:

// Pojo fields
person.setFirstName("Annna");

// Dynamic field
person.set("ex", "test");

(Got it from Cowtowncoder)

Clupeid answered 16/5, 2018 at 5:30 Comment(0)
R
2

We can use reflection to get all the fields of the object you want to parse.

@JsonSerialize(using=CustomSerializer.class)
class Test{
  int id;
  String name;
  String hash;
}    

In custom serializer, we have our serialize method like this :

        @Override
        public void serialize(Test value, JsonGenerator jgen,
                SerializerProvider provider) throws IOException,
                JsonProcessingException {

            jgen.writeStartObject();
            Field[] fields = value.getClass().getDeclaredFields();

            for (Field field : fields) {
                try {
                    jgen.writeObjectField(field.getName(), field.get(value));
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    e.printStackTrace();
                }

            }
            jgen.writeObjectField("extra_field", "whatever_value");
            jgen.writeEndObject();

        }
Riflery answered 16/10, 2014 at 11:38 Comment(2)
The Field class comes from import java.lang.reflect.Field;Montane
What if you use @JsonProperty(value="someOtherName") or @JsonIgnore in your domain object? With reflection, you override existing jackson capabilities. That doesn't seem good.Willywillynilly
F
1

Inspired from what wajda said and written in this gist:

Here is how to add a listener for bean serialization in jackson 1.9.12. In this example, the listerner is considered as a Chain Of Command which interface is :

public interface BeanSerializerListener {
    void postSerialization(Object value, JsonGenerator jgen) throws IOException;
}

MyBeanSerializer.java:

public class MyBeanSerializer extends BeanSerializerBase {
    private final BeanSerializerListener serializerListener;

    protected MyBeanSerializer(final BeanSerializerBase src, final BeanSerializerListener serializerListener) {
        super(src);
        this.serializerListener = serializerListener;
    }

    @Override
    public void serialize(final Object bean, final JsonGenerator jgen, final SerializerProvider provider) throws IOException, JsonGenerationException {
        jgen.writeStartObject();
        if (_propertyFilterId != null) {
            serializeFieldsFiltered(bean, jgen, provider);
        } else {
            serializeFields(bean, jgen, provider);
        }

        serializerListener.postSerialization(bean, jgen);

        jgen.writeEndObject();
    }
}

MyBeanSerializerBuilder.java:

public class MyBeanSerializerBuilder extends BeanSerializerBuilder {
    private final BeanSerializerListener serializerListener;

    public MyBeanSerializerBuilder(final BasicBeanDescription beanDesc, final BeanSerializerListener serializerListener) {
        super(beanDesc);
        this.serializerListener = serializerListener;
    }

    @Override
    public JsonSerializer<?> build() {
        BeanSerializerBase src = (BeanSerializerBase) super.build();
        return new MyBeanSerializer(src, serializerListener);
    }
}

MyBeanSerializerFactory.java:

public class MyBeanSerializerFactory extends BeanSerializerFactory {

    private final BeanSerializerListener serializerListener;

    public MyBeanSerializerFactory(final BeanSerializerListener serializerListener) {
        super(null);
        this.serializerListener = serializerListener;
    }

    @Override
    protected BeanSerializerBuilder constructBeanSerializerBuilder(final BasicBeanDescription beanDesc) {
        return new MyBeanSerializerBuilder(beanDesc, serializerListener);
    }
}

The last class below shows how to provide it using Resteasy 3.0.7:

@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
    private final MapperConfigurator mapperCfg;

    public ObjectMapperProvider() {
        mapperCfg = new MapperConfigurator(null, null);
        mapperCfg.setAnnotationsToUse(new Annotations[]{Annotations.JACKSON, Annotations.JAXB});
        mapperCfg.getConfiguredMapper().setSerializerFactory(serializerFactory);
    }

    @Override
    public ObjectMapper getContext(final Class<?> type) {
        return mapperCfg.getConfiguredMapper();
    }
}
Fieldwork answered 20/10, 2015 at 23:5 Comment(0)
D
1

We can extend BeanSerializer, but with little trick.

First, define a java class to wrapper your POJO.

@JsonSerialize(using = MixinResultSerializer.class)
public class MixinResult {

    private final Object origin;
    private final Map<String, String> mixed = Maps.newHashMap();

    @JsonCreator
    public MixinResult(@JsonProperty("origin") Object origin) {
        this.origin = origin;
    }

    public void add(String key, String value) {
        this.mixed.put(key, value);
    }

    public Map<String, String> getMixed() {
        return mixed;
    }

    public Object getOrigin() {
        return origin;
    }

}

Then,implement your custom serializer.

public final class MixinResultSerializer extends BeanSerializer {

    public MixinResultSerializer() {
        super(SimpleType.construct(MixinResult.class), null, new BeanPropertyWriter[0], new BeanPropertyWriter[0]);
    }

    public MixinResultSerializer(BeanSerializerBase base) {
        super(base);
    }

    @Override
    protected void serializeFields(Object bean, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (bean instanceof MixinResult) {
            MixinResult mixin  = (MixinResult) bean;
            Object      origin = mixin.getOrigin();

            BeanSerializer serializer = (BeanSerializer) provider.findValueSerializer(SimpleType.construct(origin.getClass()));

            new MixinResultSerializer(serializer).serializeFields(origin, gen, provider);

            mixin.getMixed().entrySet()
                    .stream()
                    .filter(entry -> entry.getValue() != null)
                    .forEach((entry -> {
                        try {
                            gen.writeFieldName(entry.getKey());
                            gen.writeRawValue(entry.getValue());
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }));
        } else {
            super.serializeFields(bean, gen, provider);
        }

    }

}

This way, we can handle the case that origin object using jackson annotations to custom serialize behavior.

Dedal answered 6/5, 2016 at 2:11 Comment(0)
H
0

I needed this ability as well; in my case, to support field expansion on REST services. I ended up developing a tiny framework to solve this problem, and it's open sourced on github. It's also available in the maven central repository.

It takes care of all the work. Simply wrap the POJO in a MorphedResult, and then add or remove properties at will. When serialized, the MorphedResult wrapper disappears and any 'changes' appear in the serialized JSON object.

MorphedResult<?> result = new MorphedResult<>(pojo);
result.addExpansionData("my_extra_field", "some data");

See the github page for more details and examples. Be sure to register the libraries 'filter' with Jackson's object mapper like so:

ObjectMapper mapper = new ObjectMapper();
mapper.setFilters(new FilteredResultProvider());
Hydrate answered 16/3, 2015 at 21:28 Comment(0)
A
0

This google groups thread points to the BeanSerializerModifier.changeProperties method: https://groups.google.com/g/jackson-user/c/uYIxbRZhsIM/m/1QpLh7G72C0J

It looks like this method makes the least interference with the object serialization, which is very convenient if you have other serialization customizations.

You can add more objects to the given beanProperties list.

Suppose, we have this bean to be serialized:

public class MyClass {

    private final String name;
    private final String description;

    public MyClass(String name, String description) {
        this.name = name;
        this.description = description;
    }

    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    public String getName() {
        return name;
    }

    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    public String getDescription() {
        return description;
    }
}

Then you can add a SerializerModifier to your ObjectMapper instance. The most interesting parts are the MyBeanSerializerModifier.changeProperties and the CustomPropertyWriter.value methods.

private void addSerializationCustomization(ObjectMapper objectMapper,
                                           SomeAdditionalDataFactory dataFactory) {
    SimpleModule module = new SimpleModule();
    BeanSerializerModifier modifier = new MyBeanSerializerModifier(dataFactory);
    module.setSerializerModifier(modifier);
    objectMapper.registerModule(module);
}

private static class MyBeanSerializerModifier extends BeanSerializerModifier {

    private final SomeAdditionalDataFactory dataFactory;

    public MyBeanSerializerModifier(SomeAdditionalDataFactory dataFactory) {
        this.dataFactory = dataFactory;
    }

    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
                                                     BeanDescription beanDesc,
                                                     List<BeanPropertyWriter> beanProperties) {
        if (MyClass.class.isAssignableFrom(beanDesc.getBeanClass())) {
            Map<String, Function<MyClass, String>> additionalFields = Map.of(
                    "someData1",
                    myObj -> dataFactory.getSomeData1(myObj),
                    "someData2",
                    myObj -> dataFactory.getSomeData2(myObj),
                    "someData3",
                    myObj -> dataFactory.getSomeData3(myObj)
            );
            JavaType javaType = SimpleType.constructUnsafe(String.class);

            for (Map.Entry<String, Function<MyClass, String>> entry : additionalFields.entrySet()) {
                VirtualAnnotatedMember member = new VirtualAnnotatedMember(
                        null, beanDesc.getBeanClass(), entry.getKey(), javaType);
                BeanPropertyDefinition definition = SimpleBeanPropertyDefinition
                    .construct(config, member, new PropertyName(entry.getKey()));
                BeanPropertyWriter writer = new CustomPropertyWriter<>(
                    definition, javaType, entry.getValue());
                beanProperties.add(writer);
            }
        }
        return super.changeProperties(config, beanDesc, beanProperties);
    }
}

private static class CustomPropertyWriter<T> extends VirtualBeanPropertyWriter {

    private final Function<T, String> getter;

    public CustomPropertyWriter(BeanPropertyDefinition propDef,
                                JavaType declaredType,
                                Function<T, String> getter) {
        super(propDef, null, declaredType);
        this.getter = getter;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected Object value(Object bean,
                           JsonGenerator gen,
                           SerializerProvider prov) throws Exception {
        return getter.apply((T) bean);
    }

    @Override
    public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config,
                                                AnnotatedClass declaringClass,
                                                BeanPropertyDefinition propDef,
                                                JavaType type) {
        throw new IllegalStateException("Should not be called on this type");
    }
}
Alien answered 6/1, 2023 at 10:6 Comment(0)
S
-2

After looking more on the Jackson source code I concluded that it's simply impossible to achieve without writing my own BeanSerializer, BeanSerializerBuilder and BeanSerializerFactory and provide some extension points like:

/*
/**********************************************************
/* Extension points
/**********************************************************
 */

protected void beforeEndObject(T bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JSONException {
    // May be overridden
}

protected void afterStartObject(T bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JSONException {
    // May be overridden
}

Unfortunately I had to copy and paste entire Jackson's BeanSerializer source code to MyCustomBeanSerializer because the former is not developed for extensions declaring all the fields and some important methods (like serialize(...)) as final

Samuele answered 7/2, 2013 at 13:28 Comment(2)
Improper use of final is for Code-Nazis. Often I faced it myself not being able to extend existing code, just because of final methods or classes. And don't argue with performance: #4279920Deliladelilah
@Deliladelilah I wouldn't jump to conclusions there. If a developer choose to make a class final then that may very well be a well thought-out decision. Opening up classes for extension is a decision that shouldn't be made lightly.Sardonyx

© 2022 - 2024 — McMap. All rights reserved.