Jackson Serialize Field to Different Name

后端 未结 2 1848
-上瘾入骨i
-上瘾入骨i 2021-01-05 13:35

I have this JSON to deserialize:

{
    \"first-name\": \"Alpha\",
    \"last-name\": \"Beta\",
    \"gender\": \"m\"
}

I want to serialize

相关标签:
2条回答
  • 2021-01-05 14:24

    There is a far easier way to do this - create an objectmapper that uses the "addMixin" function.

    Class to be serialized:

    Class YouWantToSerializeMe {
    
        public String firstName;
        public String lastName;
        public String gender;
    
        @JsonProperty("firstName")
        public String getFirstNameCC() {
            return firstName;
        }
    
        @JsonProperty("lastName")
        public String getLastNameCC() {
        return lastName;
        }
    }
    

    Now, to serialize using both the built-in field names and custom field names, you can do this:

    Class DoTheSerializing {
    
        String serializeNormally(YouWantToSerializeMe me) {
             ObjectMapper objectMapper = new ObjectMapper();
             ObjectWriter objectWriter = objectMapper.writer();
    
             return objectWriter(me)
         }
    
        String serializeWithMixin(YouWantToSerializeMe me) {
             ObjectMapper objectMapper = new ObjectMapper();
             ObjectWriter objectWriter = objectMapper
                     .addMixIn(YouWantToSerializeMe.class, MyMixin.class)
                     .writer();
    
             return objectWriter(me)
        }
    
        interface MyMixin {
    
             @JsonProperty("first-name")
             public String getFirstNameCC();
    
             @JsonProperty("last-name")
             public String getLastNameCC();
        }    
    
    }
    

    This uses an embedded interface in the class to keep things very local. You can make lots of optimizations around this, such as creating a static ObjectMapper and loading/unloading the mixin.

    Using the interface as a "template" to control the mapping function is really powerful. You can add things at both the field and class level.

    0 讨论(0)
  • 2021-01-05 14:31

    I am not sure I completly understand your question, but for what I could understand you can do something like this to achieve different serializtions.

    Create a custom annotation to hold all possible different serialization options:

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CustomJsonProperty {
        String propertyName();
    
        String format();
    
        @Target(ElementType.FIELD)
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @interface List {
            CustomJsonProperty[] value();
        }
    
    }
    

    Annotate your class accordingly:

    @JsonSerialize(using = CustomJsonPropertySerializer.class)
    public class Bar {
    
        @CustomJsonProperty.List({
            @CustomJsonProperty(propertyName = "first-name", format = "A"),
            @CustomJsonProperty(propertyName = "firstName", format = "B")
        })
        private String firstName;
    
        @CustomJsonProperty.List({
                @CustomJsonProperty(propertyName = "last-name", format = "A"),
                @CustomJsonProperty(propertyName = "lastName", format = "B")
        })
        private String lastName;
    
        @CustomJsonProperty.List({
                @CustomJsonProperty(propertyName = "gender-x", format = "A"),
                @CustomJsonProperty(propertyName = "gender", format = "B")
        })
        private String gender;
    
        @JsonIgnore
        private String format;
    
        //getters & setters
    
    }
    

    Create a custom serializer to interpret your new annotation:

    public class CustomJsonPropertySerializer extends JsonSerializer<Bar> {
    
        @Override
        public void serialize(Bar bar, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException {
            jsonGenerator.writeStartObject();
    
            Field[] fields = bar.getClass().getDeclaredFields();
    
            for (Field field : fields) {
                field.setAccessible(true);
                Object value = null;
    
                try {
                    value = field.get(bar);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
    
                if (field.isAnnotationPresent(CustomJsonProperty.List.class)) {
                    CustomJsonProperty[] properties = field.getAnnotation(CustomJsonProperty.List.class).value();
                    CustomJsonProperty chosenProperty = null;
    
                    for (CustomJsonProperty c : properties) {
                        if (c.format().equalsIgnoreCase(bar.getFormat())) {
                            chosenProperty = c;
                            break;
                        }
                    }
    
                    if (chosenProperty == null) {
                        //invalid format given, use first format then
                        chosenProperty = properties[0];
                    }
    
                    jsonGenerator.writeStringField(chosenProperty.propertyName(), value.toString());
                }
            }
    
            jsonGenerator.writeEndObject();
        }
    }
    

    Now you can serialize your objects taking into consideration different formats for the property names:

    public static void main(String[] args) throws IOException {
        Bar bar1 = new Bar("first", "last", "m", "A");
        Bar bar2 = new Bar("first", "last", "m", "B");
    
        ObjectMapper mapper = new ObjectMapper();
        String json1 = mapper.writeValueAsString(bar1);
        String json2 = mapper.writeValueAsString(bar2);
    
        System.out.println(json1);
        System.out.println(json2);
    
    }
    

    Output:

    {"first-name":"first","last-name":"last","gender-x":"m"}
    {"firstName":"first","lastName":"last","gender":"m"}
    

    Of course the above serializer only works for Bar objects, but that can easily be solved using inheritance with abstract String getFormat(); on the super class and changing the custom serializer to accept the super class type, instead of Bar.

    Maybe there is a simpler way than creating your own stuff, but I don't know about it. Let me know if something wasn't clear and I can elaborate it again.

    0 讨论(0)
提交回复
热议问题