1

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!

jhuether
  • 31
  • 3

1 Answers1

1

When you are instantiating the CompanyWidgetClient directly:

new CompanyWidgetClient(...)

you are not giving the spring DI container a chance to inject an instance of HeartbeatService - so its null.

When getting an instance of CompanyWidgetClient - retrieve the instance from Spring Applicaiton Context (via getBean() or similar) - so the HeartbeatService will have been Autowired.

Adam F
  • 11
  • 2
  • Thank you for your answer, this may well be the case but I'm not entirely convinced. Why would the bean be available on a per request basis in the JSP and not available during the same in a service class? – jhuether Apr 07 '14 at 01:07