Reputation: 3350
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
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