Dynamic addition of fasterxml Annotation?
Asked Answered
N

2

4

Is there a way to set @JsonProperty annotation dynamically like:

class A {

    @JsonProperty("newB") //adding this dynamically
    private String b;

}

or can I simply rename field of an instance? If so, suggest me an idea. Also, in what way an ObjectMapper can be used with serialization?

Nonoccurrence answered 13/8, 2014 at 16:1 Comment(6)
Read about MixIn - wiki.fasterxml.com/JacksonMixInAnnotations. Also see this tutorial: wiki.fasterxml.com/JacksonInFiveMinutesMalapropism
I see the whole class mapping with another JSON or like files, rather I need to change only a particular field of a class to be modified as in @JsonProperty, sorry if I missed anything from your linkNonoccurrence
@Nonoccurrence you are missing the fact that you can define mix-ins any way you want, and include only those methods, fields, annotations that you want to use as overrides. So, for example, your class A could be mix-in class to use for one or more target classes, to make field "b" be serialized as "newB".Westley
@Westley Can a serialized result be an Object or it necessarily be a String from writeValueAsString()Nonoccurrence
@Nonoccurrence I'm sorry, I don't quite understand what you are asking here. If you mean whether field or method signature of mix-in has to be the same, yes. But it sounds like you might be asking something else.Westley
@Westley Here is my changed question, linkNonoccurrence
H
4

Assume that your POJO class looks like this:

class PojoA {

    private String b;

    // getters, setters
}

Now, you have to create MixIn interface:

interface PojoAMixIn {

    @JsonProperty("newB")
    String getB();
}

Simple usage:

PojoA pojoA = new PojoA();
pojoA.setB("B value");

System.out.println("Without MixIn:");
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(pojoA));

System.out.println("With MixIn:");
ObjectMapper mapperWithMixIn = new ObjectMapper();
mapperWithMixIn.addMixInAnnotations(PojoA.class, PojoAMixIn.class);
System.out.println(mapperWithMixIn.writerWithDefaultPrettyPrinter().writeValueAsString(pojoA));

Above program prints:

Without MixIn:
{
  "b" : "B value"
}
With MixIn:
{
  "newB" : "B value"
}
Helwig answered 14/8, 2014 at 11:19 Comment(7)
what if I have multiple fields in the class, do I need to add that in Interface too ?Nonoccurrence
You have to provide only these methods for which you want to change configuration. If you want to update only one property, you have to provide only one method.Malapropism
Michael, Thanks for your response but my intent is to get back the same object with modification in field name not a String, could you guide me a solution?Nonoccurrence
Sorry, but I do not understand your problem. Could you update your question and provide the example which shows what do you want to do?Malapropism
Yes using MixIn's I can actually do the process as you said, but Can I be able to work on object pojoA and return the mixIn pojoA and not a String from writeValueAsString()Nonoccurrence
Hmm. Yes, you can deserialize returned JSON to PojoA object but why do you want to do this?Malapropism
Will deserializing maps newB to b? again in need of MixIn, if so how?Nonoccurrence
L
0

this is a very late answer but, if it helps you or others, you should be able to change annotations at runtime. Check this link:

https://www.baeldung.com/java-reflection-change-annotation-params

Modifying annotations might be a bit messy and I prefer other options.

Mixin's are a good static option but if you need to change properties at runtime you can use a custom serializer (or deserializer). Then register your serializer with the ObjectMapper of your choosing (writing formats like json / xml are now provided for free via Jackson). Here are some additional examples:

custom serializer: https://www.baeldung.com/jackson-custom-serialization

custom deserializer: https://www.baeldung.com/jackson-deserialization

i.e.:

    class A {
        //        @JsonProperty("newB") //adding this dynamically
        String b;
    }

    class ASerializer extends StdSerializer<A> {

        public ASerializer() {
            this(null);
        }

        public ASerializer(Class<A> a) {
            super(a);
        }

        @Override
        public void serialize(A a, JsonGenerator gen, SerializerProvider provider) throws IOException {

            if (a == null) {
                gen.writeNull();

            } else {
                gen.writeStartObject();
                gen.writeStringField("newB", a.b);
                gen.writeEndObject();
            }
        }
    }

    @Test
    public void test() throws JsonProcessingException {
        A a = new A();
        a.b = "bbb";
        String exp = "{\"newB\":\"bbb\"}";

        ObjectMapper mapper = new ObjectMapper();

        SimpleModule module = new SimpleModule();
        module.addSerializer(A.class, new ASerializer());
        mapper.registerModule(module);

        assertEquals(exp, mapper.writeValueAsString(a));
    }
Lymphoblast answered 18/6, 2019 at 19:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.