java 枚举的功能挺多,但是坑更多,使用的时候要注意。如下面这个枚举。

@Getter
@AllArgsConstructor
public enum EnumExpenseType implements BaseEnum {
小欢喜(1),
大欢喜(2);
private final int value;
}

咋一看,没什么问题,但是具体使用过程中,总是会出问题。原因就是这个枚举没有按照从0开始索引,除此之外即使从0开始,中间有断的索引也会有问题。主要出现在以下方面:

1. 在controller的方法中,比如以这个枚举为参数,如下代码:

    @RequestMapping("/**")
public String getRejectReasons(EnumExpenseType type) {
return "";
}

前台传入的参数如果是type:1, 那它值应该是:小欢喜,实际上呢?

Caused by: java.lang.IllegalArgumentException: No enum constant com.**.EnumReasonType.1
at java.lang.Enum.valueOf(Enum.java:238) ~[?:1.8.0_111]
at org.springframework.core.convert.support.StringToEnumConverterFactory$StringToEnum.convert(StringToEnumConverterFactory.java:52) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.core.convert.support.StringToEnumConverterFactory$StringToEnum.convert(StringToEnumConverterFactory.java:38) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.core.convert.support.GenericConversionService$ConverterFactoryAdapter.convert(GenericConversionService.java:436) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:191) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:129) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:73) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:53) ~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:693) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:124) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
... 81 more

Failed to convert value of type 'java.lang.String' to required type 'com.**.EnumExpenseType'; 
nested exception is org.springframework.core.convert.ConversionFailedException:
Failed to convert from type [java.lang.String] to type [com.**.EnumExpenseType] for value '1';
nested exception is java.lang.IllegalArgumentException: No enum constant com.***.EnumExpenseType.1
实际上它却报了个错。转换失败了。
查看报错信息,可以定位到是spring框架中StringToEnumConverterFactory中转换失败,具体代码如下:
private static class StringToEnum<T extends Enum> implements Converter<String, T> {

        private final Class<T> enumType;

        public StringToEnum(Class<T> enumType) {
this.enumType = enumType;
} @Override
public T convert(String source) {
if (source.isEmpty()) {
// It's an empty enum identifier: reset the enum value to null.
return null;
}
return (T) Enum.valueOf(this.enumType, source.trim());
}
}

是Enum.valueOf这里报错,Enum.valueOf的后面的值并不是我们的value,而是name(这里的小欢喜)。

所以,我们不能使用这个spring提供converter,需要自定义一个:StringToEnumConverterFactory

public class StringToEnumConverterFactory implements ConverterFactory<String, BaseEnum> {

    private static final Map<Class, Converter> converterMap =  new HashMap<>();

    @Override
public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
Converter<String, T> converter = converterMap.get(targetType);
if(converter == null) {
converter = new StringToEnumConverter<>(targetType);
converterMap.put(targetType, converter);
}
return converter;
} class StringToEnumConverter<T extends BaseEnum> implements Converter<String, T> {
private Map<String, T> enumMap = new HashMap<>(); StringToEnumConverter(Class<T> enumType) {
T[] enums = enumType.getEnumConstants();
for(T e : enums) {
enumMap.put(String.valueOf(e.getValue()), e);
}
} @Override
public T convert(String source) { T t = enumMap.get(source);
if (t == null) {
// 异常可以稍后去捕获
throw new IllegalArgumentException("No element matches " + source);
}
return t;
}
} }

然后再将这个工厂配置到项目中WebMvcConfigurationSupport:

@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverterFactory(new StringToEnumConverterFactory()); }

意思就是string 转 BaesEnum都走这个converter。

至此这个坑就算解决了。

下一篇继续...

