#java #json #jackson
#java #json #джексон
Вопрос:
Класс A выглядит так:
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
public final class A extends TreeSet<B> {
private final a;
private b;
private c;
public A(a, b, c) {
this.a = a;
this.b = b;
this.c = c;
}
}
Класс B:
@Data
@AllArgsConstructor
@EqualsAndHashCode
@ToString
public final class B {
private final int x;
private final double y;
}
Когда я сериализую объект класса A с помощью Jackson:
jsonString = objectMapper.writeValueAsString(class_a_object);
Я получаю массив json, подобный этому:
[
{
"x": 3,
"y": 3.23
},
{
"x": 4,
"y": 2.12
},...
]
но переменные-члены a, b, c отсутствуют. Есть ли способ включить их в строку json?
Комментарии:
1. Где бы вы хотели, чтобы они появлялись? Как бы выглядел ваш идеальный выходной JSON?
2. Я хочу, чтобы они отображались перед массивом.
3. Это не очень понятно. Jackson создает JSON, поэтому он должен быть действительным. Вы могли бы изменить свой
A
класс, чтобы иметьTreeSet
поле вместо подклассаTreeSet
. Затем Jackson создаст объект JSON с каждым из ваших 3 полей.TreetSet
Полем будет ваш массив JSON, как у вас в вашем вопросе.4. Все типы коллекций Java обрабатываются особым образом: карты, наборы, списки. Для наборов и списков Jackson просто получает итератор и записывает его элементы в массив JSON.
5. Возможно, вы сможете достичь этого, написав пользовательский сериализатор, но я не могу вспомнить, есть ли способ зарегистрировать его перед теми, которые обрабатывают типы коллекций.
Ответ №1:
Jackson
распознает класс A
как коллекцию и регистрируется CollectionSerializer
для A
сериализации экземпляров. Мы можем изменить сериализатор по умолчанию и предоставить пользовательский сериализатор. Мы можем использовать BeanSerializerModifier
для этого и повторно использовать сериализатор коллекции в пользовательской реализации. Чтобы сгенерировать valid JSON
, вам необходимо указать имя свойства для заданных значений.
Пример:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.type.CollectionType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.File;
import java.io.IOException;
import java.util.TreeSet;
public class ModifyCollectionSerializerApp {
public static void main(String[] args) throws IOException {
A a = new A(1, 2);
a.add(new B(22, 2.2));
a.add(new B(33, 3.3));
SimpleModule aModule = new SimpleModule();
aModule.setSerializerModifier(new ABeanSerializerModifier());
JsonMapper mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(aModule)
.build();
String json = mapper.writeValueAsString(a);
System.out.println(json);
}
}
class ABeanSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifyCollectionSerializer(SerializationConfig config, CollectionType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
return new AJsonSerializer(serializer);
}
}
class AJsonSerializer extends JsonSerializer<A> {
private final JsonSerializer valuesSerializer;
AJsonSerializer(JsonSerializer valuesSerializer) {
this.valuesSerializer = valuesSerializer;
}
@Override
public void serialize(A value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeNumberField("a", value.getA());
gen.writeNumberField("b", value.getB());
gen.writeFieldName("values");
valuesSerializer.serialize(value, gen, serializers);
gen.writeEndObject();
}
}
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
class A extends TreeSet<B> {
private final int a;
private final int b;
}
@Data
@AllArgsConstructor
@EqualsAndHashCode
@ToString
class B implements Comparable<B> {
private final int x;
private final double y;
@Override
public int compareTo(B o) {
return this.x - o.x;
}
}
Приведенный выше код печатает:
{
"a" : 1,
"b" : 2,
"values" : [ {
"x" : 22,
"y" : 2.2
}, {
"x" : 33,
"y" : 3.3
} ]
}