4

I am attempting to autowire a WebApplicationContext into a class ImageCreatorUtil that I have created, within my Spring MVC project. Upon execution of a method in the class, which utilizes the application context, I always receive an NPE. It is important to note that this method is called by an ApplicationListener defined in another config file. I am not sure why the autowiring is not working. Can anyone provide any suggestions?

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        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-3.1.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing 
        infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="org.springframework.data.web.PageableArgumentResolver" />
        </mvc:argument-resolvers>
    </mvc:annotation-driven>

    <!-- Intercept request to blog to add paging params -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/blog/**"/>
            <bean class="org.tothought.spring.interceptors.PageableRequestHandlerInterceptor" />
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="org.tothought.spring.interceptors.LookupHandlerInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
    <mvc:resources location="/resources/" mapping="/resources/**" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="5000000"/>
    </bean>

    <context:component-scan base-package="org.tothought.spring.**" />

</beans>

ImageCreatorUtil.java

@Component
public class ImageCreatorUtil {

    static Logger logger = LoggerFactory.getLogger(ImageCreatorUtil.class);
    static final String IMAGE_PATH_FRAGMENT = "/resources/images/resume/skills/uploaded-icons/";

    @Autowired
    private WebApplicationContext context;

    /**
     * Creates the provided file in the resources directory for access by the
     * web application.
     * 
     * @param appContext
     * @param image
     */
    public void storeImage(Image image) {
        if (image != null) {
            String realPath = ((WebApplicationContext)context).getServletContext().getRealPath("/");
            File tmpFile = new File(realPath + IMAGE_PATH_FRAGMENT + image.getName());

            try {
                logger.info("Saving image to :" + tmpFile.getAbsolutePath());
                FileUtils.writeByteArrayToFile(tmpFile, image.getFile());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

application-context.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:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <context:property-placeholder location="classpath:META-INF/db/db.properties" />
    <context:annotation-config/>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/to_thought" />
        <property name="username" value="${db.user}" />
        <property name="password" value="${db.password}" />
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="persistenceUnitName" value="toThought" />
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <jpa:repositories base-package="org.tothought.repositories"/>

    <!-- Application Listeners -->
    <bean id="lookupLoader" class="org.tothought.spring.listeners.LookupLoaderApplicationListener" /> 
    <bean id="imageLoader" class="org.tothought.spring.listeners.ImageLoaderApplicationListener" /> 
</beans>

Console Error

SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.NullPointerException
    at org.tothought.spring.utilities.ImageCreatorUtil.storeImage(ImageCreatorUtil.java:34)
    at org.tothought.spring.listeners.ImageLoaderApplicationListener.onApplicationEvent(ImageLoaderApplicationListener.java:29)
    at org.tothought.spring.listeners.ImageLoaderApplicationListener.onApplicationEvent(ImageLoaderApplicationListener.java:1)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:97)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:324)
Kevin Bowersox
  • 93,289
  • 19
  • 159
  • 189
  • @Amber thanks, any suggestions? – Kevin Bowersox Nov 21 '12 at 11:54
  • I have posted an answer for you. Its like "autowiring" works when Spring calls a method and not when you are explicitly making a call to some method using its object(which of-course is created by you and not by Spring via Autowiring). – Amber Nov 21 '12 at 11:59
  • I have some doubt..which one you are autowiring actually. Is it applicationcontext.xml or spring.xml...sorry i am learner – Pratap M Nov 21 '12 at 13:53
  • I am using Spring-MVC, which specifies a context for the dispatcher servlet and the root application. That is why you see two config files. – Kevin Bowersox Nov 21 '12 at 13:56
  • I understood it..you are autowiring the servlet-context.xml and as ImageUtilCreate class is created by you(using new)..so spring does not able to do chain autowiring.. – Pratap M Nov 21 '12 at 14:11
  • Exactly. It was not my brightest moment. – Kevin Bowersox Nov 21 '12 at 14:30

1 Answers1

2

I have tried your code. The Autowiring for context works fines for context in any controller class but its not working when i am calling a method using object of a class. So if you do something like :

Your Controller :

@Autowired
private ImageCreatorUtil icu;

public String controllerMethod(....) {
    icu.storeImage();
}

Your application-context.xml :

<bean id="icu" class="****.controller.ImageCreatorUtil"/>

Then the Autowiring would work fine. I would try and update you the reason for such a behavior.

Amber
  • 1,229
  • 9
  • 29
  • I figured out what the issue was your answer helped solve the problem. It doesn't help when you create a new instance of `ImageCreatorUtil` in the `ApplicationListener`. WOW! I need to autowire the `ImageCreatorUtil` in the `ApplicationListener` – Kevin Bowersox Nov 21 '12 at 12:06
  • 3
    I could not find any document stating the fact but the principle seems that when using "autowired" for any property, the responsibility for Object creation and hence providing all required resources to that object via "autowiring" lies with Spring. But when we create a new Object all by ourselves using "new" keyword the Spring Container has no control over object creation and hence the "autowired" properties are "null". – Amber Nov 21 '12 at 12:09
  • well stated, I kind of missed the point of dependency injection on this one. Thank you for your time. – Kevin Bowersox Nov 21 '12 at 12:10
  • Please refer : http://stackoverflow.com/questions/10997092/autowiring-in-spring-bean-component-created-with-new-keyword It provides the answer. – Amber Nov 21 '12 at 12:11