This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 3 years ago.
[RESOLVED] In this case the problem was that I haven't included into the build path some useful libs such as "jersey-spring4-2.28.jar" and "spring-bridge-2.5.0.jar". These libraries allow integration between Jersey and Spring.
I'm working on a web-app on Tomcat (9.0.16), which exposes useful REST services for data communication (services made with the help of Jersey 2.28). In the class that manages these services I used Spring (v5.1.5) to inject the dependencies as follows:
package it.learning.rest;
#Component
#Path("/")
public class GameClientCommsRestService {
#Autowired
#Qualifier("CommunicationBusiness")
private GameClientCommunication comm;
#GET
#Path("/test/check/bean")
#Produces(MediaType.TEXT_PLAIN)
public Response testCheckCommsBean() {
StringBuilder sb = new StringBuilder();
if (comm == null) {
sb.append("GameClientCommunication instance is NULL!!");
} else {
sb.append("GameClientCommunication instance is NOT NULL ---> SUCCESSFULLY instantiated");
}
return getRestResponse(sb.toString());
}
}
The class for which the dependency is injected is defined as follows:
package it.learning.business.impl;
public class GameClientCommunicationBusiness implements GameClientCommunication {
#Override
public String processesMessage(String request, String remoteIpAddress) {
// Processing input...
}
}
The XML configuration file is the following:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="it.learning" />
<context:annotation-config />
<bean id="applicationContextProvider" class="it.learning.utils.spring.ApplicationContextProvider">
</bean>
<bean id="CommunicationBusiness" class="it.learning.business.impl.GameClientCommunicationBusiness">
</bean>
</beans>
On application start-up, neither Tomcat nor the log service records any problems, but if I call
testCheckCommsBean()
it returns
"GameClientCommunication instance is NULL!!"
If instead I use the ApplicationContext object to get the instance associated with "CommunicationBusiness", I get a properly functioning object.
The log shows that both the annotated beans and those declared in the XML file were successfully created and inserted into the Spring container:
2019-03-19 13:06:00,343 DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 7 bean definitions from ServletContext resource [/WEB-INF/spring/appContext.xml]
2019-03-19 13:06:00,362 DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 4 bean definitions from ServletContext resource [/WEB-INF/spring/appContextBeans.xml]
2019-03-19 13:06:00,438 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
2019-03-19 13:06:00,526 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
2019-03-19 13:06:00,530 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
2019-03-19 13:06:00,532 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
2019-03-19 13:06:00,533 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
2019-03-19 13:06:00,537 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalPersistenceAnnotationProcessor'
2019-03-19 13:06:00,549 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'gameClientCommsRestService'
2019-03-19 13:06:00,579 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'CommunicationBusiness'
2019-03-19 13:06:00,582 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'applicationContextProvider'
Differently from what reported in
Why is my Spring #Autowired field null?
I never instantiated a "GameClientCommunication" object using the "new" keyword, therefore I really don't understand why the field annotated with #Autowired is null.
Thanks for your support!
You can try #component annotation on top of GameClientCommunicationBusiness class.
The problem is you didn't wire the implementation class.
I have an entity:
public class Auditorium {
private Integer id;
private String name;
private Integer numberOfSeats;
private List<String> vipSeats;
public Auditorium(String name, Integer numberOfSeats, List<String> vipSeats) {
this.name = name;
this.numberOfSeats = numberOfSeats;
this.vipSeats = vipSeats;
}
and I want to create Auditorium instance from property file, like:
auditorium1.name=yellow hall
auditorium1.number-of-seats=150
auditorium1.vip-seats=1,2,3,4,5,6,7,8,9
I have few different files and I want to create different Auditorium beans.
Here is snippet from spring.xml:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:auditorium1.properties</value>
<value>classpath:auditorium2.properties</value>
<value>classpath:auditorium3.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true"/>
<property name="systemPropertiesMode">
<util:constant
static-field="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
</property>
</bean>
<util:list id="auditorium1" value-type="java.lang.String">
<value></value>
</util:list>
<util:list>
<bean class="net.lelyak.edu.entity.Auditorium"
p:name="${auditorium1.name}" p:numberOfSeats="${auditorium1.number-of-seats}" p:vipSeats="${auditorium1.vip-seats}"/>
</util:list>
But Iam getting an error:
Because No matching constructor found.
And much better will have List<Integer> vipSeats. Is it possible at this situation?
How to solve this trouble?
There are 2 aspects here to be covered, so let's take them one at a time:
1)IJ (short for IntelliJ Idea) is suggesting that according to your bean declaration, Spring will be trying to invoke a no-arg constructor, which clearly does not exist since you've defined public Auditorium(String name, Integer numberOfSeats, List<String> vipSeats).
Thus you can configure it to call the above mentioned constructor passing the correct arguments, as per the spring docs:
<bean class="com.example.Auditorium">
<constructor-arg name="name" value="${auditorium1.name}"/>
<constructor-arg name="numberOfSeats" value="${auditorium1.number-of-seats}"/>
<constructor-arg name="vipSeats" value="${auditorium1.vip-seats}"/>
</bean>
Apart from this, no special handling is required for Spring to inject your list, as you can see in the log snippet below, outputted by a simple toString() IJ auto-generated method:
16:13:56.569 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.Auditorium#0'
16:13:56.601 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}
2) I see you're trying to use the p-namespace to pass arguments to your constructor, however that's used to set properties/attribute after bean instantiation. You can use the c-namespace to achieve the same effect as using the <constructor-arg> tag and be less verbose (please note that as per the spring docs, p & c namespaces the are not defined in an XSD file and exist only in the core of Spring):
<beans ...
xmlns:c="http://www.springframework.org/schema/c"
...>
<bean id="myAuditorium" class="com.example.Auditorium" c:name="${auditorium1.name}" c:numberOfSeats="${auditorium1.number-of-seats}" c:vipSeats="${auditorium1.vip-seats}"/>
And again the log snippet, generated for both the definitions this time:
16:26:52.258 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.Auditorium#0'
16:26:52.287 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}
...
16:26:52.287 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.Auditorium#1'
16:26:52.288 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}
Note: Depending on the Spring version that you are using & your needs, it may be worth also checking annotation-based configs. It may be a personal preference, but I find them cleaner and easier to maintain, and IJ has excellent Spring support for both types of config.
Special request update: Brief annotation introduction
First of all it depends on your project's setup, whether you use basic Spring Core or Spring Boot as well, etc. For this introduction: I'll just start from where you are at this point:
Enable component scanning so Spring can discover and create your components, services, etc
<?xml version="1.0" encoding="UTF-8"?>
<beans ...
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="...
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example" />
Then change our class. If you don't need to do anything else in your constructor then we can simply remove it and annotate the fields. When annotating fields please take into consideration that Spring will be able to populate them only after instantiating the beans, hence using then in a constructor will most likly result in a NPE. In such cases you can use #PostConstruct
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component
public class Auditorium {
private static final Logger log = LoggerFactory.getLogger(Auditorium.class);
private Integer id;
#Value("${auditorium1.name}")
private String name;
#Value("${auditorium1.number-of-seats}")
private Integer numberOfSeats;
#Value("${auditorium1.vip-seats}")
private List<String> vipSeats;
#PostConstruct
private void doAfterConstruction() {
log.debug(this.toString());
}
#Override
public String toString() {
return "Auditorium{" +
"id=" + id +
", name='" + name + '\'' +
", numberOfSeats=" + numberOfSeats +
", vipSeats=" + vipSeats +
'}';
}
}
As you'll see in the log, Spring will instantiate the bean, then inject the values for its fields and eventually the post-processors will call the #PostConstruct annotated method:
12:20:34.037 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'auditorium'
12:20:34.038 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'auditorium'
12:20:34.045 [main] DEBUG o.s.c.a.CommonAnnotationBeanPostProcessor - Found init method on class [com.example.Auditorium]: private void com.example.Auditorium.doAfterConstruction()
12:20:34.045 [main] DEBUG o.s.c.a.CommonAnnotationBeanPostProcessor - Registered init method on class [com.example.Auditorium]: org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement#1ec4fbf0
12:20:34.060 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Registered injected element on class [com.example.Auditorium]: AutowiredFieldElement for private java.lang.String com.example.Auditorium.name
12:20:34.060 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Registered injected element on class [com.example.Auditorium]: AutowiredFieldElement for private java.lang.Integer com.example.Auditorium.numberOfSeats
12:20:34.060 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Registered injected element on class [com.example.Auditorium]: AutowiredFieldElement for private java.util.List com.example.Auditorium.vipSeats
12:20:34.060 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'auditorium' to allow for resolving potential circular references
12:20:34.062 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Processing injected element of bean 'auditorium': AutowiredFieldElement for private java.lang.String com.example.Auditorium.name
12:20:34.067 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Processing injected element of bean 'auditorium': AutowiredFieldElement for private java.lang.Integer com.example.Auditorium.numberOfSeats
12:20:34.072 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Processing injected element of bean 'auditorium': AutowiredFieldElement for private java.util.List com.example.Auditorium.vipSeats
12:20:34.084 [main] DEBUG o.s.c.a.CommonAnnotationBeanPostProcessor - Invoking init method on bean 'auditorium': private void com.example.Auditorium.doAfterConstruction()
12:20:34.085 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}
12:20:34.094 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'auditorium'
Or if you'd like to keep your constructor, we'll just mark it as #Autowired and annotate the parameters as well:
#Component
public class Auditorium {
private static final Logger log = LoggerFactory.getLogger(Auditorium.class);
private Integer id;
private String name;
private Integer numberOfSeats;
private List<String> vipSeats;
#Autowired
public Auditorium(#Value("${auditorium1.name}") String name,
#Value("${auditorium1.number-of-seats}") Integer numberOfSeats,
#Value("${auditorium1.vip-seats}") List<String> vipSeats) {
this.name = name;
this.numberOfSeats = numberOfSeats;
this.vipSeats = vipSeats;
log.debug(this.toString());
}
}
And the log, which is simpler this time
12:29:09.492 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'auditorium'
12:29:09.492 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'auditorium'
12:29:09.525 [main] DEBUG com.example.Auditorium - Auditorium{id=null, name='yellow hall', numberOfSeats=150, vipSeats=[1,2,3,4,5,6,7,8,9]}
12:29:09.526 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'auditorium' to allow for resolving potential circular references
12:29:09.548 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'auditorium'
I use spring-boot-starter-parent as parent and add spring-boot-starter-web as denpendency.
By add the #SpringBootApplication annotation, it works.
But DispatcherServlet need initialization
Initializing servlet 'dispatcherServlet'
FrameworkServlet 'dispatcherServlet': initialization started
Using MultipartResolver [org.springframework.web.multipart.support.StandardServletMultipartResolver#745f40ac]
Unable to locate LocaleResolver with name 'localeResolver': using default [org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver#219fc57d]
Unable to locate ThemeResolver with name 'themeResolver': using default [org.springframework.web.servlet.theme.FixedThemeResolver#7b4bd6bd]
Unable to locate RequestToViewNameTranslator with name 'viewNameTranslator': using default [org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator#71ccfa36]
Unable to locate FlashMapManager with name 'flashMapManager': using default [org.springframework.web.servlet.support.SessionFlashMapManager#43f3e6a9]
Published WebApplicationContext of servlet 'dispatcherServlet' as ServletContext attribute with name [org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcherServlet]
FrameworkServlet 'dispatcherServlet': initialization completed in 37 ms
I hope I can set it's loadonstartup by 1, and don't want to use this
annoying BeanNameUrlHandlerMapping, it rejected everything and I'm not going to use it.
o.s.w.s.h.BeanNameUrlHandlerMapping : Rejected bean name 'contextAttributes': no URL paths identified
I read the java-doc about BeanNameUrlHandlerMapping:
This is the default implementation used by the org.springframework.web.servlet.DispatcherServlet, along with org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping (on Java 5 and higher). Alternatively, SimpleUrlHandlerMapping allows for customizing a handler mapping declaratively.
That's all, I just want to change these two thing:
setLoadonStartup
don't use BeanNameUrlHandlerMapping
Beside that, other thing spring boot configure for me is very great, and I want to keep it.
Thank you for any help you can provide.
New reply to old post. Seems this is easier to do with more recent versions of Spring Boot. Just adding the property spring.mvc.servlet.load-on-startup=1 works for me.
I encountered the same problem with loadOnStartup. I solved it by using a custom BeanFactoryPostProcessor to modify the BeanDefinition of the ServletRegistrationBean that Spring Boot creates for registering the DispatcherServlet.
The following code will set loadOnStartup for the DispatcherServlet in a Spring Boot app, when used within an #Configuration class:
#Bean
public static BeanFactoryPostProcessor beanFactoryPostProcessor() {
return new BeanFactoryPostProcessor() {
#Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition bean = beanFactory.getBeanDefinition(
DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
bean.getPropertyValues().add("loadOnStartup", 1);
}
};
}
BTW, the BeanNameUrlHandlerMapping is harmless here.
It is used to map a Spring Bean to a URL - for example it might be used to support Spring HttpInvoker remoting.
The rejection lines in the log output simply mean that it doesn't recognize any of the Spring beans as beans that require a URL mapping. Annoying messages but harmless. You could always set the logging level for this bean or its package to INFO or above to remove the message. In Spring Boot's application.properties put
logging.level.org.springframework.web.servlet.handler=INFO
In my application, I have the following startup bean:
#Startup
#Singleton
#DependsOn("RecordAcumulator")
public class StartupBean {
private static final Logger logger = Logger.getLogger(StartupBean.class);
#Inject
RecordAcumulator recordAcumulator;
/**
* Initializes the EJB system on the post construct event
*/
#PostConstruct
public void init() {
The record accumulator is an EJB that accesses the database. The startup is intended to preload database tables into the cache.
#Stateless
public class RecordAcumulator {
When this launches, I get
Caused by: com.ibm.ws.exception.RuntimeWarning: CNTR0200E: The StartupBean singleton session bean in the EJB.jar module depends on the RecordAcumulator enterprise bean in the EJB.jar, but the target is not a singleton session bean.
I have tried many variations of this and I can't seem to get the thing to inject. My log file indicates that the RecordAcumulator EJB was bound prior to the startup bean being loaded, so I can't figure out why I can't inject the EJB into my startup.
If I remove the #DependsOn I get this:
Caused by: javax.ejb.NoSuchEJBException: An error occurred during initialization of singleton session bean bla#EJB.jar#StartupBean, resulting in the discarding of the singleton instance.; nested exception is: javax.ejb.EJBException: The #Inject java.lang.reflect.Field.recordAcumulator reference of type com.foo.bar.accum.RecordAcumulator for the StartupBean component in the EJB.jar module of the bla application cannot be resolved.
Any ideas how to pull this off?
EDIT----------
I found this link:
Controlling CDI Startup inside EJB 3.1
But the issue with that is i'm using WAS 8.5.5.0, That issue was supposed to be resolved in 8.5.0.2
From what I can see:
Remove the #DependsOn
Make your EJB #Singleton
There can be complexities with singleton EJBs, as all the traffic going through your application will go through that one instance. In your case that may not be an issue.
A little background:
I am using Spring and Camel together with Java 8.
public static void main(String[] args) throws Exception {
AbstractApplicationContext _context = new ClassPathXmlApplicationContext(
"application-context.xml");
_context.registerShutdownHook();
MessageRoute _messageRoute = (MessageRoute) _context.getBean("messageRoute");
SpringCamelContext _camelContext = _context.getBean(SpringCamelContext.class);
_messageRoute.setContext(_camelContext);
_camelContext.addRoutes(_messageRoute);
Object lock = new Object();
synchronized (lock) {
lock.wait();
}
((ClassPathXmlApplicationContext) _context).close();
}
[main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties]
[main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment]
[main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null]
[main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'messageRoute'
[main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.apache.camel.spring.SpringCamelContext#0'
[main] DEBUG o.a.camel.spring.SpringCamelContext - Adding routes from builder: Routes: []
[main] DEBUG o.a.camel.spring.SpringCamelContext - Adding routes from builder: Routes: []
I have tried using DefaultCamelContext as well but the problem is it's just not adding the route class. The MessageRoute class is a simple class extending the RouteBuilder. My observation tells me the line containing: _context.getBean("messageRoute") might have an issue because it's not really passing any route to the RouteBuilder reference.
Never mind I fixed it! Camel wasn't adding an instance of the Route class sitting inside the spring container because in the configure method, one needs an actual path saying from().to().
Pretty funny though that it wasn't throwing any error and even refused the add the ApplicationContext bean to routes.
To add Java routes in XML, just use <routeBuilder ref="myBeanName"/> inside <camelContext>
See the Camel documentation: http://camel.apache.org/spring.html at the section Using Java Code