Spring MVC @RequestBody map可选<enum>

时间:2015-07-21 15:43:58

标签: java json spring enums jackson

我有一个使用此方法的休息控制器:

@RequestMapping(value = "", method = { RequestMethod.POST }, produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<?> add(@Valid @RequestBody MyModel myModel, Errors errors) {

        ...
        return new ResponseEntity<SomeObject>(someObject, HttpStatus.OK);
    }

MyModel中有一个字段isMeetingOrSale,即enum(MeetingSaleFlag):

public enum MeetingSaleFlag {
    MEETING("MEETING"),
    SALE("SALE");
    private final String name;       
    private MeetingSaleFlag(String s) { name = s; }
    public boolean equalsName(String otherName) {
       return (otherName == null) ? false : name.equals(otherName);
    }
    public String toString() { return this.name; }
}

它可以映射具有字段"isMeetingOrSale" : "MEETING"

的json

但是json中的值可能是"isMeetingOrSale" : ""或完全缺失,所以在这种情况下我希望将字段映射为null。如果我将字段更改为Optional<MeetingSaleFlag>

我得到了

  

无法读取JSON:无法实例化类型的值[simple type,   来自String值的类java.util.Optional<MeetingSaleFlag>]   ('会议');没有单字符串构造函数/工厂方法\\ n at   [来源:java.io.PushbackInputStream@32b21158;行:17,专栏:18]   (通过参考链:MyModel [\“isMeetingOrSale \”]);

所以问题是如何从json映射可选枚举?

2 个答案:

答案 0 :(得分:4)

感谢Sotirios Delimanolis的评论,我能够解决这个问题。

1)添加

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jdk8</artifactId>
        </dependency>

作为依赖。

2)重新配置Jackson映射器。注册

    @Bean
    @Primary
    public ObjectMapper jacksonObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new Jdk8Module());
        return mapper;
    }

OR 执行此操作以注册jdk8模块

/**
 * @return Jackson jdk8 module to be registered with every bean of type
 *         {@link ObjectMapper}
 */
@Bean
public Module jdk8JacksonModule() {
    return new Jdk8Module();
}
  

自定义Jackson的另一种方法是将com.fasterxml.jackson.databind.Module类型的bean添加到您的上下文中。它们将在ObjectMapper类型的每个bean中注册,为您的应用程序添加新功能时提供全局机制来提供自定义模块。

这样做只会注册附加模块并保留Spring Boot提供的内置Jackson配置。

3)结果

现在,当发送的json中缺少该属性时,它将映射为null (这不是那么好。我期待它会给我一个可选项,我将能够使用.isPresent()。 如果它是一个空字符串("isMeetingOrSale" : ""),杰克逊会返回错误:

  

无法读取JSON:无法构造实例   来自字符串值的MyModel&#39;&#39;:值不是   一个声明的枚举实例名称:[VAL1,VAL2]

对我来说很好看。

有用的链接:Jackson jdk8 moduleSpring MVC configure Jackson

答案 1 :(得分:3)

这是我们代码库的一个例子:

@NotNull // You probably don't want this
@JsonSerialize(using=CountrySerializer.class)
@JsonDeserialize(using=CountryDeserializer.class)
private CountryCode country;

其中CountryCode是 complex 枚举(请参阅nv-i18n),这些是(de)从/到JSON序列化的类:

public class CountrySerializer extends JsonSerializer<CountryCode> {
    @Override
    public void serialize(CountryCode value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        jgen.writeString(value.getAlpha3()); // Takes the Alpha3 code
    }

    public Class<CountryCode> handledType() { return CountryCode.class; }
}

public class CountryDeserializer extends JsonDeserializer<CountryCode> {
    @Override
    public CountryCode deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
        // You can add here the check whether the field is empty/null
        return CountryCode.getByCode(jp.getText());
    }
}

您可以使用 MeetingSaleFlag 而不是 CountryCode 轻松复制相同的方案。