如何将枚举序列化为对象形状和默认字符串? [英] How to serialise Enums as both Object Shape and default string?

查看:63
本文介绍了如何将枚举序列化为对象形状和默认字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于具有属性的枚举,例如:

For an enum with attributes, eg:

public enum Thing {
  THING_A("a"),
  THING_B("b");

  private String thing;

  private Thing(String thing) {
    this.thing = thing;
  }

  // Getters...
}

Jackson序列化为值的名称,例如:

Jackson serializes as the name of the values, eg:

mapper.writeValueAsString(Thing.THING_A)); // "THING_A"

如果添加注释以将序列化视为对象:
@JsonFormat(shape = JsonFormat.Shape.OBJECT) 它将序列化属性:

If we add the annotation to treat serialisation as an object:
@JsonFormat(shape = JsonFormat.Shape.OBJECT) it will serialize the attributes:

mapper.writeValueAsString(Thing.THING_A)); // "{"thing":"a"}"

我希望能够在序列化期间决定使用哪种方法.因为这涉及大量枚举,所以我不想编辑每个枚举.有什么好方法吗?

I'd like to be able to decide, during serialization, which of these methods to use. Because this spans a large number of enums, I'd rather not edit each one. Is there a good way to do this?

例如:像这样的东西会很棒:

eg: something like this would be great:

mapper.writeValueAsString(Thing.THING_A, JsonFormat.Shape.OBJECT); // "{"thing":"a"}"
mapper.writeValueAsString(Thing.THING_A, JsonFormat.Enum.DEFAULT); // "THING_A"

推荐答案

由于com.fasterxml.jackson.annotation.JsonFormat是一个批注,您可以实现自己的com.fasterxml.jackson.databind.AnnotationIntrospector并为所有枚举返回所需的值.您可以在下面找到一个简单的示例:

Since, com.fasterxml.jackson.annotation.JsonFormat is an annotation you can implement your own com.fasterxml.jackson.databind.AnnotationIntrospector and return value you want for all your enums. Simple example you can find below:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;

public class JsonPathApp {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(new DynamicEnumAnnotationIntrospector(), new JacksonAnnotationIntrospector()));

        System.out.println(mapper.writeValueAsString(Thing.THING_A));
    }
}

class DynamicEnumAnnotationIntrospector extends AnnotationIntrospector {

    @Override
    public Version version() {
        return new Version(1, 0, 0, "Dynamic enum object", "your.package", "jackson.dynamic.enum");
    }

    @Override
    public JsonFormat.Value findFormat(Annotated memberOrClass) {
        final Class<?> rawType = memberOrClass.getRawType();
        if (rawType.isEnum() && rawType.getPackage().getName().startsWith("your.package")) {
            return JsonFormat.Value.forShape(JsonFormat.Shape.OBJECT);
        }

        return super.findFormat(memberOrClass);
    }
}

上面的代码显示:

{"thing":"a"}

现在,您可以创建两个ObjectMapper实例,其中一个实例配置您自己的注释自省功能,第二个实例使用默认设置离开.如果您真的想以动态方式使用它,则可以为每个可用的Shape值创建一个ObjectMapper,并为给定的形状选择所需的一个:

Now, you can create two instances of ObjectMapper and for one configure your own annotation introspector and second one leave with default. If you really want to use it in dynamic way you can create one ObjectMapper for each available Shape value and select required one for a given shape:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;

import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.Objects;

public class JsonPathApp {

    public static void main(String[] args) throws Exception {
        JsonFactory factory = new JsonFactory();

        for (Shape shape : Shape.values()) {
            ObjectMapper mapper = factory.getWithEnumShapeSetTo(shape);
            System.out.println(shape + " => " + mapper.writeValueAsString(Thing.THING_A));
        }
    }
}

class JsonFactory {
    private final AnnotationIntrospector defaultIntrospector = new JacksonAnnotationIntrospector();
    private final EnumMap<Shape, ObjectMapper> instances = new EnumMap<>(Shape.class);

    public JsonFactory() {
        final List<Shape> notAllowed = Arrays.asList(Shape.BOOLEAN, Shape.BINARY);
        Arrays.stream(Shape.values())
                .filter(shape -> !notAllowed.contains(shape))
                .forEach(shape -> instances.put(shape, createNewWithEnumShape(shape)));
    }

    private ObjectMapper createNewWithEnumShape(Shape shape) {
        DynamicEnumAnnotationIntrospector enumIntrospector = new DynamicEnumAnnotationIntrospector(shape);

        ObjectMapper mapper = new ObjectMapper();
        mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(enumIntrospector, defaultIntrospector));

        return mapper;
    }

    public ObjectMapper getWithEnumShapeSetTo(Shape shape) {
        Objects.requireNonNull(shape);

        final ObjectMapper mapper = instances.get(shape);
        if (mapper == null) {
            return new ObjectMapper();
        }

        return mapper;
    }
}

class DynamicEnumAnnotationIntrospector extends AnnotationIntrospector {

    private final Shape shape;

    public DynamicEnumAnnotationIntrospector(Shape shape) {
        this.shape = Objects.requireNonNull(shape);
    }

    @Override
    public Version version() {
        return new Version(1, 0, 0, "Dynamic enum shape", "your.package", "jackson.dynamic.enum");
    }

    @Override
    public JsonFormat.Value findFormat(Annotated memberOrClass) {
        final Class<?> rawType = memberOrClass.getRawType();
        if (rawType.isEnum() && rawType.getPackage().getName().startsWith("your.package")) {
            return JsonFormat.Value.forShape(shape);
        }

        return super.findFormat(memberOrClass);
    }
}

上面的代码显示:

ANY => "THING_A"
NATURAL => "THING_A"
SCALAR => "THING_A"
ARRAY => 0
OBJECT => {"thing":"a"}
NUMBER => 0
NUMBER_FLOAT => 0
NUMBER_INT => 0
STRING => "THING_A"
BOOLEAN => "THING_A"
BINARY => "THING_A"

上面的代码当然是过大了,但是我想证明我们拥有的可能性.我们只有3个不同的输出,因此您可以将具有相同输出的值分组,并最多创建3个不同的ObjectMappers.

Above code of course is overkill but I wanted to show possibilities we have. We have only 3 different outputs so you can group values with the same output and create maximum 3 different ObjectMappers.

这篇关于如何将枚举序列化为对象形状和默认字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