<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
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: 即可正常啟動。
在排查問題的過程中也粗略的跟讀了一下原始碼
//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); } }
最終賦值在
//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
1、初始化PropertyPlaceholderHelper物件
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
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(); }
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45