当前位置: 首页 > 知识库问答 >
问题:

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

穆歌者
2023-03-14

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

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

  private String thing;

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

  // Getters...
}

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

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

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

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

我希望能够在序列化过程中决定使用这些方法中的哪一个。因为这跨越了大量枚举,我宁愿不编辑每个枚举。有什么好方法可以做到这一点吗?

像这样的东西会很棒:

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

共有2个答案

班建义
2023-03-14

因为,com。fasterxml。杰克逊。注释。JsonFormat是一种注释,您可以实现自己的com。fasterxml。杰克逊。数据绑定。AnnotationIntrospector和所有枚举所需的返回值。下面是一个简单的例子:

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实例,其中一个配置自己的注释内省器,另一个保留默认值。如果您真的想以动态方式使用它,可以为每个可用的形状值创建一个对象映射器,并为给定形状选择所需的值:

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个不同的对象映射器。

罗宪
2023-03-14

上述问题类似,已经得到了回答。Jackson ObjectMapper设置JsonFormat。形状不带注释的数组

可以为枚举使用特定的自定义对象映射器,为其他类使用不同的对象映射器。

 类似资料:
  • 我的JSON如下所示: 我的课程如下所示: 如何反序列化到映射如和到

  • 本文向大家介绍Rust 将枚举序列化为字符串,包括了Rust 将枚举序列化为字符串的使用技巧和注意事项,需要的朋友参考一下 示例            

  • 我在一个JSON文件中记录一些东西,我有一个datetime对象,我把它转换成一个字符串,这样我就可以在JSON中记录它(它不接受datetime对象)。 我的问题是如何将datetime字符串转换回datetime对象。我知道strptime,我只是不知道什么格式会使它与其他datetime.now对象兼容。 每当我尝试使用strtime时,我都会使用格式,并出现以下错误: 那么,默认datet

  • 问题内容: 我能够将一个对象序列化为一个文件,然后再次还原它,如下面的代码片段所示。我想将对象序列化为字符串并存储到数据库中。谁能帮我? 问题答案: 你应该使用BLOB。使用JDBC非常简单。 你发布的第二个代码的问题是编码。你还应该对字节进行编码,以确保它们均不会失败。 如果你仍然想将其记录为字符串,则可以使用java.util.Base64对字节进行编码。 仍然应该将CLOB用作数据类型,因为

  • 问题内容: 我需要将对象序列化为String并反序列化。 我阅读了关于stackoverflow的建议,并编写了以下代码: } 但我得到错误: 为什么?我预期:dx = 5 dy = 3 怎样做才好?啊。我不想在文件中写入此对象。我必须使用字符串格式。 问题答案: 使用 代替 ,因为String转换会破坏数据(由于编码)。 如果确实需要将结果存储在字符串中,则需要一种安全的方法将任意字节存储在字符

  • 问题内容: 如何将上述字符串反序列化为java对象。 我正在使用的类是 问题答案: @基达 我假设您可以控制JSON输入字符串的创建方式。我认为JSON字符串格式不正确,无法对地图类型进行默认的GSON反序列化。 我已经修改了输入字符串供您考虑,这将导致非null的LocalLocationId 如果我对输入字符串的假设不正确,请发表评论。 编辑1:由于无法修改输入,请考虑编写自定义解串器。以下是