Jefferson Tavares
Jefferson Tavares

Reputation: 991

Spring @Transactional calling abstract superclass method throws org.hibernate.HibernateException

I have read over 20 questions on stackoverflow related to this, but none of them worked.

Basically I have a service abstract superclass with 3 methods. Persist is like a template method, whereas save and update are overriden only when needed.

public abstract class BaseService<E> implements ServiceImpl{
    protected E save(E object, Class<E> returnedClass){//save object}
    protected E update(E object){//update object}

    public boolean persist(E object) {
        //validation rules

        if(shouldSave) {
            save(object);
        }else {
            update(object);
        }
    }
}

Then I have this subclass

@Service
@Transactional
public CompanyService extends BaseService<Company> {
    @Autowired
    private CompanyRepository repository;

    public void testSaving(Company company) {
        repository.save(company);
    }

    @Override //from service impl
    public CommpanyRepositoy getRepository() {
        return repository;
    }
}

and this is my entry point

@RestController
@RequestMapping("/company")
public CompanyRestController {
    @Autowired
    private CompanyService service;

    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public boolean save(@RequestBody Company company) {
        return service.persist(company);
    }
}

Now, the thing is, if I call for the testSaving method, everything goes right. BUT, when I call the persist method, it always give the error mentioned. I have tried lot's of things, like adding @Transactional to the BaseService superclass and even adding it to my repository doesn't work. Please, I need to fix this, its driving me crazy. Any advice?

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
    at br.com.jeffersontpadua.spring.generic.BaseRepository.getSession(BaseRepository.java:56)
    at br.com.jeffersontpadua.spring.generic.BaseRepository.save(BaseRepository.java:27)
    at br.com.jeffersontpadua.spring.service.BaseService.save(BaseService.java:45)
    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:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:723)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
    at br.com.jeffersontpadua.spring.service.CompanyService$$EnhancerBySpringCGLIB$$a3329725.save(<generated>)
    at br.com.jeffersontpadua.spring.service.BaseService.persist(BaseService.java:34)
    at br.com.jeffersontpadua.spring.rest.CompanyRestController.save(CompanyRestController.java:41)
    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:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at br.com.jeffersontpadua.spring.filter.RequestFilter.doFilter(RequestFilter.java:34)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    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:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:436)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    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)

Upvotes: 1

Views: 2966

Answers (2)

Jefferson Tavares
Jefferson Tavares

Reputation: 991

I finaly found a way to make this happen, so, for anyone who is still struggling to solve this, the trick is to add @Transactional(propagation = Propagation.REQUIRES_NEW) to your superclass xD

Upvotes: 2

Naros
Naros

Reputation: 21113

This is intentional, see SPR-7824.

You basically need to place the @Transactional annotation on the super-class rather than the subclass and that will cause all subclass methods to be transactional as well as those on the superclass.

If you cannot do that, override the methods in the subclass and delegate to the superclass.

Upvotes: 4

Related Questions