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?

Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
Jayanth
  • 329
  • 4
  • 15
  • 1
    Read about MixIn - http://wiki.fasterxml.com/JacksonMixInAnnotations. Also see this tutorial: http://wiki.fasterxml.com/JacksonInFiveMinutes – Michał Ziober Aug 13 '14 at 22:17
  • 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 link – Jayanth Aug 14 '14 at 05:59
  • @Jayanth 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". – StaxMan Aug 14 '14 at 20:49
  • @StaxMan Can a serialized result be an Object or it necessarily be a `String` from `writeValueAsString()` – Jayanth Aug 15 '14 at 11:48
  • @Jayanth 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. – StaxMan Aug 16 '14 at 21:14
  • @StaxMan Here is my changed question, [link](http://stackoverflow.com/questions/25364095/is-there-a-way-to-modify-a-pojo-field-and-return-the-pojo) – Jayanth Aug 18 '14 at 13:11

2 Answers2

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"
}
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
  • what if I have multiple fields in the class, do I need to add that in Interface too ? – Jayanth Aug 14 '14 at 13:59
  • 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. – Michał Ziober Aug 14 '14 at 14:05
  • 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? – Jayanth Aug 14 '14 at 15:41
  • 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? – Michał Ziober Aug 14 '14 at 16:30
  • 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()` – Jayanth Aug 15 '14 at 11:45
  • Hmm. Yes, you can deserialize returned `JSON` to `PojoA` object but why do you want to do this? – Michał Ziober Aug 15 '14 at 12:16
  • Will deserializing maps `newB` to `b`? again in need of **MixIn**, if so how? – Jayanth Aug 15 '14 at 15:02
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));
    }
riiich
  • 861
  • 8
  • 12