1

This is not a duplicate of this question. So please don't close it for "is duplicate of" reasons..


I'm trying to autowire a bean into the java class. My problem is that playerDAO remains null and does not get initialized.

mvc-dispatcher-service.xml

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

    <context:component-scan base-package="ngdemo"/>

    <mvc:annotation-driven/>

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="mySessionFactory"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>    
</beans>

PlayerDAO.java

@Repository
@SuppressWarnings({"unchecked", "rawtypes"})
public class PlayerDAO {
    @Autowired
    private SessionFactory sessionFactory;

    @Transactional
    public Player getPlayerByUsername(String username) {
      //some code
    }
}

LoginRestService.java

@Path("/v1")
@Controller
public class LoginRestService {

    @Autowired
    private PlayerDAO playerDAO;

    @Path("/login")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Response authenticateUser(@FormParam("username") String username,
                                     @FormParam("password") String password, @Context UriInfo request) {
     playerDAO.getPlayerByUsername(username);
     //NPE, playerDAO here is null when I'm trying to access it
    }    
}

What am I missing?

Full code available here: https://github.com/Ferenus/hestalis

Community
  • 1
  • 1
Daniel Stradowski
  • 3,466
  • 1
  • 12
  • 21
  • http://stackoverflow.com/questions/12899372/spring-why-do-we-autowire-the-interface-and-not-the-implemented-class – duardito Jun 26 '16 at 17:16

5 Answers5

1

Are you sure that your Controller package name is "ngdemo" not "com.pack.ngdemo" ? Are you using database or not ? may be you are getting null value from your query can you please show me what query you are using inside getplayerbyusername() method.

try this

public TypedQuery<User> findUsersByNameEquals(String name) {
    if (name == null || name.length() == 0) { 
        throw new IllegalArgumentException("The name argument is required"); 
    }

    TypedQuery<User> q = entityManager.createQuery("SELECT o FROM User AS o WHERE o.username = :name", User.class);
    q.setParameter("name", name);

    return q;
}

or

public boolean loginWithUserPass(String username, String password){

    TypedQuery<User> q = entityManager.createQuery("SELECT o FROM User AS o WHERE o.username = :name and o.password = :pass", User.class);
    q.setParameter("name", username);
    q.setParameter("pass", password);

    List<User> results = q.getResultList();
    if (!results.isEmpty()) return true;

    else return false;
}

do not try exact same code cause i have used entity manager. try something similar. may be this would help.

nikesh adhikari
  • 113
  • 2
  • 11
  • PlayerDAO is in `package ngdemo.dao;`. I'm using database. playerDAO is null for sure, not the query from `getPlayerByUsername`. – Daniel Stradowski Jun 26 '16 at 13:46
  • if you will not insert any values in player DAO It will be null automatically. for example if you want Login functionality in your web app you need to select row where username eq entered username and password eq entered password or just count row where username and password eq entered username and entered password. – nikesh adhikari Jun 26 '16 at 13:58
  • and print your form parameters to make sure that they hold correct values – nikesh adhikari Jun 26 '16 at 14:01
  • I've edited the question to let you see where NPE is produced. Should I initialize productDAO in some different way, so it will not be null? – Daniel Stradowski Jun 26 '16 at 14:04
  • nope your function should initialize playerDao automatically – nikesh adhikari Jun 26 '16 at 14:13
1

I've checked your code and i got answer for your problem.

There is nothing wrong with your code.

But when you want to use both spring mvc and jersey restfull webservices you have to do something more than that you are doing here. Bcoz jersey is not aware of spring container and it's implementation. So, whenever you are requesting for a webservice jersey fullfills your request processing instead of the spring framework.

So, here the playerDao is not injected into the LoginRestService.java and hence it (playerDao) resolve to null.

So do the following steps,

Step-1:-- Add the below maven dependency to your pom.xml

    <dependency>
        <groupId>com.sun.jersey.contribs</groupId>
       <artifactId>jersey-spring</artifactId>
        <version>1.19.1</version>
   <dependency>

This dependency is used to integrate Spring and Jersey

Step-2:- Now create a WebApplicationContext to read all the configuration information from your mvc-dispatcher-servlet.xml. For this copy the following code to your web.xml

<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Step-3:-- Now integrate spring and jersey by using jersey framework provided class com.sun.jersey.spi.spring.container.servlet.SpringServlet (This class is available in jersey-spring.jar ). For this copy the below code to your web.xml

<servlet>
        <servlet-name>jersey-serlvet</servlet-name>

        <servlet-class>
            com.sun.jersey.spi.spring.container.servlet.SpringServlet
        </servlet-class>

        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>ngdemo.rest</param-value>
        </init-param>

        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

