Question

I'm a beginner with spring and I am having problem with basic context init and I can't find any easy tutorial. So what I want to do is basic dependency injection and I have seen I only have to mark classes as @Componant or @Service and inject them directly within target fiels with @Autowired. For this I need to set properly my spring context (I'll need to build a web service + use JPA so I want to build a webapp)

I'm using JDK 1.8, maven 3.2.1

I want to do a basic dependency injection. => I want to inject a storeImpl instance there but this lead to a null pointer exception => this work perfectly without injection ( private Store storeImpl = new storeImpl(); )

package com.mycompany.app.controller;

@Controller
public class Controller
{
    @Autowired
    private Store storeImpl;

    public void use()
    {
        storeImpl.get();
    }
}


package com.mycompany.app.store;

public interface Store {
    boolean get();

}


package com.mycompany.app.store;

@Component
public class StoreImpl implements Store {
    @Override
    public boolean get()
    {
        return true;
    }
}

=> my main (I test my app with this for now):

public class App
{
    public static void main(String[] args)
    {
        Controller controller = new Controller();
        controller.use();
    }
}

=> my pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>my-app</name>
  <url>http://maven.apache.org</url>

    <properties>
        <spring.version>4.0.4.RELEASE</spring.version>
    </properties>

  <dependencies>
      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
      </dependency>

      <dependency>
          <groupId>org.jsoup</groupId>
          <artifactId>jsoup</artifactId>
          <version>1.7.1</version>
      </dependency>

      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.12.6</version>
          <scope>provided</scope>
      </dependency>




      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>${spring.version}</version>
      </dependency>

      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring.version}</version>
      </dependency>

      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context-support</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>${spring.version}</version>
      </dependency>


      <dependency>
          <groupId>org.springframework.data</groupId>
          <artifactId>spring-data-jpa</artifactId>
          <version>1.5.2.RELEASE</version>
      </dependency>


      <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-core</artifactId>
          <version>4.3.5.Final</version>
      </dependency>

      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.0.1</version>
          <scope>provided</scope>
      </dependency>
  </dependencies>

  <build>
    <plugins>
        <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
      </plugin>
    </plugins>
    </build>
</project>

=> my web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    <display-name>Archetype Created Web Application</display-name>

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/META-INF/spring-context.xml</param-value>

    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app>

=> my spring-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: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/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--<context:component-scan base-package="com.mycompany.app"/>-->
    <context:component-scan base-package="com.mycompany.app">
       <!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />-->
    </context:component-scan>

</beans>

=> my project architecture


my-app
  src
    main
      java
        com.mycompagny.app
          controller
            Controller.java
          store
            Store.java
            StoreImpl.java

          app.java

       ressources
         META-INF
           spring-context.xml

       webapp
         WEB-INF
           web.xml


  test
   java

pom.xml

=> stacktrace of main()

Exception in thread "main" java.lang.NullPointerException
    at com.mycompany.app.controller.Controller.run(Controller.java:25)
    at com.mycompany.app.App.main(App.java:19)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

So my problem is my injected field (storeImpl) is null. And I think I miss something with context init ? Thanks again for your help and yourr grats answer

Was it helpful?

Solution

You have a couple of problems (the following are apparent from your post).

  1. Mixing jars of different versions of Spring
  2. Wrong location of annotations
  3. Duplication in your applicationcontext.
  4. Using versioned XSD files.
  5. Conflicting versioning in web.xml

1. Mixing Jars of different versions of Spring

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.0.3.RELEASE</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.0.4.RELEASE</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>4.0.3.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.0.1.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.0.1.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>3.0.5.RELEASE</version>
  </dependency>

Your pom is littered with jars from different spring versions (3.0.5, 4.0.1, 4.0.3 and 4.0.3). If you want trouble then that is the way to go. Always stick to a single version of a framework and don't mix jars from different versions. This isn't only for Spring but goes for every (multi jar) framework out-there.

Use the power of maven to help you, specify a property to hold the version of Spring you want to use and use that property.

<properties>
    <spring.version>4.0.4.RELEASE</spring.version>
</properties>
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${spring.version}</version>
  </dependency>

You might need to add a couple more depending on which dependencies Spring Data JPA is pulling in, if that has different versions.

2. Wrong location of annotations

@Service
public interface Store {
    boolean get();
}

Annotations aren't inherited from interfaces so putting the annotation on the interface is pretty much useless. Spring has some hacks in place for specific annotations like @Transactional but not for this. Move the annotation to the concrete implementation and don't put it on the interface.

@Service
public class Controller {
    @Autowired
    private Store storeImpl;

    public void use() {
       storeImpl.get();
    }
}

I don't see anything here no @Controller or what so ever also no @RequestMapping so I'm not sure how you think that Spring detects and handles this class.

3. Duplication in your applicationcontext.

<context:annotation-config /> remove it from your context as that is already implied by the use of <context:component-scan />.

<mvc:annotation-driven /> should be only in the xml file loaded by the DispatcherServlet in your case (if you have posted actual code) that should be the dispatcher-servlet.xml.

You have the same <context:component-scan .. /> element in both your xml files, this will ead to bean duplication. The files loaded by the ContextLoaderListener should load anything but @Controllers and the DispatcherServlet should load only @Controllers and ignore anything else. To accomplish that use include/exclude filters when component scanning.

Use this for the ContextLoaderListener.

<context:component-scan base-package="com.mycompany.app">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype. Controller" />
<context:component-scan>

Use this for the DispatcherServlet.

<context:component-scan base-package="com.mycompany.app" use-default-filters="false >
    <context:include-filter type="annotation" expression="org.springframework.stereotype. Controller" />
<context:component-scan>

Also don't import the configuration of the DispatcherServlet into the ContextLoaderListener as this will again lead to bean duplication.

4. Using versioned XSD files.

xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-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/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

Your schema locations use versioned XSD files, it is recommended to use versionless xsd files. This will ensure that the xsd version belonging to your current spring version will be loaded.

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
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

5. Conflicting versioning in web.xml

<!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app id="WebApp_ID" version="2.4"
     xmlns="http://java.sun.com/xml/ns/j2ee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

What is it you want version 2.3 of 2.4? You including servlet-api 2.5 in your pom and I would expect that you want version 3.0. Change your header (and maven dependency) accordingly.

Change your web.xml header to the following.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     version="3.0">

Update your pom.xml to include the servlet 3.0 spec.

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.0.1</version>
    <scope>provided</scope>
</dependency>

OTHER TIPS

You have to define the bean in your Spring xml

<bean id="storeImpl" class="com.mycompany.app.store.StoreImpl">
       <!-- collaborators and configuration for this bean go here -->
</bean>

So, the @Autowired bean will be injected by Spring framework

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top