2

SUMMARY

I'm building a spring-mvc web application and trying to use Mybatis and DAO for data access.

I configured Mybatis successfully and I was able to fetch expected data from Mysql server.

But a problem occured when I tried to use DAO with Mybatis.

ERROR

As you could see below, it's a NullPointerException.

INFO : com.*****.web.controller.ExampleController - testDaoSelect action has been executed. No parameter has been taken.
INFO : com.*****.web.service.exampleService - Executed or not??
09, March, 2015 5:07:28 PM org.apache.catalina.core.StandardWrapperValve invoke
Fatal: Servlet.service() for servlet [appServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
    at com.*****.web.service.exampleService.sampleList(exampleService.java:29)
    at com.*****.web.controller.ExampleController.testDaoSelect(ExampleController.java:188)
    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.invoke(InvocableHandlerMethod.java:213)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1086)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:659)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
    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)

REPRODUCING ERORR

Starting with AJAX call.

    $('#DaoSelectTest').click(function(e) {
    $.ajax({
        type: "POST",
        url: "/testDaoSelect.fst",
        data: {},
        success: function (result) {
            console.log(result);

            var html = "Querying was successful. Check out console logs. <br/>";
            html += "Done with the test. <a href='/daoSample.fst'>Click here</a> ";
            html += "And proceed to the next.";

            $('#sampleTable').html(html);
        },
        error: function (result) {
            // error...
        }
    });
});

And next, the action is executed..

@Controller
public class ExampleController {

    // Mybatis direct
    @Autowired
    private SqlSession sqlSession;

    // Dao  
    @Autowired
    private exampleService exService;
.
.
.
.
.


@RequestMapping("/testDaoSelect")
        @ResponseBody
        public List<HashMap<String, Object>> testDaoSelect(HttpServletRequest request, HttpServletResponse response) {
            logger.info("testDaoSelect action has been executed. No parameter has been taken.");

            List<HashMap<String, Object>> result = exService.sampleList();

            logger.info("result size is... " + result.size());

            return result;
        }

Calling textDaoSelect is alright, and what's next is Service class.

@Service
@Transactional
public class exampleService {

    private Log logger = LogFactory.getLog(this.getClass());

    @Autowired
    private exampleDao exDao;

    @Transactional(readOnly = true)
    public List<HashMap<String, Object>> sampleList() {
        logger.info("Executed or not??");

        return exDao.sampleList();
    }
}

BOOM~! HERE

exDao is null here, NullPointException occurs here. It's not correctly wired. Why?? And What should I do??

My exampleDao

public interface exampleDao {
    public List<HashMap<String, Object>> sampleList();
}

**My exampleDaoImplement

public class exampleDaoImplement extends SqlSessionDaoSupport implements exampleDao {

    private static final Logger logger = LoggerFactory.getLogger(exampleDaoImplement.class);    

    public List<HashMap<String, Object>> sampleList() {
        // TODO Auto-generated method stub

        logger.info("I've reached impl class....");
        return getSqlSession().selectList("Example.selectTest");

    }
}

MY ROOT CONTEXT

( Forget about ****** anyway... )

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

    <!-- Root Context: defines shared resources visible to all other web components -->

    <bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://*******:3306/*****_web"/>
        <property name="username" value="root"/>
        <property name="password" value="*******"/>
    </bean>

    <bean id ="sqlSessionFactory" class= "org.mybatis.spring.SqlSessionFactoryBean" >
        <property name ="dataSource" ref= "dataSource"></property >
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
    </bean >

    <bean id ="transactionManager"
        class= "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
        <property name ="dataSource" ref= "dataSource"></property >
    </bean >

    <bean id ="sqlSession"
        class= "org.mybatis.spring.SqlSessionTemplate" >
        <constructor-arg ref= "sqlSessionFactory"></constructor-arg >
    </bean >

    <bean id ="exService" class= "com.*****.web.service.exampleService" ></bean >

</beans>

My servlet-context

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

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

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

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

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

