我又花了几个小时试图找出一种遍历类的方法,并且找到了一种对我来说足够好的方法。
为了强调,Jackson 没有创建类型树。相反,它有几种访问者类型,可用于访问序列化程序。 Jackson 中的序列化器是将类的实例序列化为某些输出(JSON、YAML 等)的方法。当访问这些序列化器时,我们可以依次检查对象的属性并依次访问它们。
下面是这个机制的基本实现,可以调整它以手动构建类型树。我使用了 jackson-databind:2.12.1,但我相信该机制是在 jackson-databind:2.2.0 中引入的。
package org.example.jackson.type.tree;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsonFormatVisitors.*;
import com.fasterxml.jackson.databind.ser.SerializerFactory;
import org.junit.jupiter.api.Test;
import java.util.Set;
public class FunctioningTest {
@Test
void extractTypeTree() throws JsonMappingException {
final var objectMapper = new ObjectMapper();
final var serializerProvider = objectMapper.getSerializerProviderInstance();
final var javaType = objectMapper.constructType(SomeClass.class);
final var serializerFactory = objectMapper.getSerializerFactory();
final var typeSerializer = serializerFactory.createSerializer(serializerProvider, javaType);
final var FieldVisitor = new FieldVisitor(serializerProvider, serializerFactory);
typeSerializer.acceptJsonFormatVisitor(FieldVisitor, javaType);
}
static class SomeClass {
public Integer integer;
public String string;
public FieldClass fieldClass;
}
static class FieldClass {
public boolean aBoolean;
public double floatingPoint;
}
static class FieldVisitor extends JsonFormatVisitorWrapper.Base implements JsonFormatVisitorWrapper {
private final SerializerFactory serializerFactory;
public FieldVisitor(final SerializerProvider provider, final SerializerFactory serializerFactory) {
super(provider);
this.serializerFactory = serializerFactory;
}
@Override
public JsonObjectFormatVisitor expectObjectFormat(JavaType javaType) throws JsonMappingException {
System.out.println("FieldVisitor (Object): " + javaType);
final var objectVisitor = new ObjectVisitor(getProvider());
final var objectSerializer = serializerFactory.createSerializer(getProvider(), javaType);
final var properties = objectSerializer.properties();
while (properties.hasNext()) {
final var property = properties.next();
final var propertyType = property.getType();
final var propertySerializer = serializerFactory.createSerializer(getProvider(), propertyType);
propertySerializer.acceptJsonFormatVisitor(this, propertyType);
}
return objectVisitor;
}
@Override
public JsonArrayFormatVisitor expectArrayFormat(JavaType type) throws JsonMappingException {
return null;
}
@Override
public JsonStringFormatVisitor expectStringFormat(JavaType type) throws JsonMappingException {
System.out.println("FieldVisitor (String): " + type);
return new StringVisitor();
}
@Override
public JsonNumberFormatVisitor expectNumberFormat(JavaType type) throws JsonMappingException {
System.out.println("FieldVisitor (Number): " + type);
return new NumberVisitor();
}
@Override
public JsonIntegerFormatVisitor expectIntegerFormat(JavaType type) throws JsonMappingException {
System.out.println("FieldVisitor (Integer): " + type);
return new IntegerVisitor();
}
@Override
public JsonBooleanFormatVisitor expectBooleanFormat(JavaType type) throws JsonMappingException {
System.out.println("FieldVisitor (Boolean): " + type);
return new BooleanVisitor();
}
@Override
public JsonNullFormatVisitor expectNullFormat(JavaType type) throws JsonMappingException {
System.out.println("Null: " + type);
return null;
}
@Override
public JsonAnyFormatVisitor expectAnyFormat(JavaType type) throws JsonMappingException {
return null;
}
@Override
public JsonMapFormatVisitor expectMapFormat(JavaType type) throws JsonMappingException {
return null;
}
}
static class ObjectVisitor extends JsonObjectFormatVisitor.Base implements JsonObjectFormatVisitor {
public ObjectVisitor(SerializerProvider serializerProvider) {
super(serializerProvider);
}
@Override
public void property(BeanProperty writer) throws JsonMappingException {
System.out.println("ObjectVisitor: " + writer);
}
@Override
public void property(String name, JsonFormatVisitable handler, JavaType propertyTypeHint) throws JsonMappingException {
System.out.println("ObjectVisitor: " + String.join(", ", name, handler.toString(), propertyTypeHint.toString()));
}
@Override
public void optionalProperty(BeanProperty writer) throws JsonMappingException {
System.out.println("ObjectVisitor (optional): " + writer);
}
@Override
public void optionalProperty(String name, JsonFormatVisitable handler, JavaType propertyTypeHint) throws JsonMappingException {
System.out.println("ObjectVisitor (optional): " + String.join(", ", name, handler.toString(), propertyTypeHint.toString()));
}
}
static class StringVisitor implements JsonStringFormatVisitor {
@Override
public void format(JsonValueFormat format) {
System.out.println("StringVisitor (format): " + format);
}
@Override
public void enumTypes(Set<String> enums) {
System.out.println("StringVisitor (enums): " + enums);
}
}
static class IntegerVisitor implements JsonIntegerFormatVisitor {
@Override
public void numberType(JsonParser.NumberType type) {
System.out.println("IntegerVisitor (numberType): " + type);
}
@Override
public void format(JsonValueFormat format) {
System.out.println("IntegerVisitor (format): " + format);
}
@Override
public void enumTypes(Set<String> enums) {
System.out.println("IntegerVisitor (enums): " + enums);
}
}
static public class BooleanVisitor implements JsonBooleanFormatVisitor {
@Override
public void format(JsonValueFormat format) {
System.out.println("BooleanVisitor (format): " + format);
}
@Override
public void enumTypes(Set<String> enums) {
System.out.println("BooleanVisitor (enums): " + enums);
}
}
static class NumberVisitor implements JsonNumberFormatVisitor {
@Override
public void numberType(JsonParser.NumberType type) {
System.out.println("NumberVisitor (numberType): " + type);
}
@Override
public void format(JsonValueFormat format) {
System.out.println("NumberVisitor (format): " + format);
}
@Override
public void enumTypes(Set<String> enums) {
System.out.println("NumberVisitor (enums): " + enums);
}
}
}
哪些输出:
FieldVisitor (Object): [simple type, class io.serpentes.examples.schema.sources.jackson.FunctioningTest$SomeClass]
FieldVisitor (Integer): [simple type, class java.lang.Integer]
IntegerVisitor (numberType): INT
FieldVisitor (String): [simple type, class java.lang.String]
FieldVisitor (Object): [simple type, class io.serpentes.examples.schema.sources.jackson.FunctioningTest$FieldClass]
FieldVisitor (Boolean): [simple type, class boolean]
FieldVisitor (Number): [simple type, class double]
NumberVisitor (numberType): DOUBLE
ObjectVisitor (optional): property 'aBoolean' (field "io.serpentes.examples.schema.sources.jackson.FunctioningTest$FieldClass#aBoolean, no static serializer)
ObjectVisitor (optional): property 'floatingPoint' (field "io.serpentes.examples.schema.sources.jackson.FunctioningTest$FieldClass#floatingPoint, no static serializer)
ObjectVisitor (optional): property 'integer' (field "io.serpentes.examples.schema.sources.jackson.FunctioningTest$SomeClass#integer, no static serializer)
ObjectVisitor (optional): property 'string' (field "io.serpentes.examples.schema.sources.jackson.FunctioningTest$SomeClass#string, no static serializer)
ObjectVisitor (optional): property 'fieldClass' (field "io.serpentes.examples.schema.sources.jackson.FunctioningTest$SomeClass#fieldClass, no static serializer)