marionmaiden
marionmaiden

Reputation: 3350

org.springframework.beans.factory.BeanCreationException with Transaction Manager

I've been studying Spring MVC on a Restful application, but I'm struggling to get it working.

My application have the following structure:

I want to use @Transactional for queries, but I'm getting the error message on server start when I configure it on spring xml file.

WARN : org.springframework.web.context.support.XmlWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'calendarController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private br.com.milo.repository.CalendarRepository br.com.milo.controller.CalendarController.repository; nested exception is java.lang.IllegalArgumentException: Can not set br.com.milo.repository.CalendarRepository field br.com.milo.controller.CalendarController.repository to com.sun.proxy.$Proxy47
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:835)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:667)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:633)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:681)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:552)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:493)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:158)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1197)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1087)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5253)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5543)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1574)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1564)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

This error only happens if I add the following config in my spring config file:

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

If I remove this line, the problem disappears, the Restful requests works fine, but, the Repository methods doesn't save the data. In this case, the message below is shown (this error ocurred on another Controller, as Callendar functionality isn't finished. Although, the exception is related, as it verses about Transaction):

Dec 29, 2015 5:03:45 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/milo] threw exception [Request processing failed; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call] with root cause
javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:277)
    at com.sun.proxy.$Proxy45.persist(Unknown Source)
    at br.com.milo.repository.FarmRepository.save(FarmRepository.java:28)
    at br.com.milo.controller.FarmController.insertFarm(FarmController.java:70)
    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:497)
    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.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    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 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.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at br.com.milo.security.CsrfHeaderFilter.doFilterInternal(CsrfHeaderFilter.java:34)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:120)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    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:170)
    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:423)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    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)

Here is my spring config file

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

    <mvc:annotation-driven />

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

    <resources mapping="/resources/**" location="/resources/" />
    <resources mapping="/pages/**" location="/pages/" />
    <resources mapping="/login/**" location="/login/" />

    <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>

    <beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <beans:property name="messageConverters">
            <beans:list>
                <beans:ref bean="jsonMessageConverter"/>
            </beans:list>
        </beans:property>
    </beans:bean>

    <beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    </beans:bean>   

    <beans:bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <beans:property name="dataSource" ref="dataSource" />
      <beans:property name="packagesToScan" value="br.com.milo" />
      <beans:property name="jpaVendorAdapter">
         <beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
      </beans:property>
      <beans:property name="jpaProperties">
         <beans:props>
            <beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</beans:prop>
         </beans:props>
      </beans:property>
   </beans:bean>

   <beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <beans:property name="driverClassName" value="org.postgresql.Driver" />
      <beans:property name="url" value="jdbc:postgresql://localhost:5432/milo" />
      <beans:property name="username" value="123" />
      <beans:property name="password" value="123" />
   </beans:bean>

    <beans:bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <beans:property name="entityManagerFactory" ref="myEmf" />
    </beans:bean>
    <!-- Just when I add this line the error above  is shown -->
    <tx:annotation-driven transaction-manager="transactionManager"/>    
</beans:beans>

Here is the Class CalendarController.java

package br.com.milo.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import br.com.milo.domain.Calendar;
import br.com.milo.domain.Owner;
import br.com.milo.domain.DTO.CalendarMonthDTO;
import br.com.milo.repository.CalendarRepository;
@RestController
@RequestMapping("/rest/calendar")
public class CalendarController {

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

    @Autowired
    private CalendarRepository repository;

    @RequestMapping(value = RestPaths.GET_CALENDAR, method = RequestMethod.GET)
    public @ResponseBody Calendar getCalendar(@PathVariable("id") int id) {
        logger.info("Start Get Calendar. ID=" + id);
        return repository.findById(id);
    }

    @RequestMapping(value = RestPaths.LIST_CALENDARS, method = RequestMethod.GET)
    public @ResponseBody List<Calendar> listCalendars() {
        logger.info("Start List Calendars.");
        List<Calendar> calendars = repository.list();
        return calendars;
    }

    @RequestMapping(value = RestPaths.LIST_CALENDAR_BY_OWNER, method = RequestMethod.GET)
    public @ResponseBody List<Calendar> listByOwner(@RequestBody Owner o) {
        logger.info("Start List Calendars By Owner.");
        List<Calendar> calendars = repository.listByType(o);
        return calendars;
    }

