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

时间:2018-02-22 00:09:12

标签: java jackson

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

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)在某些情况下,必须获取表示整个枚举的对象,而不仅仅是这个名字。

杰克逊似乎没有内置这种能力(或者我不太了解它)。我无法创建一个扩展此类的包装类,因为Java不允许使用枚举。

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

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

添加自定义序列化程序很简单,只需要一个扩展JsonSerializer类并实现serialize方法,然后使用@JsonSerialize注释中的类到需要的类型(和你一样)不需要@JsonValue)。枚举对象将传递到serialize方法,您可以选择编写toStringtoValue

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

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的道歉让事情变得简单。如果你不熟悉,那就该把它拿起来。