Springboot @Value注入boolean设置默认值方式

网友投稿 1505 2022-08-19


Springboot @Value注入boolean设置默认值方式

目录@Value注入boolean设置默认值问题描述问题分析解决方案@Value 源码阅读Spring解析@Value

@Value注入boolean设置默认值

问题描述

Springboot 中读取配置文件

test:

业务代码如下

@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 类型。

@Value("${test:true}")

private String test;

于是更改了接收类型,看看获取到的值是否是 true,结果发现 test 值为 “”,而不是设置的默认值

解决方案

报错问题在于只要配置文件中有 test: 所以系统就默认 test 为 “” 而不是按照我所设想的为空所以默认值为 true。

直接删除配置文件中的 test: 即可正常启动。

@Value 源码阅读

在排查问题的过程中也粗略的跟读了一下源码

//org.springframework.beans.TypeConverterSupport#doConvert()

private T doConvert(Object value, Class 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);

}

}

最终赋值在

//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 的具体代码:

// 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对象

protected String placeholderPrefix = "${";

protected String placeholderSuffix = "}";

@Nullable

protected String valueSeparator = ":";

private static final Map 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;

//默jFbuYz认值}

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

protected String parseStringValue(

String value, PlaceholderResolver placeholderResolver, Set visitedPlaceholders) {

StringBuilder result = new StringBuilder(value);

//是否包含前缀,返回第一个前缀的开始index

int startIndex = value.indexOfjFbuYz(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.valueSjFbuYzeparator.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 + "'");

http:// }

startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());

}

else if (this.ignoreUnresolvablePlaceholders) {

// Proceed with unprocessed value.

startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.lejFbuYzngth());

}

else {

throw new IllegalArgumentException("Could not resolve placeholder '" +

placeholder + "'" + " in value \"" + value + "\"");

}

visitedPlaceholders.remove(originalPlaceholder);

}

else {

startIndex = -1;

}

}

return result.toString();

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:剑指Offer之Java算法习题精讲数组与字符串
下一篇:剑指Offer之Java算法习题精讲数组与列表的查找及字符串转换
相关文章