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> 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

Spring解析@Value

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();
    }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 解决SpringBoot @value注解取不到值的问题

    关于@value的springapplication容器的问题 1.在src/main/resources下创建stu.properties文件 ## student.name=Tom student.age=22 student.birthday=1996/01/10 student.sex=true student.hobbies[0]=swimming student.hobbies[1]=basketball student.skills[0]=programming student.s

  • 基于Spring boot @Value 注解注入属性值的操作方法

    本文主要介绍Spring @Value 注解注入属性值的使用方法的分析,文章通过示例代码非常详细地介绍,对于每个人的学习或工作都有一定的参考学习价值 在使用spring框架的项目中,@Value是经常使用的注解之一.其功能是将与配置文件中的键对应的值分配给其带注解的属性.在日常使用中,我们常用的功能相对简单.本文使您系统地了解@Value的用法. @Value注入形式 根据注入的内容来源,@ Value属性注入功能可以分为两种:通过配置文件进行属性注入和通过非配置文件进行属性注入. 非配置文件注

  • Springboot中@Value的使用详解

    Springboot通过@Value注解将配置文件中的属性注入到容器内组件中(可用在@Controller.@Service.@Configuration.@Component等Spring托管的类中) 1.普通字符串注入 例:yml中存在key: name: zs @Value注入 @Value("${name}") public String name; 当yml中的name没有对应值时,即yml中为: name: 此时字符串name的值为"" 可设置注入属性的

  • Spring @Value 设置默认值的实现

    1.概览 Spring 的 @Vaule 注解提供了一种便捷的方法可以让属性值注入到组件中,当属性值不存在的时候提供一个默认值也是非常好用的 这就是我们这篇文章所专注的,如何给 @Vaule 注解指定一个默认值.对于更多的关于 @Vaule 的教程看这篇文章 2.String 默认值 让我们看看对于 String 类型的值,给定一个默认值得基础语法 @Value("${some.key:my default value}") private String stringWithDefau

  • 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: Fa

  • django-xadmin根据当前登录用户动态设置表单字段默认值方式

    相信你一定会设置一个普通字段的默认值: class Offer(models.Model): salary = models.CharField(max_length=64, blank=True, default='6000', verbose_name='薪资待遇') 相信你还能动态设置外键字段的默认值: class Interview(models.Model): department = models.ForeignKey('departments.Department', relate

  • 使用JavaBean根据指定条件设置属性值默认值方式

    目录 JavaBean根据指定条件设置属性值默认值 使用场景 使用范围 使用示例 JavaBean对象成员变量默认值及数组默认值 JavaBean根据指定条件设置属性值默认值 使用场景 当bean数据中已经装配好其他数据,在逻辑以及数据转换完成的最后一步进行数据默认值设置:如果bean的属性较少,可以手动写if条件就行了,如果bean的属性太多,你不希望写太多if的时候,这个方法是很不错的方法: 使用范围 仅限于当前类,不能给父类设置值 也是参考了其他博主的方法,做的优化和修改,由于时间过了很长

  • 关于el-select组件设置默认值的实现方式

    目录 el-select组件设置默认值问题 如何给el-select赋默认值 el-select组件设置默认值问题 最近写项目的时候遇到将el-select组件设置默认值需求,通过查阅资料发现很多是使用v-model来实现的,但是只用v-model可能会有一些小小的问题. 因此根据他们的进行改变了一下 实现方式 el-select组件:    <el-select v-model="templateValue" placeholder="请选择模板" @cha

  • golang给函数参数设置默认值的几种方式小结(函数参数默认值

    目录 前言 强制改变 使用可变参数语法糖 利用结构体的config 转换函数的全部参数 补充知识:Golang中设置函数默认参数的优雅实现 总结 前言 这个问题相当麻烦,根据golang-nuts/google groups中的这篇文章,golang现在与将来都不会支持参数默认值.Go始终在使得自己变得尽可能的简单,而增加这种额外的支持会使parser变得更复杂. 设置参数值的好处: 可以缺省部分参数. 可以提供一种默认的,行之有效的配置. 但是参考资料中提到了几种实现默认值的方法: 强制改变

  • Spring Data JPA 设置字段默认值方式

    目录 Spring Data JPA设置字段默认值 Spring Data JPA设置字段默认值失败 Spring Data JPA设置字段默认值 在Column注解中写入以下两个属性,为什么自己查一下文档吧,即可实现字段默认值设置,并顺带解决save方法所生成的sql语句中自动填充字段为null的问题. 默认值无法更新,所以如果想在代码里修改字段默认值,你需要重新建表. @Column(insertable = false,columnDefinition = "int default 1&q

  • select2 ajax 设置默认值,初始值的方法

    在做功能的时候需要修改数据, 修改数据时需要显示原始值. 但是在select2的时候 显示原始值是一个非常非常非常非常非常要命的难题. 研究了3个小时, 最后使用$.ajax 重新加载原始值, 并显示. //two AJAX获取数据方式(每次请求) var $c_HospitalCode = $("#c_HospitalCode").select2({ ajax: { type: 'GET', url: "/Report/AjaxOption/Ajax_LoadHospita

  • 记录一个使用Spring Data JPA设置默认值的问题

    目录 Spring Data JPA设置默认值的问题 一开始经过百度,写法是这样的 于是改了第二版 在大佬的指点下,有了第三种写法 Jpa设置默认值约束 1.修改建表时的列定义属性 2.通过Hibernate(org.hibernate.annotations.ColumnDefault) Spring Data JPA设置默认值的问题 我有一个entity实体,其中里面有一个布尔类型的字段: //entity table注解略 public class TableEntity { privat

  • 举例说明如何为JavaScript的方法参数设置默认值

    你是否遇到过这样的情况,写了个function,无参数. function showUserInfo(){ alert("你好!我是小明."); } function showUserInfo(){ alert("你好!我是小明."); } 调用: showUserInfo(); showUserInfo(); 后来,发现其他地方也需要这个function,但是有变量值已经在function里面写死了,怎么办?加个参数吧. function showUserInfo

随机推荐