7

I am studying spring framework and trying to use it in my project. But I have came across the following problem with spring data repository and @Transactional annotation used in my service. The problem is that there are no exceptions on the spring start up. Later on when I try to access spring data repository I get NullPointerException. Maybe you have some thoughts that could help me.

I am using spring data repository define as following:

package net.question.data.repository;

import net.question.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {  
}

Then I have a service defined which contains autowired repository:

package net.question.data.service;

import net.question.data.repository.UserRepository;
import net.question.model.User;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class UserService {
    @Autowired
    public UserRepository userRepository;

    public void doStuff(User usr) {
            // login will be here
    }
}

here is the test to show my problem:

package net.question.spring;

import static org.junit.Assert.assertNotNull;
import net.question.data.service.UserService;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/app-context.xml")
public class InjectionTestSuite {

    @Autowired
    UserService userService;

    @Test
    public void testRepositoryInjection() {
            assertNotNull(userService);
            assertNotNull(userService.userRepository);
    }
}

The test fails on the follwowing line:

assertNotNull(userService.userRepository);

If I remove the @Transactional annotation on the service then the test passes.

here is my app-context.xml file:

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:tx="http://www.springframework.org/schema/tx"
        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-3.1.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd
    http://www.springframework.org/schema/data/jpa
    http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd ">

    <jpa:repositories base-package="net.question.data.repository" />

    <!-- For discovering entity services -->
    <context:component-scan base-package="net.question.data.service" />

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

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

    <tx:annotation-driven />
</beans>

Maybe you have some ideas, how to find the error?

reemsky
  • 71
  • 1
  • 2
  • It might have something to with the proxy wrapping. Given your configuration the injection of the `UserService` into the test case cannot work actually. As you do not implement an interface with `UserService` the proxy created for the object will use CGLib and thus is not assignable to `UserService` anymore. So are you sure, it's not the first assertion that fails if you add `@Transactional`? Any chance you change the `UserService` into an interface and let the class be `UserServiceImpl` or the like and retry? – Oliver Drotbohm Apr 04 '12 at 23:26
  • I have added logging to the test class and I am sure that service is NOT null. More that that if I create getter and setter for repository in service and access it via them then test passes. Not very nice solution though. Anyway I still do not understand why my example fails and why @Transactional annotation makes any difference. – reemsky Apr 05 '12 at 10:19
  • Read up on that one: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies and http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop-api.html#aop-pfb-proxy-types. `@Transactional` triggers a proxy being created, thus the differing behavior. – Oliver Drotbohm Apr 05 '12 at 17:49
  • Oliver thank you for you comments! – reemsky Apr 05 '12 at 19:32
  • Looking at: https://dzone.com/articles/transaction-configuration-jpa seems like you are missing: – Ignasi Jan 28 '16 at 22:14

0 Answers0