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.