自定义 YML 配置文件 String 转换 Enum
Custom YML configuration file String conversion Enum
在Springboot工程中,yml文件中的配置可以自动转换为@ConfigurationProperties
注解bean,我从官方文档和源码中找到 ApplicationConversionService#addApplicationConverters()
方法添加一个默认的LenientStringToEnumConverterFactory
来处理所有String到Enum的转换,它通过Enum.valueOf()
实现,但是我想使用其他规则将字符串转换为枚举的例子,就像fromAlias()
下面的方法,
@ConfigurationProperties(prefix = "head")
@Component
@Data
public class HeadProperties {
private PayType payType;
private Integer cast;
@Getter
@RequiredArgsConstructor
enum PayType {
GOLD("GOLD", "金币"), DIAMOND("DIAMOND", "钻石"), VIP_FREE("VIP_FREE", "会员免费");
private final String val;
private final String alias;
static PayType fromAlias(String alias) {
return Arrays.stream(values())
.filter(type -> alias.equals(type.getAlias()))
.findAny()
.orElse(null);
}
}
}
以下是yml文件配置
head:
payType: "金币"
cast: 10
不知道入口在哪里,所以程序一运行就报错
代码:
@SpringBootApplication
@Slf4j
public class DemoApplication{
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
ApplicationRunner runner(HeadProperties headConfig) {
return arg -> log.info("head config:{}", headConfig);
}
}
以下是错误信息:
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'head.pay-type' to com.example.demo.HeadProperties$PayType:
Property: head.pay-type
Value: 金币
Origin: class path resource [application.yml] - 2:12
Reason: failed to convert java.lang.String to com.example.demo.HeadProperties$PayType (caused by java.lang.IllegalArgumentException: No enum constant com.example.demo.HeadProperties.PayType.金币)
Action:
Update your application's configuration. The following values are valid:
DIAMOND
GOLD
VIP_FREE
我尝试将各种转换器(如下图)注入到容器中,但仍然没有用。
@Component
public class PayTypeConverter implements Converter<String, HeadProperties.PayType> {
@Override
public HeadProperties.PayType convert(String source) {
return HeadProperties.PayType.fromAlias(source);
}
}
@Component
public class PayTypeConverter implements Converter<String, Enum<HeadProperties.PayType>> {
@Override
public Enum<HeadProperties.PayType> convert(String source) {
return HeadProperties.PayType.fromAlias(source);
}
}
如何满足这个要求?
用于 @ConfigurationProperties
绑定的转换器需要一个特殊的限定符来告诉 Spring 它们将用于该目的。
这个注释存在 - @ConfigurationPropertiesBinding
。 Javadoc如下:
Qualifier for beans that are needed to configure the binding of @ConfigurationProperties (e.g. Converters).
所以只需要将该注释添加到您的转换器,然后 Spring 将在绑定过程中使用它:
@Component
@ConfigurationPropertiesBinding
public class PayTypeConverter implements Converter<String, HeadProperties.PayType> {
@Override
public HeadProperties.PayType convert(String source) {
return HeadProperties.PayType.fromAlias(source);
}
}
然后产生预期的输出:
head config:HeadProperties(payType=GOLD, cast=10)
还有一个小注意事项,在编写自定义转换器时,请注意返回 null 不会触发错误(假设没有配置其他措施来防止这种情况发生)。这意味着与 out-of-the-box 枚举转换器不同,如果找不到匹配的枚举,您的自定义转换器不会产生错误。您可以通过抛出异常而不是返回 null 来解决这个问题。
在Springboot工程中,yml文件中的配置可以自动转换为@ConfigurationProperties
注解bean,我从官方文档和源码中找到 ApplicationConversionService#addApplicationConverters()
方法添加一个默认的LenientStringToEnumConverterFactory
来处理所有String到Enum的转换,它通过Enum.valueOf()
实现,但是我想使用其他规则将字符串转换为枚举的例子,就像fromAlias()
下面的方法,
@ConfigurationProperties(prefix = "head")
@Component
@Data
public class HeadProperties {
private PayType payType;
private Integer cast;
@Getter
@RequiredArgsConstructor
enum PayType {
GOLD("GOLD", "金币"), DIAMOND("DIAMOND", "钻石"), VIP_FREE("VIP_FREE", "会员免费");
private final String val;
private final String alias;
static PayType fromAlias(String alias) {
return Arrays.stream(values())
.filter(type -> alias.equals(type.getAlias()))
.findAny()
.orElse(null);
}
}
}
以下是yml文件配置
head:
payType: "金币"
cast: 10
不知道入口在哪里,所以程序一运行就报错 代码:
@SpringBootApplication
@Slf4j
public class DemoApplication{
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
ApplicationRunner runner(HeadProperties headConfig) {
return arg -> log.info("head config:{}", headConfig);
}
}
以下是错误信息:
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'head.pay-type' to com.example.demo.HeadProperties$PayType:
Property: head.pay-type
Value: 金币
Origin: class path resource [application.yml] - 2:12
Reason: failed to convert java.lang.String to com.example.demo.HeadProperties$PayType (caused by java.lang.IllegalArgumentException: No enum constant com.example.demo.HeadProperties.PayType.金币)
Action:
Update your application's configuration. The following values are valid:
DIAMOND
GOLD
VIP_FREE
我尝试将各种转换器(如下图)注入到容器中,但仍然没有用。
@Component
public class PayTypeConverter implements Converter<String, HeadProperties.PayType> {
@Override
public HeadProperties.PayType convert(String source) {
return HeadProperties.PayType.fromAlias(source);
}
}
@Component
public class PayTypeConverter implements Converter<String, Enum<HeadProperties.PayType>> {
@Override
public Enum<HeadProperties.PayType> convert(String source) {
return HeadProperties.PayType.fromAlias(source);
}
}
如何满足这个要求?
用于 @ConfigurationProperties
绑定的转换器需要一个特殊的限定符来告诉 Spring 它们将用于该目的。
这个注释存在 - @ConfigurationPropertiesBinding
。 Javadoc如下:
Qualifier for beans that are needed to configure the binding of @ConfigurationProperties (e.g. Converters).
所以只需要将该注释添加到您的转换器,然后 Spring 将在绑定过程中使用它:
@Component
@ConfigurationPropertiesBinding
public class PayTypeConverter implements Converter<String, HeadProperties.PayType> {
@Override
public HeadProperties.PayType convert(String source) {
return HeadProperties.PayType.fromAlias(source);
}
}
然后产生预期的输出:
head config:HeadProperties(payType=GOLD, cast=10)
还有一个小注意事项,在编写自定义转换器时,请注意返回 null 不会触发错误(假设没有配置其他措施来防止这种情况发生)。这意味着与 out-of-the-box 枚举转换器不同,如果找不到匹配的枚举,您的自定义转换器不会产生错误。您可以通过抛出异常而不是返回 null 来解决这个问题。