Cannot convert value of type ‘java.lang.String‘ to required type ‘org.example.ioc.MyServiceB‘

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serviceA' defined in class path resource [spring-bean.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'org.example.ioc.MyServiceB' for property 'serviceB'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.example.ioc.MyServiceB' for property 'serviceB': no matching editors or conversion strategy found
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:628)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
	at org.example.App.main(App.java:16)
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'org.example.ioc.MyServiceB' for property 'serviceB'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.example.ioc.MyServiceB' for property 'serviceB': no matching editors or conversion strategy found
	at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:595)
	at org.springframework.beans.AbstractNestablePropertyAccessor.convertForProperty(AbstractNestablePropertyAccessor.java:609)
	at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:219)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1756)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1712)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1452)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)
	... 11 more
Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.example.ioc.MyServiceB' for property 'serviceB': no matching editors or conversion strategy found
	at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:262)
	at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:590)
	... 17 more

由于在 spring-beans.xml 文件中使用 配置 serviceA 的依赖,导致 ioc 容器在实例化 serviceA 之后,调用 applyPropertyValues 方法进行属性值的注入时,PropertyValue 对应的值是 RuntimeBeanNameReference 而不是 RuntimeBeanReference,所以经过 BeanDefinitionValueResolver 解析后得到的是 “serviceB” 字符串(serviceB 的 beanName)而不是 serviceB 对应的 bean 对象,因此在之后的 convertForProperty 方法中抛出类型转换异常。正确配置应该是使用

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    // ...
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
    // ...
    // 遍历 BeanDefinition 中配置的所有属性值
    // 即 spring-beans.xml 文件中配置的 property 子元素
    // PropertyValue(nameA)
    // PropertyValue(RuntimeBeanNameReference)
    for (PropertyValue pv : original) {
        // ...
        String propertyName = pv.getName();// “serviceB”
        Object originalValue = pv.getValue();// RuntimeBeanNameReference

        Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);// “serviceB”
        Object convertedValue = resolvedValue;// “serviceB”
    
        // 如果该属性有对应的 set 方法并且不是嵌套属性,接下来可以进行类型转换
        boolean convertible = bw.isWritableProperty(propertyName) &&
            !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
        if (convertible) {// true
            // 使用 PropertyEditor 或 ConversionService 进行类型转换
            convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
        }
        // ...
    }
    // ...
}

spring bean 源码如下:

public class MyServiceA {

    private String nameA;

    private MyServiceB serviceB;

    public void setNameA(String nameA) {
        this.nameA = nameA;
    }

    public void setServiceB(MyServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

public class MyServiceB {

    private String nameB;

    // 必须编写属性对应的 setter 方法,否则在属性注入时会抛出如下异常
    // org.springframework.beans.NotWritablePropertyException:
    // Invalid property 'nameB' of bean class [org.example.ioc.MyServiceB]:
    // Bean property 'nameB' is not writable or has an invalid setter method.
    // Does the parameter type of the setter match the return type of the getter?
    public void setNameB(String nameB) {
        this.nameB = nameB;
    }
}

spring-beans.xml 配置文件如下:


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="serviceA" class="org.example.ioc.MyServiceA">
        <property name="nameA">
            <value type="java.lang.String">
                Smile
            value>
        property>
        <property name="serviceB">
            <idref bean="serviceB"/>
        property>
    bean>

    <bean id="serviceB" class="org.example.ioc.MyServiceB">
        <property name="nameB">
            <value type="java.lang.String">
                Silence
            value>
        property>
    bean>
beans>

你可能感兴趣的:(spring,spring,ioc,类型转换异常,属性不可写异常)