Search code examples
javajsonjacksonjackson-databind

Custom or dynamic @JsonProperty for all fields without annotation with Jackson


I'm looking for a way to customize the serialized keys and deserialized setter calls for jackson. I have a few hundred objects that are all somehow related with various levels of abstractions and interfaces, however they don't have many inherited fields. I am using a mixin that applies to all my classes to utilize a filter and a TypeIdResolver. All of the fields I want serialized to json end in 'attribute', but I don't want attribute after every key in the json. I'm unable to refactor the field and method names as it's used for legacy XML parsing and I can't break that. I really don't want to add @JsonProperty to every field; I'm looking for something more dynamic. Some way to inspect fields to serialize or keys to deserialize and modify it to my liking.

For deserialization, I think I might be able to use InjectibleValues, but I haven't tried as I haven't been able to find anything to customize the output keys.

for example,

String nameAttribute = "xyz";
getNameAttribute()

"name"="xyz"

Not

"nameAttribute"="xyz"

Solution

  • I was able to solve this with a custom extension of JacksonAnnotationIntrospector. I overrode the methods that look for @JsonProperty and provided my own logic. I also had to implement my own hasIgnoreMarker() to avoid placing @JsonIgnore all over the place because the filtering doesn't happen until the actual serialization so I was getting errors about duplicate getters and setters.

    mapper.setAnnotationIntrospector(new MyAnnotationIntrospector());
    
    
    
    private static class MyAnnotationIntrospector extends JacksonAnnotationIntrospector {
    
        
        @Override
        public PropertyName findNameForSerialization(Annotated a) {
            if (a instanceof AnnotatedField) {
                String name = a.getName();
                if (name.endsWith("Attribute")) {
                    return PropertyName.construct(name.replace("Attribute", ""));
                }
            }
            return super.findNameForSerialization(a);
        }
    
        @Override
        public PropertyName findNameForDeserialization(Annotated a) {
            if (a instanceof AnnotatedField) {
                String name = a.getName();
                if (name.endsWith("Attribute")) {
                    return PropertyName.construct(name.replace("Attribute", ""));
                }
            }
            return super.findNameForDeserialization(a);
        }