@Value注入boolean设置默认值
问题描述
Springboot 中读取配置文件
1
|
test: |
业务代码如下
1
2
|
@Value ( "${test:true}" ) private boolean test; |
报错如下
nested exception is org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'boolean'; nested exception is java.lang.IllegalArgumentException: Invalid boolean value []
问题分析
根据报错可知,主要问题在于 注入时 test 的值是 String 类型,无法转换成 boolean 类型。
1
2
|
@Value ( "${test:true}" ) private String test; |
于是更改了接收类型,看看获取到的值是否是 true,结果发现 test 值为 “”,而不是设置的默认值
解决方案
报错问题在于只要配置文件中有 test: 所以系统就默认 test 为 “” 而不是按照我所设想的为空所以默认值为 true。
直接删除配置文件中的 test: 即可正常启动。
@Value 源码阅读
在排查问题的过程中也粗略的跟读了一下源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//org.springframework.beans.TypeConverterSupport#doConvert() private <T> T doConvert(Object value, Class<T> requiredType, MethodParameter methodParam, Field field) throws TypeMismatchException { try { return field != null ? this .typeConverterDelegate.convertIfNecessary(value, requiredType, field) : this .typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam); } catch (ConverterNotFoundException var6) { throw new ConversionNotSupportedException(value, requiredType, var6); } catch (ConversionException var7) { throw new TypeMismatchException(value, requiredType, var7); } catch (IllegalStateException var8) { throw new ConversionNotSupportedException(value, requiredType, var8); } catch (IllegalArgumentException var9) { // 最终异常从这里抛出 throw new TypeMismatchException(value, requiredType, var9); } } |
最终赋值在
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//org.springframework.beans.TypeConverterDelegate#doConvertTextValue() private Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) { try { editor.setValue(oldValue); } catch (Exception var5) { if (logger.isDebugEnabled()) { logger.debug( "PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call" , var5); } } // 此处发现 newTextValue 为 "" editor.setAsText(newTextValue); return editor.getValue(); } |
接下来就是如何将 字符串 true 转换为 boolean 的具体代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// org.springframework.beans.propertyeditors.CustomBooleanEditor#setAsText() public void setAsText(String text) throws IllegalArgumentException { String input = text != null ? text.trim() : null ; if ( this .allowEmpty && !StringUtils.hasLength(input)) { this .setValue((Object) null ); } else if ( this .trueString != null && this .trueString.equalsIgnoreCase(input)) { this .setValue(Boolean.TRUE); } else if ( this .falseString != null && this .falseString.equalsIgnoreCase(input)) { this .setValue(Boolean.FALSE); } else if ( this .trueString != null || ! "true" .equalsIgnoreCase(input) && ! "on" .equalsIgnoreCase(input) && ! "yes" .equalsIgnoreCase(input) && ! "1" .equals(input)) { if ( this .falseString != null || ! "false" .equalsIgnoreCase(input) && ! "off" .equalsIgnoreCase(input) && ! "no" .equalsIgnoreCase(input) && ! "0" .equals(input)) { throw new IllegalArgumentException( "Invalid boolean value [" + text + "]" ); } this .setValue(Boolean.FALSE); } else { this .setValue(Boolean.TRUE); } } |
tips:windows 中使用 IDEA 去查找类可以使用 ctrl + shift +alt +N的快捷键组合去查询,mac 系统则是 commond + O
Spring解析@Value
1、初始化PropertyPlaceholderHelper对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
protected String placeholderPrefix = "${" ; protected String placeholderSuffix = "}" ; @Nullable protected String valueSeparator = ":" ; private static final Map<String, String> wellKnownSimplePrefixes = new HashMap<>( 4 ); static { wellKnownSimplePrefixes.put( "}" , "{" ); wellKnownSimplePrefixes.put( "]" , "[" ); wellKnownSimplePrefixes.put( ")" , "(" ); } public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, @Nullable String valueSeparator, boolean ignoreUnresolvablePlaceholders) { Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null" ); Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null" ); //默认值${ this .placeholderPrefix = placeholderPrefix; //默认值} this .placeholderSuffix = placeholderSuffix; String simplePrefixForSuffix = wellKnownSimplePrefixes.get( this .placeholderSuffix); //当前缀为空或跟定义的不匹配,取传入的前缀 if (simplePrefixForSuffix != null && this .placeholderPrefix.endsWith(simplePrefixForSuffix)) { this .simplePrefix = simplePrefixForSuffix; } else { this .simplePrefix = this .placeholderPrefix; } //默认值: this .valueSeparator = valueSeparator; this .ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; } |
2、解析@Value
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
protected String parseStringValue( String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) { StringBuilder result = new StringBuilder(value); //是否包含前缀,返回第一个前缀的开始index int startIndex = value.indexOf( this .placeholderPrefix); while (startIndex != - 1 ) { //找到最后一个后缀的index int endIndex = findPlaceholderEndIndex(result, startIndex); if (endIndex != - 1 ) { //去掉前缀后缀,取出里面的字符串 String placeholder = result.substring(startIndex + this .placeholderPrefix.length(), endIndex); String originalPlaceholder = placeholder; if (!visitedPlaceholders.add(originalPlaceholder)) { throw new IllegalArgumentException( "Circular placeholder reference '" + originalPlaceholder + "' in property definitions" ); } // 递归判断是否存在占位符,可以这样写${acm.endpoint:${address.server.domain:}} placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); // 根据key获取对应的值 String propVal = placeholderResolver.resolvePlaceholder(placeholder); // 值不存在,但存在默认值的分隔符 if (propVal == null && this .valueSeparator != null ) { // 获取默认值的索引 int separatorIndex = placeholder.indexOf( this .valueSeparator); if (separatorIndex != - 1 ) { // 切掉默认值的字符串 String actualPlaceholder = placeholder.substring( 0 , separatorIndex); // 切出默认值 String defaultValue = placeholder.substring(separatorIndex + this .valueSeparator.length()); // 根据新的key获取对应的值 propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder); // 如果值不存在,则把默认值赋值给当前值 if (propVal == null ) { propVal = defaultValue; } } } // 如果当前值不为NULL if (propVal != null ) { // 递归获取存在占位符的值信息 propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); // 替换占位符 result.replace(startIndex, endIndex + this .placeholderSuffix.length(), propVal); if (logger.isTraceEnabled()) { logger.trace( "Resolved placeholder '" + placeholder + "'" ); } startIndex = result.indexOf( this .placeholderPrefix, startIndex + propVal.length()); } else if ( this .ignoreUnresolvablePlaceholders) { // Proceed with unprocessed value. startIndex = result.indexOf( this .placeholderPrefix, endIndex + this .placeholderSuffix.length()); } else { throw new IllegalArgumentException( "Could not resolve placeholder '" + placeholder + "'" + " in value \"" + value + "\"" ); } visitedPlaceholders.remove(originalPlaceholder); } else { startIndex = - 1 ; } } return result.toString(); } |
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/mochi_li/article/details/106349403