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

Jackson@JsonValue注释选择性地覆盖或禁用

阎雪峰
2023-03-14

我有一个具有以下属性的枚举:

private Integer id;
private String name;
private String description;

此枚举有一个带有Jackson的@JsonValue注释的函数:

@JsonValue
public String toValue() {
    return Stream.of(values())
            .filter(eventType -> eventType == this)
            .findAny()
            .map(EventType::toString)
            .orElseThrow(() -> new IllegalArgumentException("Unable to convert EventType to value:" + this));
}

这将根据需要执行,将枚举值序列化为toString返回的值,这是枚举的名称。

我希望能够禁用@JsonValue注释,并且仅使用附加到此类的 Jackson 的默认 JSON 序列化行为:在某些情况下,必须获取表示整个枚举的对象而不仅仅是名称,@JsonFormat(shape = JsonFormat.Shape.OBJECT)。

Jackson似乎没有内置这种能力(要么是这样,要么是我对它的理解不够好)。我不能创建一个扩展这个类的包装类,因为Java不允许枚举这样做。

有什么建议吗?

共有2个答案

柴昆杰
2023-03-14

我想不出一个现成的解决方案,但我能想到的最接近的选项是为这个特定的枚举类型使用自定义序列化程序

添加自定义序列化程序很容易,只需要扩展< code>JsonSerializer类并实现< code>serialize方法,然后在需要的地方使用类型的< code>@JsonSerialize批注中的类(不需要< code>@JsonValue)。枚举对象将被传递到< code>serialize方法中,在那里您可以选择写入< code>toString或< code>toValue。

下面提供了示例代码以及输出。

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.IOException;
import java.util.stream.Stream;

public class SOQuestion {

    static ThreadLocal<Boolean> USE_TO_STRING = ThreadLocal.withInitial(() -> false);

    @JsonSerialize(using = MySerializer.class)
    enum EventType{
        ONE(1, "One", "Just One"), TWO(2, "Two", "Just Two");

        private Integer id;
        private String name;
        private String description;

        EventType(Integer id, String name, String description) {
            this.id = id;
            this.name = name;
            this.description = description;
        }

        public String toValue() {
            return Stream.of(values())
                    .filter(eventType -> eventType == this)
                    .findAny()
                    .map(EventType::toString)
                    .map(s -> "toValue="+s)
                    .orElseThrow(() -> new IllegalArgumentException("Unable to convert EventType to value:" + this));
        }
    }

    @Data
    @AllArgsConstructor
    static class Dummy{
        int someNum;
        EventType eventType;
    }

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Dummy dummy = new Dummy(100, EventType.ONE);
        System.out.println("**** DEFAULT *****");
        System.out.println(objectMapper.writeValueAsString(dummy));
        System.out.println("**** toString *****");
        USE_TO_STRING.set(true);
        System.out.println(objectMapper.writeValueAsString(dummy));
    }

    private static class MySerializer extends JsonSerializer<EventType> {
        @Override
        public void serialize(EventType value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
            if(USE_TO_STRING.get()){
                gen.writeString(value.toString());
            }else{
                gen.writeString(value.toValue());
            }
        }
    }
}

输出:

**** DEFAULT *****
{"someNum":100,"eventType":"toValue=ONE"}
**** toString *****
{"someNum":100,"eventType":"ONE"}

为使用lombok而道歉,它使事情变得简单。如果你不熟悉,是时候拿起它了。

韦志新
2023-03-14

这可以通过使用Mixin来实现。

保持枚举类不变,创建一个 mixin 类:

// MyEnumMixin.java

import com.fasterxml.jackson.annotation.JsonValue;

public abstract class MyEnumMixin {

    @JsonValue(false)
    public abstract String toValue();
}

然后在创建映射器时添加混音

// MyService.java

...
    ObjectMapper mapper = new ObjectMapper();
    mapper.addMixIn(MyEnum.class, MyEnumMixin.class);
    return mapper.writeValueAsString(pojoWithEnum);
...

感谢https://stackoverflow.com/users/6911095/ldz帮助我解决了类似的问题,并能够在这里添加答案。https://stackoverflow.com/a/59459177/7589862

 类似资料:
  • 我正在使用jackson库,我遇到了一种情况,我想在序列化/反序列化时使用对象映射器禁用@JsonFormat注释。 我的Api代码在第三方库中,所以我不能删除/添加任何注释,所以objectMapper是唯一的选择。 Api类别: 我的代码: 我希望这种转换成功发生。 目前我得到了:com.fasterxml.jackson.databind。JsonMappingException:格式无效:

  • 问题内容: 有谁知道如何使用jQuery选择HTML注释节点吗? 这不会引起评论。 问题答案: 有jQuerycomments()插件将为您完成此操作。用法:

  • 问题内容: 现在,我正在尝试用我的LESS代码在CSS3中执行此操作: 但是,LESS编译时将输出以下内容: 有没有办法告诉LESS不要以这种方式编译它并正常输出它? 问题答案: 使用[转义字符串(也称为转义值): 另外,如果您需要将Less Math与转义字符串混合使用: 编译为: 默认情况下,这作为“少”将值(转义的字符串和数学结果)连接在一起时起作用。

  • 我们可以禁用或覆盖身体解析器后,注入它作为中间件来表达应用程序? 在一个文件(不可编辑,由框架完成)应用程序中。使用(bodyParser.json());出口应用程序; 在另一个文件中,我正在导入应用程序,这里我想为其中一个路由禁用bodyParser。我有办法做到吗?

  • 我试图将某些方法排除在单元测试覆盖范围之外。我之所以使用Cobertura,是因为我发现从2.0版开始,他们引入了一个用于排除方法和类的覆盖忽略注释:https://github.com/Cobertura/Cobertura/wiki/covered-annotations

  • 我想知道如何为添加排除。IE和Chrome似乎用appcache做了正确的事情,而不管我的头是什么,但FF似乎更奇怪一点,它注意到appcache何时发生了变化,我认为我的缓存头搞砸了。 编辑:我应该从WebMvcAutoConfiguration的源代码中添加,它显示了如何为资源设置缓存,我只是不确定如何选择性地禁用我的1case W/O,这可能会破坏spring boot在该文件中设置的其余内