Thats it. Everything is completed.

Just update your maven project and run again in the server.

Suggestion One more thing when you are adding dependency ( jersey-spring-1.19.1.jar ) some spring related jar files (like spring-aop.3.0.0CR.jar, spring-bean.jar etc.. ) are included into your maven dependencies and the included jars are old version. So sometime you may get ClassNotFoundException.So you have to exclude those spring dependencies. If you get such kind of Exception copy this below code to element of your jersey-spring.jar

<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-spring</artifactId>
    <version>1.19.1</version>
    <exclusions>
        <exclusion>
            <artifactId>spring-context</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-core</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-beans</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-web</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-aop</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
    </exclusions>
</dependency>

I hope this helps you. Let me know whether you got correct solution or not.

Snr
  • 141
  • 4
0

I should suggest you to use interfaces instead implementations, in your controller you are injecting DAO implementation, while you should inject service interface.

If you do not want to use service class, I should suggest you to inject an interface:

public class PlayerDAO implements IPlayerDAO

and in your controller inject interface.

public class LoginRestService {

    @Autowired
    private IPlayerDAO IPlayer;

This is a good practice.

In other hand, you are setting transactional in DAOS, it is not a good idea, you should specify it in a service class.

Finally talking about your problem, null in a spring component, normally, it is because it is not properly specified component scan.

regards.

duardito
  • 107
  • 2
  • 8
  • Thank you for good practise learning. But how to properly specify component scan? – Daniel Stradowski Jun 26 '16 at 14:06
  • hi, can you show package where your classes are? then copy exact path in ****. I should recomend, first add interfaces, and a service layer between controller and dao. And move transactionality to service layer. Latest step should be inject interfaces. – duardito Jun 26 '16 at 14:08
  • `package ngdemo.dao;` PlayerDAO.java. And LoginRestService.java: `package ngdemo.rest;`So it should be exact path? Can I use it twice? – Daniel Stradowski Jun 26 '16 at 14:09
  • add this pacakages to scan : , – duardito Jun 26 '16 at 14:12
  • ` ` didnt help, playerDAO is still null. I'll try with interface. – Daniel Stradowski Jun 26 '16 at 14:12
  • exactly, use interfaces. – duardito Jun 26 '16 at 14:13
  • But in intellij component scan shows me that it see the beans. – Daniel Stradowski Jun 26 '16 at 14:20
  • I forget one thing, you need to add an extra definition in your xml file, you need to specify where you repository is located with this : – duardito Jun 26 '16 at 14:23
  • If we can not see all code, it is difficult to try to solve it. Can you share it in github? – duardito Jun 26 '16 at 14:41
  • It's about time to ease down on the "use interfaces" advice. As long as you have only one implementation and no module-level separation (as in separate JAR containing only java-beans and interfaces), there is no reason to introduce and use interface. As soon as another implementation of the service pops up you can extract the interface. Doing it eagerly won't save you any time, just clutter your code with one-implementation interfaces. Just like header files in CPP. Don't do it just because someone at some point said it's a "best practice". – Michal M Jun 26 '16 at 15:16
  • http://stackoverflow.com/questions/12899372/spring-why-do-we-autowire-the-interface-and-not-the-implemented-class – duardito Jun 26 '16 at 17:17
0

I tried the github version of your application, added a test and it worked fine: https://github.com/michalmela/hestalis .

Check your test configuration. Also, please don't follow the advice from the other response to add interfaces for services for no good reason.

Michal M
  • 1,521
  • 14
  • 35
  • Maybe it works for you, because you use: @ContextConfiguration(locations = "classpath:**/mvc-dispatcher-servlet.xml"). I tried to use ContextConfiguration in my LoginRestService class, but it didn't help, because it cant resolve the path to mvc-dispatcher-servlet.xml in webapp.WEB-INF. Maybe I should put it in different package? Is it possible that this xml file is not seen by my project? How can I make my app see it? – Daniel Stradowski Jun 26 '16 at 17:37
  • Nope, `@ContextConfiguration` is only for tests, don't use it in production classes. Anyway, I guess then it boils down to `web.xml`. Tell me what servlet container (tomcat, jetty, sth else?) are you using and I'll take a look. – Michal M Jun 27 '16 at 07:18
  • tomcat. You can be right, because i didn't perform any spring configuration in web.xml. I thought it'll work without it. – Daniel Stradowski Jun 27 '16 at 08:32
0

Try giving @Component annotation at the top of your PlayerDAO class . May be that way your bean will be scanned properly by Spring .This will register the bean in Spring Container for sure . Let me know if that helps :)

Saurabh Chaturvedi
  • 2,028
  • 2
  • 18
  • 39