用于 ValueObject 层次结构的 Jackson 序列化器 - 多态

问题描述

作为jackson-serialize-simple-one-attribute-valueobject-like-enum-without-nesting的延续

我希望能够以一种非常简单的方式创建包装一个属性的 ValueObjects,只需从基础 ValueObject 类继承即可:

@JsonSerialize(using = ValueObjectJsonSerializer.class)
@EqualsAndHashCode
public abstract class BaseValueObject<T> { 

  T value;
  .......
}
// I want to be able to create multiple ValueObject wrapping Types like
public class Name extends ValueObject<String> {}
public class Surname extends ValueObject<String>{}
public class Age extends ValueObject<Integer>{} 
etc...

有可能吗?

正在实施

    public void serializeWithType(Object value,JsonGenerator gen,SerializerProvider serializers,TypeSerializer typeSer) throws IOException

足够了,还是必须以其他方式完成?

在哪里可以找到一些简单的示例 serializeWithType 实现?

也许基类应该覆盖一些返回实际类型鉴别器的方法?

我是否还必须实现反序列化器才能反序列化此类 json?

解决方法

下面的实现可以序列化多态类型,仍然是反序列化器。 我想知道 jackson 如何序列化和反序列化 Java 枚举,它不必在 json 中包含它们的类型。这将是我感兴趣的。OnePropertyValueObject 可以像枚举一样序列化和反序列化。

@Slf4j
class ValueObjectJsonSerializer extends JsonSerializer<Object> {
    @Override
    public void serialize(Object value,JsonGenerator gen,SerializerProvider serializers) throws IOException {
        if (value == null) {
            gen.writeNull();
            return;
        }
        Class clazz = value.getClass();
        while (clazz != Object.class) {
            java.lang.reflect.Field[] fields = value.getClass().getDeclaredFields();
            if (fields.length > 1) {
                throw new IOException(
                    "Do not use this serializer for the class " + value.getClass().getSimpleName() + " which has at least " + fields.length +
                        " fields!");
            } else if (fields.length == 1) {

                final Field first = fields[0];
                try {
                    final Object fieldValue = first.get(value);
                    gen.writeObject(fieldValue);
                    log.info("field {} value: {}",fields[0],fieldValue);
                    return;
                } catch (IllegalAccessException e) {
                    throw new IOException(e);
                }
            } else {
                clazz = clazz.getSuperclass();
            }
        }

        throw new IOException(
            "Do not use this serializer for the class " + value.getClass().getSimpleName() + " which has no fields!");

    }

    public void serializeWithType(Object value,SerializerProvider serializers,TypeSerializer typeSer) throws IOException
    {
        if (value == null) {
            gen.writeNull();
            return;
        }
        Class clazz = value.getClass();
        while (clazz != Object.class) {
            java.lang.reflect.Field[] fields = clazz.getDeclaredFields();
            if (fields.length > 1) {
                throw new IOException(
                    "Do not use this serializer for the class " + value.getClass().getSimpleName() + " which has at least " + fields.length + " fields!");
            } else if (fields.length == 1) {

                final Field first = fields[0];
                try {
                    final Object fieldValue = first.get(value);

                    WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen,typeSer.typeId(value,value.getClass(),JsonToken.VALUE_STRING));
                    gen.writeObject(fieldValue);
                    typeSer.writeTypeSuffix(gen,typeIdDef);
                    log.info("field {} value: {}",fieldValue);
                    return;
                } catch (IllegalAccessException e) {
                    throw new IOException(e);
                }
            } else {
                clazz = clazz.getSuperclass();
            }
        }

        throw new IOException(
            "Do not use this type serializer for the class " + value.getClass().getSimpleName() + " which has no fields!");
    }

    public JsonTypeInfo.As getTypeInclusion() {
        return JsonTypeInfo.As.WRAPPER_OBJECT;
    }
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...