I'm having trouble autowiring a Spring bean in my application. This is something I've done before in other applications with success, but for some reason I'm getting stumped. I've googled around, and have found many folks having the same troubles, and the warnings that go along with using the getApplicationContext() approach but no answers that helped me. I understand the warnings and still have a case where I want to do it this way, then maybe I'll get it working using AspectJ and compile time weaving.
Here is my setup:
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<context:property-placeholder location="classpath:widgetClient.properties"/>
<context:component-scan base-package="com.myCompany.widget.domain" />
<context:component-scan base-package="com.myCompany.widget.services" />
<context:annotation-config />
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
<bean id="heartbeat" class="com.company.widget.domain.CheckWidgetServerHeartbeat" destroy-method="destroy">
<constructor-arg type="java.lang.Integer" name="interval" value="${heartbeat.interval}"/>
<constructor-arg type="java.lang.Integer" name="timeout" value="${heartbeat.timeout}"/>
<constructor-arg type="java.lang.Integer" name="unhealthyThreshold" value="${unhealthy.threshold}"/>
<constructor-arg type="java.lang.Integer" name="healthyThreshold" value="${healthy.threshold}"/>
<constructor-arg type="java.lang.Integer" name="backupVerifyTime" value="${backup.verify.time}"/>
<constructor-arg type="java.lang.String" name="apiServerUrl" value="${api.server.url}" />
</bean>
</beans>
BaseService.java
package com.company.widget.services;
import com.company.widget.domain.CheckWidgetServerHeartbeat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class BaseService{
@Autowired
private ApplicationContext appContext;
public BaseService(){}
public CheckWidgetServerHeartbeat getHeartbeat(){
return (CheckWidgetServerHeartbeat) appContext.getBean("heartbeat");
}
}
Heartbeatservice.java
package com.company.widget.services;
import org.springframework.stereotype.Service;
import org.apache.log4j.Logger;
@Service
public class HeartbeatService extends BaseService{
private static final Logger logger = Logger.getLogger(HeartbeatService.class);
public HeartbeatService(){}
public Boolean isHealthy(){
return getHeartbeat().check();
}
}
CompanyWidgetClient.java
package com.company.widget.domain;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.Locale;
import java.util.ResourceBundle;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.*;
import com.company.widget.services.HeartbeatService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class CompanyWidgetClient{
@Autowired
private HeartbeatService heartbeatService;
public CompanyWidgetClient(String settingsXmlFilePath, HttpServletRequest request){
if(settingsXmlFilePath != null){
configuration = new CompanyWidgetConfiguration(settingsXmlFilePath, request);
}
if(request != null){
this.request = request;
}
//Use API server URL from settings file if it is present
if (configuration.getProperty("api_server_url") != null) {
this.apiServerUrl = configuration.getProperty("api_server_url");
log.debug("Set api_server_url to " + this.apiServerUrl + " which was found in settings.xml");
}
}
public CompanyWidgetClient(CompanyWidgetConfiguration configuration, HttpServletRequest request){
if(configuration != null){
this.configuration=configuration;
}
if(request != null){
this.request = request;
}
//Use API server URL from settings file if it is present
if (configuration.getProperty("api_server_url") != null) {
this.apiServerUrl = configuration.getProperty("api_server_url");
log.debug("Set api_server_url to " + this.apiServerUrl + " which was found in settings.xml");
}
}
public CompanyWidgetClient(){}
private CompanyWidgetResponse requestWidget(){
if(heartbeatService.isHealthy()){
do stuff...
}
index.jsp
<%@ page import="com.company.widget.domain.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
CompanyWidgetClient widgetClient = new CompanyWidgetClient("/WEB-INF/settings.xml", request);
String companyWidgetComponent = widgetClient.createWidget();
%>
...
HTML stuff
...
<div id="widget">
<%=companyWidgetComponent%>
</div>
...
The error:
500
org.apache.jasper.JasperException: An exception occurred processing JSP page /index.jsp at line 5
2: <%@ page contentType="text/html;charset=UTF-8" language="java" %> 3: <% 4: CompanyWidgetClient widgetClient = new CompanyWidgetClient("/WEB-INF/settings.xml", request); 5: String companyWidgetComponent = widgetClient.createWidget(); 6: %> 7: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 8: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:568)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:470)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
root cause
java.lang.NullPointerException
com.company.widget.domain.CompanyWidgetClient.requestWidget(CompanyWidgetClient.java:553)
com.company.widget.domain.CompanyWidgetClient.createWidget(CompanyWidgetClient.java:603)
org.apache.jsp.index_jsp._jspService(index_jsp.java:67)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
Observations:
I know I'm missing something as it required the default constructor to be present on the CompanyClient object, and it logs that it builds a CompanyClient object on deployment. I guess I'm not very clear on scope when it comes to Spring application context. My understanding was that a singleton bean should be available using the application context irrespective of the scope of the calling bean. Any and all help is very appreciated!