У меня есть этот JSON для десериализации:

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

Я хочу сериализовать его в 2 разных формата:

[A]

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

[B]

{
    "firstName": "Alpha",
    "lastName": "Beta",
    "gender": "m"
}

Я могу преобразовать его в один формат: только [A] или только [B]. Вот мой код для сериализации в [B]:

public String firstName;
public String lastName;
public String gender;

@JsonProperty("firstName")
public String getFirstNameCC() {
    return firstName;
}

@JsonProperty("first-name")
public void setFirstNameD(String firstName) {
    this.firstName = firstName;
}

@JsonProperty("lastName")
public String getLastNameCC() {
    return lastName;
}

@JsonProperty("last-name")
public void setLastNameD(String lastName) {
    this.lastName = lastName;
}

public String getGender() {
    return gender;
}

public void setGender(String gender) {
    this.gender = gender;
}

Я читал о JsonView здесь http://www.baeldung.com/jackson- json-view-annotation (раздел «5. Настройка представлений JSON»), но меняет только его значение. Я хочу изменить имя поля, как показано выше. Может ли кто-нибудь дать представление об этом?

6
shankshera 15 Апр 2016 в 14:36

2 ответа

Лучший ответ

Я не уверен, что полностью понимаю ваш вопрос, но насколько я могу понять, вы можете сделать что-то вроде этого для достижения разных сериализаций.

Создайте специальную аннотацию, содержащую все возможные варианты сериализации:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomJsonProperty {
    String propertyName();

    String format();

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

}

Аннотируйте свой класс соответствующим образом:

@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

}

Создайте собственный сериализатор для интерпретации вашей новой аннотации:

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();
    }
}

Теперь вы можете сериализовать свои объекты с учетом различных форматов имен свойств:

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);

}

Выход:

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

Конечно, указанный выше сериализатор работает только для объектов Bar, но это можно легко решить, используя наследование с abstract String getFormat(); в суперклассе и изменяя настраиваемый сериализатор, чтобы он принимал тип суперкласса вместо Bar.

Может быть, есть более простой способ, чем создавать свои собственные вещи, но я не знаю об этом. Дайте мне знать, если что-то непонятно, и я могу уточнить это снова.

9
dambros 15 Апр 2016 в 13:56

Есть гораздо более простой способ сделать это - создать объектную карту, которая использует функцию «addMixin».

Класс для сериализации:

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;
    }
}

Теперь, чтобы сериализовать с использованием как встроенных, так и настраиваемых имен полей, вы можете сделать следующее:

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();
    }    

}

При этом используется встроенный интерфейс в класс, чтобы вещи оставались очень локальными. Вы можете сделать множество оптимизаций вокруг этого, например, создать статический ObjectMapper и загрузить / выгрузить миксин.

Использование интерфейса в качестве «шаблона» для управления функцией сопоставления - действительно мощный инструмент. Вы можете добавлять вещи как на уровне поля, так и на уровне класса.

4
sdw 21 Янв 2019 в 17:41