【问题标题】:Deserialize enum ignoring case in Spring Boot controller在 Spring Boot 控制器中反序列化枚举忽略大小写
【发布时间】:2018-10-18 06:21:36
【问题描述】:

我有 Spring Boot 端点,它有枚举作为查询参数:

@GetMapping("/example")
public List<Example> getByEnum(@RequestParam(name = "exampleEnum", required = false) ExampleEnum exampleEnum) {
    // code
}

还有枚举类:

public enum ExampleEnum {
    FIRST,
    SECOND,
}

如果我将大写枚举值传递给端点,它会很好地反序列化,但会抛出小写错误:

java.lang.IllegalArgumentException: No enum constant 

如何反序列化 Spring Boot Rest 端点中忽略大小写的枚举?

此问题不重复,因为它与查询参数反序列化有关。

【问题讨论】:

  • 不是重复的,因为该问题专门指查询字符串参数,这些参数的处理方式与帖子正文的属性不同。
  • 叹息 - 两个答案都是错误的,我无法提供正确答案,因为该问题已被不知道自己在说什么的人关闭为重复。
  • @Dave 我已经修改了问题。您可以按问题下方的重新打开吗?

标签: java spring spring-boot enums


【解决方案1】:

编辑: 下面的答案不正确。您必须定义一个自定义 PropertyEditor 并将其注册到 Spring @InitBinder 我解释了 in this post。感谢@Dave 在 cmets 中指出这一点。


Spring Boot 2.0 使用的是具有 ACCEPT_CASE_INSENSITIVE_ENUMS 功能的 Jackson 2.9。您应该可以通过设置来启用它

spring.jackson.mapper.ACCEPT_CASE_INSENSITIVE_ENUMS = true 

docs, Appendix A 的属性。

【讨论】:

  • 添加属性和 objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);但仍然得到 java.lang.IllegalArgumentException: No enum constant
  • 您配置的objectMapper 很可能不是Web 层使用的那个。使用我的示例中的 Spring Boot 属性,然后检查。见Jackson2ObjectMapperBuilder类。
  • 我同时使用了:spring boot 属性并在自定义对象映射器上启用。自定义 ObjectMapper 配置被标记为 \@Bean \@Primary 所以它应该适用于所有层。
  • Jackson 甚至没有在这里查看,因为我们没有反序列化消息体 - Spring MVC 而是 转换 请求参数。为此,Spring 使用 DataBinder 注册的 PropertyEditor,或者,如果失败,则使用来自 web ConversionService 的匹配 TypeConverter。要解决此问题,您应该扩展 PropertyEditorSupport 并添加一个 @InitBinder 注释方法,将其注册到您的控制器。
【解决方案2】:
import com.fasterxml.jackson.annotation.JsonCreator;
import java.util.Arrays;
import java.util.Optional;

public enum ExampleEnum {
    FIRST,
    SECOND;

    @JsonCreator
    public static ExampleEnum setValue(String key) {
        return Arrays.stream(ExampleEnum.values())
            .filter(exampleEnum -> exampleEnum.toString().equals(key.toUpperCase()))
            .findAny()
            .orElse(null);
}

【讨论】:

  • 还在用这样的 Optional 吧?应该是 optional.orElse(null)。请参阅 Stuart Mark 的演讲 youtube.com/watch?v=Ej0sss6cq14
  • 然后使用 orElse(null) 代替 if else
【解决方案3】:

您可以为所有枚举制作通用转换器

package ru.grancall.kb.logging.service.dto.converter;

import lombok.AllArgsConstructor;
import org.apache.commons.lang3.EnumUtils;
import java.beans.PropertyEditorSupport;

@AllArgsConstructor
public class EnumConverter extends PropertyEditorSupport {
    private Class type;

    public void setAsText(String text) {
        setValue(EnumUtils.getEnum(type, text.toUpperCase()));
    }
}

然后在你的任何控制器中使用它:

@InitBinder
    public void initBinder(WebDataBinder dataBinder) {
        dataBinder.registerCustomEditor(YourEnum.class, new EnumConverter(YourEnum.class));
    }

【讨论】:

    猜你喜欢
    • 2019-08-05
    • 2017-05-23
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多