简体   繁体   English

如何将枚举序列化为 Object 形状和默认字符串?

[英]How to serialise Enums as both Object Shape and default string?

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 serializes as the name of the values, eg: Jackson序列化为值的名称,例如:

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

If we add the annotation to treat serialisation as an object:如果我们添加注释以将序列化视为 object:
@JsonFormat(shape = JsonFormat.Shape.OBJECT) it will serialize the attributes: @JsonFormat(shape = JsonFormat.Shape.OBJECT)它将序列化属性:

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"

The above question is similar and has already been answered.上面的问题是类似的,已经回答了。 Jackson ObjectMapper set JsonFormat.Shape.ARRAY without annotation . Jackson ObjectMapper 设置 JsonFormat.Shape.ARRAY 无注释

You can use custom object mapper specific for the Enum and different object mapper for other classes.您可以使用特定于 Enum 的自定义 object 映射器和其他类的不同 object 映射器。

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

Above code prints:上面的代码打印:

{"thing":"a"}

Now, you can create two instances of ObjectMapper and for one configure your own annotation introspector and second one leave with default.现在,您可以创建两个ObjectMapper实例,一个配置您自己的注释内省,第二个保留默认值。 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:如果您真的想以动态方式使用它,您可以为每个可用的Shape值创建一个ObjectMapper ,并且 select 需要一个给定形状:

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

Above code prints:上面的代码打印:

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"

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 .我们只有 3 个不同的输出,因此您可以使用相同的 output 对值进行分组,并创建最多 3 个不同的ObjectMappers

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM