Affects: 4.3.30, 5.2.13, 5.3.4

I tried all three, same result.

I have a Spring Web Application. The root context is loaded with:

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/*.xml</param-value>
    </context-param>

and files are:

/webapp/src/main/webapp/WEB-INF/spring
/webapp/src/main/webapp/WEB-INF/spring/jaxrs
/webapp/src/main/webapp/WEB-INF/spring/jaxws
/webapp/src/main/webapp/WEB-INF/spring/config-properties.xml
/webapp/src/main/webapp/WEB-INF/spring/root-context.xml
/webapp/src/main/webapp/WEB-INF/spring/x2tc-proxy-components.xml

Note JAX-RS and JAX-WS have their subcontexts. They do not matter now here.

config-properties.xml is merely:

    <beans:bean id="config" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <beans:property name="locations">
            <beans:array>
                <beans:value>classpath:x2tc-proxy.properties</beans:value>
                <beans:value>classpath:x2tc-proxy-override.properties</beans:value>
                <beans:value>file:${catalina.base}/conf/x2tc-proxy/tc-system.properties</beans:value>
                <beans:value>file:${catalina.base}/conf/x2tc-proxy/credentials.properties</beans:value>
            </beans:array>
        </beans:property>
        <beans:property name="ignoreResourceNotFound" value="true" />
    </beans:bean>

x2tc-proxy.properties contains:

...
teamcenter.auth.credentialsFactory.plain=....PlainCredentialsFactoryBean
teamcenter.auth.credentialsFactory.offlineSso=....OfflineSsoCredentialsFactoryBean
teamcenter.auth.credentialsFactory.onlineSso=...OnlineSsoCredentialsFactoryBean

All of these factory beans have everything autowired and return an object of interface type Credentials. Now credentials.properties contains specific config for a factory type, depending on a deployment. The properties file contains:

teamcenter.auth.credentialsFactory=onlineSso
# followed by all properties the `OnlineSsoCredentialsFactoryBean` requires.

x2tc-proxy-components.xml contains:

    <beans:bean id="credentialsFactory"
        class="${teamcenter.auth.credentialsFactory.${teamcenter.auth.credentialsFactory}}" />

I'd like to configure the concrete factory bean class name in the properties file w/o fiddling the beans definition. At startup I see the following:

22:30:53.037 [localhost-startStop-1] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Ignoring bean class loading failure for bean 'credentialsFactory'
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [${teamcenter.auth.credentialsFactory.${teamcenter.auth.credentialsFactory}}] for bean with name 'credentialsFactory' defined in ServletContext resource [/WEB-INF/spring/x2tc-proxy-components.xml]; nested exception is java.lang.ClassNotFoundException: ${teamcenter.auth.credentialsFactory.${teamcenter.auth.credentialsFactory}}
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1397)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:638)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:607)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1496)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:425)

but as it seems the factory bean is still wired and the objects from the factory are perfectly.

It is not clear whether this is intentional or bug. StackOverflow contains a bunch of questions where people try to provide a class name from a property.

Comment From: sbrannen

What happens if you add the following to config-properties.xml?

<context:property-placeholder properties-ref="config" />

Comment From: michael-o

What happens if you add the following to config-properties.xml?

<context:property-placeholder properties-ref="config" />

I have this actually in my root-context.xml permanently and added in x2tc-proxy-components.xml, but never added to config-properties.xml. I assumed it to be enough to declare once because the context is constituted of those three files.

I will try this tomorrow and let you know.

Comment From: michael-o

I have just added <context:property-placeholder ... /> right after <beans:bean id="config" /> in config-properties.xml and not avail. I still see the exception. Looking at the debug output of Spring shows me that the config bean as well es the placeholder support is initiated after the credentialsFactory.

Comment From: sbrannen

22:30:53.037 [localhost-startStop-1] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Ignoring bean class loading failure for bean 'credentialsFactory' org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [${teamcenter.auth.credentialsFactory.${teamcenter.auth.credentialsFactory}}] for bean with name 'credentialsFactory' defined in ServletContext resource [/WEB-INF/spring/x2tc-proxy-components.xml]; nested exception is java.lang.ClassNotFoundException: ${teamcenter.auth.credentialsFactory.${teamcenter.auth.credentialsFactory}} at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1397) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:638) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:607) at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1496) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:425)

but as it seems the factory bean is still wired and the objects from the factory are perfectly.

Although you have not included the entire stack trace, based on the exception message, it appears that this comes from an early attempt to find all beans for a given type:

https://github.com/spring-projects/spring-framework/blob/4af7a6863b8c07e936cbf3db59dcffe4dbea4294/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java#L596-L607

Note this is a TRACE message in master (DEBUG in the version you used) stating that Spring is Ignoring bean class loading failure for bean 'credentialsFactory' at this point, but it does not mean that the bean class will not be properly resolved later once the placeholders have been resolved.

In light of that, and since your application seems to work without any issues, I am closing this issue.

Comment From: michael-o

Alright, I will take this as works as desgined and my usecase is generally supported. Is my conclusion correct?

Comment From: sbrannen

Yes, you have concluded correctly.

In general, if Spring logs something at DEBUG or TRACE level and your app still works fine, then the log messages are only there for informational purposes.

My tip: filter logging at INFO or WARN and only revert to DEBUG or TRACE if you run into issues.

Comment From: michael-o

Thanks a million. I can safely put this in production now.