    @RequestMapping(value = RestPaths.UPDATE_CALENDAR, method = RequestMethod.POST)
    public @ResponseBody Calendar updateCalendar(@RequestBody Calendar calendar) {
        logger.info("Start Update Calendar.");
        repository.update(calendar);
        return calendar;
    }

    @RequestMapping(value = RestPaths.INSERT_CALENDAR, method = RequestMethod.POST)
    public @ResponseBody Calendar insertCalendar(@RequestBody Calendar calendar) {
        logger.info("Start Insert Calendar.");
        repository.save(calendar);
        return calendar;
    }

    @RequestMapping(value = RestPaths.DELETE_CALENDAR, method = RequestMethod.PUT)
    public @ResponseBody Calendar deleteCalendar(@PathVariable("id") int calendarId) {
        logger.info("Start delete Calendar.");
        Calendar calendar = repository.findById(calendarId);
        repository.delete(calendar);
        return calendar;
    }

    @RequestMapping(value = RestPaths.LIST_CALENDAR_BY_MONTH, method = RequestMethod.GET)
    public @ResponseBody List<Calendar> listByMonth(@RequestBody CalendarMonthDTO calendarDTO) {
        logger.info("Start List Calendar By Month.");
        List<Calendar> calendars = repository.listByMonth(calendarDTO.getOwner(), calendarDTO.getYear(), calendarDTO.getMonth());
        return calendars;
    }

}

Here is the class CalendarRepository.java

package br.com.milo.repository;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import br.com.milo.domain.Calendar;
import br.com.milo.domain.Owner;

@Repository
public class CalendarRepository implements br.com.milo.repository.Repository<Calendar, Owner>{

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    @Transactional
    public void save(Calendar calendar) {
        entityManager.persist(calendar);
    }

    @Override
    @Transactional
    public void update(Calendar calendar) {
        entityManager.merge(calendar);
    }

    @Override
    @Transactional
    public void delete(Integer id) {
        this.delete(this.findById(id));
    }

    @Override
    @Transactional
    public void delete(Calendar calendar){
        entityManager.remove(calendar);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Calendar> list() {
        Query query = entityManager.createQuery("from Calendar c order by c.calendarDate DESC");
        return query.getResultList();
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Calendar> listByType(Owner o) {

        if(o != null){
            Query query = entityManager.createQuery("from Calendar c join c.ownerList o where o.name = :owner");
            query.setParameter("owner", o.getName());
            return query.getResultList();
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public List<Calendar> listByMonth(Owner o, int year, int month) {

        if(o != null){
            Query query = entityManager.createQuery("from Calendar c join c.ownerList o "
                + "where o.name = :owner "
                + "and month(e.calendarDate)=:month "
                + "and year(e.calendarDate)=:year");
            query.setParameter("owner", o.getName());
            query.setParameter("month", month);
            query.setParameter("year", year);
            return query.getResultList();
        }
        return null;
    }

    @Override
    public Calendar findById(Integer id) {
        Calendar calendar = entityManager.find(Calendar.class, id);
        return calendar;
    }

}

Thanks in advance for looking to my question!

Upvotes: 1

Views: 1210

Answers (1)

Benedikt K&#246;ppel
Benedikt K&#246;ppel

Reputation: 5109

Your repository field in the CalendarController should be defined by the interface, not with the class. Spring creates a Proxy around your CalendarRepository which implements the same interfaces, but is not a subclass of CalendarRepository.

This question was about exactly the same problem: @Autowired return exception on UserDetails in Spring-security

You are trying to autowire your user details service by class, but that can't work, because the spring bean is actually a proxy created around that class (and not an instance of the class). The proxy will however implement all interfaces of the original bean, so injecting by interface is safe.

Exchange this line:

@Autowired
private MyCustomUserDetailsService myCustomUserDetailsService;

for this one:

@Autowired
private UserDetailsService myCustomUserDetailsService;

Read the section on Proxying Mechanisms in the Spring AOP to understand the details.

So in your case, you could create a new interface CalendarRepository with the methods you need, and then implement then in class CalendarRepositoryImpl implements CalendarRepository:

interface CalendarRepository extends br.com.milo.repository.Repository<Calendar, Owner>{
    void save(Calendar calendar);
    void update(Calendar calendar);
    void delete(Integer id);
    ... (and all other methods you need)
}

@Repository
class CalendarRepositoryImpl implements CalendarRepository {
    ... (what you currently have in CalendarRepository)
}

class CalendarController {
    @Autowired
    CalendarRepository repository; // NOT CalendarRepositoryImpl
}

Upvotes: 1

Related Questions