spring boot 枚举使用的坑的更多相关文章

  1. spring boot 枚举使用的坑3

    上一篇说到spring boot 使用jackson在枚举enum序列化和反序列化的问题, 再来说说在JPA中实体entity使用枚举的问题. 还是这个枚举: @Getter @AllArgsCons ...

  2. spring boot 枚举使用的坑2

    上一篇说到在枚举当在controller的方法做参数时的坑,解决方法是配置了一个converter,后来想想,如果不闲每次都加一个注解麻烦的话,可以在参数前面加一个注解,添加一个解析器应该也可以解决这 ...

  3. 部署spring boot + Vue遇到的坑(权限、刷新404、跨域、内存)

    部署spring boot + Vue遇到的坑(权限.刷新404.跨域.内存) 项目背景是采用前后端分离,前端使用vue,后端使用springboot. 工具 工欲善其事必先利其器,我们先找一个操作L ...

  4. 初学spring boot踩过的坑

    一.搭建spring boot环境 maven工程 pom文件内容 <project xmlns="http://maven.apache.org/POM/4.0.0" xm ...

  5. Spring Boot 学习填的坑一

    1.关于springBoot自动扫描规则: SpringBoot项目的Bean装配默认规则是根据Application类所在的包位置从上往下扫描! "Application"类是指 ...

  6. spring boot & mybatis集合的坑

    因为是使用的mybatis逆向工程自动生成的实体类和dao层,然后在读取某一个表的content字段时出现问题. 问题描述:在mysql数据库里可以直接查询到这个字段的内容,但是使用java相关的方法 ...

  7. 从源码看Spring Security之采坑笔记(Spring Boot篇)

    一:唠嗑 鼓捣了两天的Spring Security,踩了不少坑.如果你在学Spring Security,恰好又是使用的Spring Boot,那么给我点个赞吧!这篇博客将会让你了解Spring S ...

  8. spring boot升级到2.x的坑

    升级到spring boot 2.x后,发现了好多坑,现记录下来. 1.pom文件依赖的变化 1.x中,依赖是这样的: <dependency> <groupId>org.sp ...

  9. spring cloud: 升级到spring boot 2.x/Finchley.RELEASE遇到的坑

    spring boot2.x已经出来好一阵了,而且spring cloud 的最新Release版本Finchley.RELEASE,默认集成的就是spring boot 2.x,这几天将一个旧项目尝 ...

随机推荐

  1. Shell中的特殊字符(三)

    一 通配符 [root@192 test]# touch abc [root@192 test]# touch abcd [root@192 test]# touch 012 [root@192 te ...

  2. 【转】ACM-数学总揽

    转自: http://www.aiuxian.com/article/p-2262657.html 数学也分好几大部分,各种算法也很多,一时不知从哪里开始,算了,具体的后面再说吧,鉴于最近遇到的有关博 ...

  3. Unity PlayerPrefs 存储的位置

    Mac OS 在Mac OS X上PlayerPrefs是存储在~/Library/Preferences文件夹,名为unity.[company name].[product name].plist ...

  4. [CSP-S模拟测试]:旅行计划(分块+DP)

    题目传送门(内部题83) 输入格式 第一行两个整数$n,m$ 接下来$m$行,每行三个整数,$u,v,w$,表示从$u$到$v$有一条权值为$w$的边 接下来一行有一个整数$q$,表示$q$天 接下来 ...

  5. javadoc生成文档

    标签(空格分隔): javadoc java生成html的文档: 要生成注释文档html格式,java里面提供一个工具:javadoc 例如: javadoc -d myhelp -author -v ...

  6. @RequestMapping 和@ResponseBody 和 @RequestBody和@PathVariable 注解 注解用法

    接下来讲解一下 @RequestMapping  和@ResponseBody 和 @RequestBody和@PathVariable 注解 注解用法 @RequestMapping 为url映射路 ...

  7. day66—angularJS学习笔记-表达式

    转行学开发,代码100天——2018-05-21 angular的变量数据初始化: ng-init="quantity=1;cost=30;student={firstName:'李',la ...

  8. 转]@SuppressWarnings 详解

    转自:http://gladto.iteye.com/blog/728634 背景知识:        从JDK5开始提供名为Annotation(注释)的功能,它被定义为JSR-175规范.注释是以 ...

  9. 用JS实现移动的窗口

    https://blog.csdn.net/iteye_21064/article/details/81496640 用JS实现移动的窗口 2007年09月06日 23:23:00 阅读数:3 很简单 ...

  10. wpf datagrid tooltip

    <DataGridTemplateColumn Header="购方名称" Width="260" HeaderStyle="{StaticRe ...