    <context:component-scan base-package="com.******.web.controller" />

</beans:beans>

I've googled on this for like a half a day, and got some hints but no exact solutions. What seems to be the matter??


ADDED

While googling, I got this hint and configured accordingly.

<bean id ="exDao" class= "com.*****.web.dao.implement.exampleDaoImplement" >
    <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean >

( without defining property, It throws error while starting up the server, saying that property sqlSessionFactory or SqlSessionTemplate is required. )

But it doesn't work... even with this configuration, there's still the nullpoint error.

hina10531
  • 3,938
  • 4
  • 40
  • 59

3 Answers3

3

First idea : in servlet-context.xml, you have written:

<context:component-scan base-package="com.******.web.controller" />

This means that Spring will look for your annotated classes (like @Service and others) only inside this folder. Did you, by any chance, put your DAO outside of the "com.******.web.controller" folder? This would explain why it remains null.

A simple test is to use "com.******" to make sure that every folders are scanned.

Second idea : if you want that Spring instanciates your DAO class, you have to add the @Repository annotation in your concrete implementation of the DAO interface.

Third idea : you should not use XML-configuration and an annotation for the same class. In your example, you don't need to use <bean id ="exService" class= "com.*****.web.service.exampleService"></bean > if you use @Service in the exampleService class and your <component-scan> covers the directory where the service is.

Final note: You write in the comments that using @Service("exService") solved your problem. This is due to the fact that, if you don't specify the name of your components, Spring looks up for any existing bean with the given type (and not its name). So, it injected the bean you declared in XML, which had a null DAO.

To avoid this kind of problems, you should always explicitly name your beans after the name of the variable where you use it, here @Service("exService") toggles the "bind by name" behaviour, which makes your code works as expected:

// This works because the name of the variable
// matches the @Service("exService") annotation
@Autowired
private ExampleService exService;

Thanks go to @RohitJain for this last note.


Unrelated to your problem, Java classes and interfaces should always be written with an uppercase letter (e.g. "ExampleDao", "ExampleDaoImplement" and "ExampleService").

Grégoire C
  • 1,361
  • 1
  • 13
  • 32
  • Yes, My DAOs are outside of the controller package. I also got your hint and tried to add `` on _servlet-context.xml_ like this, but with this configuration, It's the same... still `NullPointException` – hina10531 Mar 09 '15 at 08:52
  • Please try with ``, without any subfolders, that way you will be sure that Spring instanciates everything it can find. If you still have the error when the server starts, please post it in your question. – Grégoire C Mar 09 '15 at 08:57
  • No server error anymore, but it's still `NullPointException` – hina10531 Mar 09 '15 at 08:59
  • Have you a `@Repository` in your class *exampleDaoImplement*? – Grégoire C Mar 09 '15 at 09:07
  • Then you must have this, otherwise Spring will ignore your DAO class. Also, you don't need to use `` if you use `@Service` in the *exampleService* class and your `component-scan` covers the directory where the service is. This is redundant and could make Spring do stupid things, like instanciating your service twice. – Grégoire C Mar 09 '15 at 09:11
  • UPDATED my question. Without the declaration, starting up the server fails. – hina10531 Mar 09 '15 at 09:17
  • 1
    You should try re-using the `id` that you were declaring in XML, that is, you should annotate your service with `@Service("exService")` instead of just `@Service`. – Grégoire C Mar 09 '15 at 09:23
  • `@Service("exService")` Solved my problem. My god !! thank you soooo much, could you explain why "exService" is required in this case??? – hina10531 Mar 09 '15 at 09:29
  • You've registered 2 `exampleService` bean. One using `@Service` annotation, and one in your `xml` file. That probably is the issue. That is why you should be very careful while mixing up different ways of bean registration. – Rohit Jain Mar 09 '15 at 09:37
  • 1
    @geceo Your reasoning is not correct. Spring uses autowire byType as default when you use `@Autowired` annotation. Here there are two beans with type `ExampleService`, one in root context, and one through child context. If `DAO` bean is registered in `child` context, and autowiring will only be done in the `service` bean registered in child context - which is `exService`. – Rohit Jain Mar 09 '15 at 09:40
  • @hina10531 Which xml file have you registered your `exDao`? – Rohit Jain Mar 09 '15 at 09:46
  • @RohitJain I believe the OP removed the XML declaration of the bean "ExampleService" (that's what I meant with my "third idea" above), so there may not be anymore two beans for this same class. – Grégoire C Mar 09 '15 at 09:51
  • @RohitJain You're right, Spring injects the component from its type in the example I gave, because of the lack of the name after the `@Service`. The problem was probably due to the double declaration of the *ExampleService* bean. I'll try to correct my answer. Thanks for your comment. – Grégoire C Mar 09 '15 at 10:18
  • @RohitJain It's root-context.xml in which I registered `exService` and `exDao` – hina10531 Mar 09 '15 at 10:30
0

This is a really wild guess, but I think you should rename exampleDaoImplement to exampleDaoImpl with a refactor rename.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • Is the `exampleDao` service in `com.****.service`, and the `exampleDaoImpl` in `com.****.service.impl` package? Try making the `exampleDaoImpl` class into a bean by either XML or by using `@Component` annotation. – EpicPandaForce Mar 09 '15 at 09:23
  • Well, `@Repository` and `@Component` currently do pretty much the same thing, so that would have worked. Oh well. – EpicPandaForce Mar 09 '15 at 10:30
0

My implementation uses pure XML spring config and everything is fine since the web-app is able to boot up normally without any errors.

But I still got null exception for a DAO instance autowired by name and I solved it by adding a getter and one setter for it.

Linyun Liu
  • 721
  • 6
  • 7