8

Using Jackson to convert a Java object to JSON

ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);
jsonMessage = mapper.writeValueAsString(object);

the result is that the field "participants" (which is part of the object instance)

participants    Arrays$ArrayList<E> 

gets renamed to "participantsList"

participantsList":[{"userId":"c1f9c"}]

i.e. "List" is appended to the field name. I went through the Jackson documentation but haven't found a way to prevent this from happening. Is this possible? Testing the above code in a standalone project does not cause the same result (i.e. no renaming takes place). Why is Jackson behaving like this? Unfortunately, the object is third party and I cannot change it.

Using Jackson version 2.3.3 (same behaviour verified with 2.9.0).

heeboir
  • 729
  • 1
  • 9
  • 26
  • what is message object? – Mykola Yashchenko Aug 04 '17 at 12:36
  • the instance passed as the argument of writeValueAsString(). it is a third-party object so not much can be done there. – heeboir Aug 04 '17 at 12:51
  • If it is a third party object then you should create a model you control for serialization. Then you would convert the third party object and serialize to JSON. This way you will be able to annotate all the properties to your heart's desire. – icirellik Aug 04 '17 at 13:37
  • thing is, I cannot be aware of all its attributes as that object is an instantiation of a request, so it is bound to change and adapt. additionally, the serialization already works well without having to add any maintenance to it - with the only drawback the unclear renaming of the list types (protostuff, another JSON serializer, for example, does not resort to such a change). if I can just turn off this renaming I'd be well on my way - if I do a nasty .replaceAll("List", "") on the returned json string all is well.. – heeboir Aug 04 '17 at 13:56
  • What do you mean by it works fine in a standalone project? Can you elaborate a little on that? – Ashish Lohia Aug 08 '17 at 10:52
  • 8
    Could you verify, may be there is a corresponding getter called `getParticipantsList() `? – Sasha Shpota Aug 08 '17 at 10:55
  • Cannot reproduce it, can you provide the object definition? – aristotll Aug 08 '17 at 11:37
  • @AshishLohia I meant that when I tried it when a standalone application using a simple main method, outside of my normal application, I could not replicate the same behaviour, i.e. the produced json would always contain the correct field name. – heeboir Aug 08 '17 at 12:47
  • @OleksandrShpota great hint! many thanks! – heeboir Aug 08 '17 at 12:48
  • @aristotll it is easily reproducible (now that I know what is causing it), simply by having a fieldName with a getFieldNameList accessor. The produced JSON will contain fieldNameList instead of fieldName. – heeboir Aug 08 '17 at 12:50
  • 1
    @OleksandrShpota already identified the problem. There is another question discussing how to use Jackson serialization based on fields instead of methods: https://stackoverflow.com/questions/10240372/jackson-field-based-serialization – Helder Pereira Aug 11 '17 at 15:50

2 Answers2

4

Oleksandr's comment pointed in the right direction. Indeed there is a getParticipantsList() that Jackson seems to take into account when determining the JSON field name. However, as I wrote before, I am not able to make any changes there, considering it is a third party object.

But, with a better understanding of what causes the problem, I was able to come up with a solution:

mapper.setVisibilityChecker(mapper.getVisibilityChecker().withFieldVisibility(Visibility.ANY).withGetterVisibility(Visibility.NONE).withIsGetterVisibility(Visibility.NONE));

or

mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.setVisibility(PropertyAccessor.GETTER, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.IS_GETTER, Visibility.NONE);
heeboir
  • 729
  • 1
  • 9
  • 26
  • 2
    You're not using Jackson 2.6+ so this comment does not concern you but maybe for the others : setVisibilityChecker is deprecated since 2.6. You have to use setVisibility instead. http://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/ObjectMapper.html#setVisibilityChecker(com.fasterxml.jackson.databind.introspect.VisibilityChecker) – Junior Dussouillez Aug 08 '17 at 13:24
  • 1
    @JuniorDussouillez I was actually just editing my answer for the same purpose! I just found out about said deprecation in later versions. In any case, thanks for pointing it out! – heeboir Aug 08 '17 at 13:26
  • Just to clarify, your object had mismatched field & getter naming (and Jackson defaulted to the getter name)? – charles-allen Aug 10 '17 at 10:19
  • You can use `mix-ins` to apply jackson annotations to classes you do not have access to change. – Darren Forsythe Aug 10 '17 at 20:31
  • 1
    @CodeConfident correct - though I'm not sure if we can call them mismatched, moreso as not following the usual convention. – heeboir Aug 18 '17 at 07:39
  • @DarrenForsythe the problem with the mix-ins (and any annotation-based) approach is that it requires knowledge of all possible variations of the third-party object. Considering that it is a request object (i.e. used to invoke various client requests towards the server) that is not possible and not maintainable. – heeboir Aug 18 '17 at 07:44
  • FYI objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); – muditrustagii Apr 28 '21 at 02:55
-1

Maybe you can use USE_ANNOTATIONS to skip annotations like this:

    ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    mapper.configure(MapperFeature.USE_ANNOTATIONS, false);
    String jsonMessage = mapper.writeValueAsString(object);
flytosea
  • 42
  • 2