Search code examples
javajacksongsonjackson-databind

Make Jackson use GSON Annotations


I have a data model which I cannot change. The model itself is annotated with GSON annotations.

@SerializedName("first_value")
private String firstValue = null;

The deserialization with Jackson does not work as needed. Jackson cannot match the entry, therefore the value is null.

It would work with

@JsonProperty("first_value")
private String firstValue = null;

Is there any way I can make Jackson use the GSON annotations, or is there a any other solution in which I do not need to change the original models annotations?


Solution

  • I investigated the problem a bit and it seems that the @JsonProperty annotation is handled with JacksonAnnotationIntrospector. Extending the latter, making it handle @SerializedName, seems to do the trick preserving the original behavior (I hope so):

    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    final class SerializedNameAnnotationIntrospector
            extends JacksonAnnotationIntrospector {
    
        @Getter
        private static final AnnotationIntrospector instance = new SerializedNameAnnotationIntrospector();
    
        @Override
        public PropertyName findNameForDeserialization(final Annotated annotated) {
            @Nullable
            final SerializedName serializedName = annotated.getAnnotation(SerializedName.class);
            if ( serializedName == null ) {
                return super.findNameForDeserialization(annotated);
            }
            // TODO how to handle serializedName.alternate()?
            return new PropertyName(serializedName.value());
        }
    
    }
    
    public final class SerializedNameAnnotationIntrospectorTest {
    
        private static final AnnotationIntrospector unit = SerializedNameAnnotationIntrospector.getInstance();
    
        @Test
        public void test()
                throws IOException {
            final ObjectMapper objectMapper = new ObjectMapper()
                    .setAnnotationIntrospector(unit);
            final Model model = objectMapper.readValue("{\"first_value\":\"foo\",\"second_value\":\"bar\"}", Model.class);
            Assertions.assertEquals("foo", model.firstValue);
            Assertions.assertEquals("bar", model.secondValue);
        }
    
        private static final class Model {
    
            @SerializedName("first_value")
            private final String firstValue = null;
    
            // does not exist in the original model,
            // but retains here to verify whether the introspector still works fine
            @JsonProperty("second_value")
            private final String secondValue = null;
    
        }
    
    }
    

    Please note that I'm not sure how good it works as I'm not a Jackson expert.