0

Question is not a duplicate as Hibernate is involved

As the James' answer partially solved the problem, I accepted it and opened a new question, please follow up here

I am trying to inject SessionFactory into a repository class; however, it looks like it does not work as the code returns NullPointer exception. I cleaned and rebuilt the project but the issue still exist. I also put @Autowired on the setSessionFactory method but did not help.

Interface

public interface TestRep {
public void get(int id);
}

Class

@Repository
public class TestRepImpl implements TestRep{

    @Autowired
    SessionFactory sessionFactory;


    public TestRepImpl() {

    }

    public TestRepImpl(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Transactional
    public void get(int id) {
        String hql = "from Business where id=" + id;
        Query query = sessionFactory.getCurrentSession().createQuery(hql);
         ....

pr-servlet.xml

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

<context:annotation-config/>
 .....
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>

<tx:annotation-driven />
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="TestRep" class="com.project.repository.TestRepImpl">
    <constructor-arg>
        <ref bean="sessionFactory" />
    </constructor-arg>
</bean>

StackTrace

    Mar 10, 2015 12:22:21 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [pr] in context with path [/project] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
    at com.project.repository.TestRepImpl.get(TestRepImpl.java:39)
    at com.project.web.MainController.index(MainController.java:17)
    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 org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

Jars

Jars

MainController

@Controller
public class MainController {

     @RequestMapping("/{viewName}.htm")
     public String index(@PathVariable(value = "viewName") String viewName) {
     System.err.println(viewName);
     Test test = new Test();
     test.get(1);
     if (isValidView(viewName)) {
     return viewName;
     }
     return null;
     }

    @RequestMapping("/{viewName}/{viewName2}") //suburb/catname
    public String index(@PathVariable(value = "viewName") String viewName, Model model) {
        System.err.println(viewName);
        if (isValidView(viewName)) {
            model.addAttribute("viewName",viewName);
            return "page";
        }
        return null;
    }

    private boolean isValidView(String viewName) {
        switch (viewName) {
        case "index":
        case "aboutus":
            return true;
        }
        return false;
    }

}

Test

@Service 
public class Test {

    public void get(int i){
         TestRepImpl test = new TestRepImpl();
         test.get(i);
    }
}

Hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">12</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">update</property>


        <mapping class="com.myproject.model.MyTable" />
        ....
Community
  • 1
  • 1
Jack
  • 6,430
  • 27
  • 80
  • 151
  • You shouldn't need the getter and setter for sessionFactory. Also, did you try putting the line above the sessionFactory bean declaration? Just comparing mine with yours. – riddle_me_this Mar 10 '15 at 03:47
  • Try removing your constructor. You don't need it, since you are autowiring. – minion Mar 10 '15 at 03:59
  • @bphilipnyc still the same issue – Jack Mar 10 '15 at 04:15
  • @minion still the same issue – Jack Mar 10 '15 at 04:15
  • Can you paste the top of pr-servlet.xml? Should be something like: – riddle_me_this Mar 10 '15 at 04:17
  • @bphilipnyc then it shows context is not bound. – Jack Mar 10 '15 at 04:23
  • Can you also add MainControlller code to the post? – RKodakandla Mar 10 '15 at 05:32
  • 1
    @James-Massey has the right approach - you may want to read up on the Spring autowiring (dependency-injection) concepts and look at sample projects on github. There's a lot of nitpicks that Spring has about configuration and you'll get exceptions if it's even slightly off. It doesn't take too long if you play around with it for a bit. Spring Boot can relieve some of this. Also, the move is generally to using JavaConfig over XML config based at what I saw at the last SpringOne conference. There are pros and cons to JavaConfig - just letting you know. – riddle_me_this Mar 10 '15 at 14:55
  • @bphilipnyc thanks for your comment, which source do you suggest to learn it? I have found Spring documentation quite confusing and incomplete. I am looking for a tutorial with working examples, I read Hibernate related part of the documentation but did not help me much. – Jack Mar 11 '15 at 00:10
  • possible duplicate of [Why is my Spring @Autowired field null?](http://stackoverflow.com/questions/19896870/why-is-my-spring-autowired-field-null) – chrylis -cautiouslyoptimistic- Mar 11 '15 at 00:49
  • 1
    Definitely look at Spring Boot; I'm using it for all my applications now. I recommend Greg Turnquist's Learning Spring Boot book. – chrylis -cautiouslyoptimistic- Mar 11 '15 at 00:51

1 Answers1

3

You need to use Autowiring everywhere or your program won't work. Spring can only autowire beans that are present in the Spring application context, which is what your @Controller, @Service and @Repository annotations are supposed to do. However, these annotations are meaningless without a <context:component-scan base-package="your.base.package"> tag in your config XML.

So, assuming that your controller, service and DAO are all somewhere in the package com.repository, you need to add this line to your XML config.

<context:component-scan base-package="com.repository"/>

What this does is tells Spring to recursively search inside the foo.bar.baz package (and all sub-packages) for classes annotated with @Controller, @Service, @Repository and @Component, instantiate a singleton instance of them and make them eligible to be autowired into other classes.

You also need to modify your controller and service classes to use @Autowired. Spring can't manage your classes if you instantiate them with the new keyword. These beans are singletons (only one instance of them should ever exist in your program) for a reason.

Your controller needs to change as follows.

@Controller
public class MainController {

    @Autowired
    private TestService testService;

    @RequestMapping("/{viewName}.htm")
    public String index(@PathVariable(value = "viewName") String viewName) {
         System.err.println(viewName);
         testService.get(1);
         if (isValidView(viewName)) {
             return viewName;
         }
         return null;
     }

    @RequestMapping("/{viewName}/{viewName2}") //suburb/catname
    public String index(@PathVariable(value = "viewName") String viewName, Model model) {
        System.err.println(viewName);
        if (isValidView(viewName)) {
            model.addAttribute("viewName",viewName);
            return "page";
        }
        return null;
    }

    private boolean isValidView(String viewName) {
        switch (viewName) {
        case "index":
        case "aboutus":
            return true;
        }
        return false;
    }
}

Notice that you Autowire your service class into your controller.

Your service class needs to implement an interface. Spring does all this autowiring magic using interfaces. You cannot autowire a class that does not implement an interface, unless you specifically create an instance of that class in your XML config.

Your service class needs to change as follows:

@Service 
public class TestServiceImpl implements TestService {
    @Autowired
    private TestRepDao testDao;

    @Transactional
    public void get(int i){
         testDao.get(i);
    }
}

and create an interface called TestService.

public interface TestService{
    public void get(int i);
}

and then your DAO becomes

@Repository
public class TestRepDaoImpl implements TestRepDao{

    @Autowired
    private SessionFactory sessionFactory;

    public void get(int id) {
        String hql = "from Business where id=" + id;
        Query query = sessionFactory.getCurrentSession().createQuery(hql);
    }
}

which implements the interface TestRepDao:

public interface TestRepDao{
    public void get(int id);
}

you can also remove the declaration of

<bean id="TestRep" class="com.project.repository.TestRepImpl">
    <constructor-arg>
        <ref bean="sessionFactory" />
    </constructor-arg>
</bean>

from your XML configuration.

As you can see I've changed a few class names to better fit with the Spring convention. Your application is supposed to layer down from Controller to Service Class to DAO and back out again. This should work providing you follow the steps I've laid out here.

A few things to keep in mind:

  1. Spring hates the new keyword. If you find yourself using it, you are probably doing something wrong.
  2. There is only ever one instance of any of your classes that Spring picks up with the component scan in your entire application. DO NOT use these classes to store persistent data or states. That path is full of threading issues, race conditions and pits full of acid spiders.
  3. Read and re-read the documentation, these are not easy concepts to pick up if you have never used Spring before. Spring is super easy to use, once you understand how it works, and how it expects you to use it.
  4. Spring works on interfaces. If your class doesn't implement an interface, Spring can't proxy it without using AspectJ Load Time Weaving, which is a conversation for another day, and not something you should be using, just starting out. If you don't know why Spring needs to create a proxy of your object, you need to re-read the documentation until you understand the application context.
  5. I moved the @Transactional annotation into the Service class. This is because the DAO should only be concerned with accessing and retrieving the data from the database, NOT having to manage the connection/session to the database, that is the job of the service class.
  6. I'm guessing you started using the new keyword after hitting exceptions saying something similar to

    No qualifying bean of type found for dependency TestService.

    This is Spring telling you that it doesn't have a bean that can be autowired into the TestService field on whatever class. Listen when Spring is telling you things, it will save you a lot of bother.

  7. Don't be discouraged, I faced all these problems when I was trying to learn how to use Spring, but I got through it and Spring is second nature to me now.
JamesENL
  • 6,400
  • 6
  • 39
  • 64
  • I appreciate your help, it works now, however it throws following exception org.hibernate.HibernateException: createQuery is not valid without active transaction – Jack Mar 10 '15 at 06:16
  • Did you move the `@Transactional` annotation to your Service class? Is the annotation on the actual method inside the `TestServiceImpl` and not on the interface? Add this bean to your config as well: `` – JamesENL Mar 10 '15 at 06:21
  • How are you running this? Are you using JUnit, or deploying onto something like a Tomcat Server? – JamesENL Mar 10 '15 at 06:21
  • Yes I moved @ Transactional to @ Service class, and i is in actual method not interface. Whats that bean good for? – Jack Mar 10 '15 at 06:23
  • deploying into Tomcat – Jack Mar 10 '15 at 06:23
  • That bean translates HibernateExceptions into something that Spring can work with to control your transactions. – JamesENL Mar 10 '15 at 06:24
  • Now that I added it, looks like it cant find the entities , Caused by: java.lang.ClassNotFoundException: com.myproject.model.Business – Jack Mar 10 '15 at 06:26
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72640/discussion-between-jack-and-james-massey). – Jack Mar 10 '15 at 06:30
  • James I am available to chat, please let me know when you are free. thanks – Jack Mar 10 '15 at 23:12
  • Following this question http://stackoverflow.com/questions/26836560/createquery-is-not-valid-without-active-transaction I added transaction manager to the tx:annotation, at first it throws an exception that it cannot the first entity that I declared in hibernate.cfx.xml and in the second run throws the same error as before. – Jack Mar 11 '15 at 00:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72713/discussion-between-jack-and-james-massey). – Jack Mar 11 '15 at 01:00
  • please follow up the question here http://stackoverflow.com/questions/28976816/org-hibernate-hibernateexception-createquery-is-not-valid-without-active-transa – Jack Mar 11 '15 at 01:01
  • Your suggestions sound great to the learner of the spring, especially the last 7 points. Thank you. – zhfkt Mar 09 '16 at 16:26