Spring MockMvc Did not find handler method - java

I've added validation to the classes in an app that provides REST APIs and I'm trying to restructure the unit tests to use MockMvc so that the validation will be called. I've seen several tutorials on setting this up, but whenever I try and make a call to one of the APIs, I get a 404 empty response and the log files indicate "Did not find handler method for /xxxxx".
There's probably just something I'm missing in either the XML configuration file or the test class, but I haven't been able to figure it out.
Test Code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:spring_test.xml")
#TestPropertySource("classpath:test.properties")
#WebAppConfiguration
public class ClientControllerTest {
#Autowired
private Validator validator;
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
private static final String baseUrl = "http://localhost:8080";
#Mock
StorageProvider storageProvider;
#Mock
ClientCriteria clientCriteria;
#Mock
UserPermissionChecker userPermissionChecker;
#Before
public void setUp() throws BusinessException {
MockitoAnnotations.initMocks(this);
String identityUserToken = "TEST USER";
Mockito.when(userPermissionChecker.checkPermissions(Mockito.any())).thenReturn(identityUserToken);
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void testMockMvc() throws Exception {
String clientId = "1";
String channel = "internet";
String market = "canada";
String transactionStyle = "blah";
String featureSet = "blah_blah";
Client requestedClient = new Client(clientId, channel, market, transactionStyle, featureSet);
ServletContext sc = webApplicationContext.getServletContext();
assertNotNull(sc);
assertTrue(sc instanceof MockServletContext);
ResultActions ra = mockMvc.perform(post("/myapibase/v1/clients")
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(requestedClient))
);
ra.andDo(print());
Controller:
#RestController
#RequestMapping("/myapibase/v1")
public class ClientController {
#Autowired
private Validator validator;
#Autowired
private StorageProvider storageProvider;
#Autowired
private UserPermissionChecker userPermissionChecker;
private String baseUrl;
private static Logger log = LoggerFactory.getLogger(ClientController.class.getName());
#Autowired
public ClientController(String baseUrl) {
this.baseUrl = baseUrl;
}
#RequestMapping(value = "/clients", method = RequestMethod.POST)
public ResponseEntity<?> addClient(#RequestBody #Valid Client clientToAdd, #RequestHeader HttpHeaders headers, #RequestParam Map<String, String> queryParams) {
String methodName = "addClient";
...
}
XML Configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:annotation-config />
<tx:annotation-driven/>
<mvc:annotation-driven/>
<!--<mvc:default-servlet-handler/>-->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:ValidationMessages</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="messageAccessor" class="org.springframework.context.support.MessageSourceAccessor">
<constructor-arg index="0" ref="messageSource"/>
</bean>
</beans>
Application.java
#Configuration
#EnableAutoConfiguration(exclude = MetricRepositoryAutoConfiguration.class)
#EnableAspectJAutoProxy(proxyTargetClass = true)
#EnableServiceFoundation
#ComponentScan(basePackages = { "com.myapp.controllers", "com.myapp.models", "com.myapp.storage", "com.myapp.managers",
"com.myapp.txyz", "com.myapp.util", })
public class Application {
...
}
Log Output:
22:04:30.866 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'org.springframework.web.servlet.support.SessionFlashMapManager'
22:04:30.870 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
22:04:30.871 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'org.springframework.web.servlet.support.SessionFlashMapManager'
22:04:30.871 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Unable to locate FlashMapManager with name 'flashMapManager': using default [org.springframework.web.servlet.support.SessionFlashMapManager#1f7076bc]
22:04:30.871 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Published WebApplicationContext of servlet '' as ServletContext attribute with name [org.springframework.web.servlet.FrameworkServlet.CONTEXT.]
22:04:30.871 [main] INFO o.s.t.w.s.TestDispatcherServlet - FrameworkServlet '': initialization completed in 38 ms
22:04:30.872 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Servlet '' configured successfully
22:04:30.978 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [/myapibase/v1/clients]
22:04:30.981 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /myapibase/v1/clients
22:04:30.982 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Did not find handler method for [/myapibase/v1/clients]
22:04:30.982 [main] WARN o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/myapibase/v1/clients] in DispatcherServlet with name ''
22:04:30.983 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
MockHttpServletRequest:
HTTP Method = POST
Request URI = /myapibase/v1/clients
Parameters = {}
Headers = {Content-Type=[application/json]}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
MockHttpServletResponse:
Status = 404
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []

Related

JUnit, Mockito and Spring ApplicationContext: Trouble mocking a property

Problem description: I have trouble setting up a mock for a particular spring bean to return the correct mock test resource location on my development box, rather than the runtime web application root. I am sure I am doing something silly with my refactoring. I hope someone sees it.
I am using Quartz to execute a job over Spring. The Quartz job is working fine and picking up the Spring applicationcontext ok. The only thing left is to wire up a configuration property for the test or runtime location where the web resources are located. :
JUnit 4, Spring 3.1, Quartz, Java 8, Mockito
The interface:
public interface ITitle {
/**
* Gets the root of the application.
* #return location String
*/
public String getRuntimeLocation();
}
The implementation:
#Component("Title")
public class Title implements ITitle, ApplicationContextAware {
private String location;
/**
* Gets the root of the application.
* #return location String
*/
public String getRuntimeLocation() {
String location = "";
config = getConfig();
log.debug("Class Title --- Method getRuntimeLocation -- config is " + config );
location = config.getRuntimeLocation();
log.debug("Class Title --- Method getRuntimeMethod -- runtime location is " + location );
return location;
}
}
The Unit Test
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.generators.analytics.serialised.ITitle;
import java.io.File;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath*:/WEB-INF/conf/analytics-context.xml"
})
public class GeneratorTest {
private AnalyticsGenerator generator;
#Mock
private IConfig config;
#Mock
private ApplicationContext applicationContext;
#Mock
private ITitle title;
// Set a logger
private static Logger log = LoggerFactory.getLogger(GeneratorTest.class);
private JobExecutionContext job;
/**
* Initialises the test parameters.
*/
#Before
public void setUp() throws Exception {
//create a generator object
generator = new AnalyticsGenerator();
MockitoAnnotations.initMocks(this);
when(applicationContext.getBean("Query")).thenReturn(query);
when(applicationContext.getBean("Config")).thenReturn(config);
when(config.getRuntimeLocation()).thenReturn(“/Users/me/dev/workarea/");
generator.executeInternal(ctx);
}
/**
* Expected: Json exists
*/
#Test
public void testThatExecuteInternalCreatesAJsonFile() throws JobExecutionException {
generator.executeInternal(job);
File returnedJson = new File("classpath:/google-analytics.json");
Assert.assertNotNull("The JSON file does not exist", returnedJson );
}
/**
* Remove objects from memory.
*/
#After
public void tearDown() throws Exception {
generator = null;
}
}
The spring xml file
<?xml version="1.0" encoding="UTF-8"?>
<!--
* analytics-context.xml
*
* resource configuration file for Google Analytics recommendations integration framework.
*
* All custom beans and services must be defined in this file.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">
<context:annotation-config/>
<!--
START Globally used Google Analytics Query parameters
-->
<bean id="Config" class=“com.generators.analytics.Config">
<property name="reportLocation" value="/data/runtime/web/assets/generated-list/google-analytics.json"/>
<property name="runtimeLocation" value="/data/runtime/web/"/>
</bean>
<bean id="configFactory" class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface" value=“com.generators.analytics.ConfigFactory" />
</bean>
<alias name="Config" alias="C" />
<bean id="Title" class=“com.generators.analytics.serialised.Title">
<property name="config" ref="Config"/>
</bean>
<context:component-scan base-package=“com.generators.analytics" />
<!--
END Globally used Google Analytics Query parameters
-->
After running the test I get this in the log:
11:51:43.020 [main] DEBUG com.generators.analytics.serialised.Title - Class Title --- Method getConfig -- applicationContext is org.springframework.context.support.GenericApplicationContext#57f23557: startup date [Tue Jan 24 11:51:31 GMT 2017]; root of context hierarchy
11:51:43.020 [main] DEBUG com.generators.analytics.serialised.Title - Class Title --- Method getConfig -- config is com.generators.analytics.Config#13d9cbf5
11:51:43.020 [main] DEBUG com.generators.analytics.serialised.Title - Class Title --- Method getRuntimeLocation -- config is com.generators.analytics.Config#13d9cbf5
11:51:43.020 [main] DEBUG com.generators.analytics.serialised.Title - Class Title --- Method getRuntimeMethod -- runtime location is /data/runtime/web/
The question is, is there anything obvious that I do wrong to get the intended path /Users/me/dev/workarea/ ?
I guess I need to do refactoring to extract the location from the method ? I am not sure how to refactor this particular step.
when(config.getRuntimeLocation()).thenReturn(“/Users/me/dev/workarea/");
I resolved this problem by creating a copy of the spring configuration file and changing
<bean id="Config" class="com.generators.analytics.Config">
<property name="reportLocation" value="/Users/arnout/dev/soton-test/workarea/assets/generated-list/google-analytics.json"/>
<property name="runtimeLocation" value="/Users/arnout/dev/soton-test/workarea/"/>
</bean>
and then changing
#ContextConfiguration(locations = {
"classpath*:/WEB-INF/conf/livesite_customer/resources/test-analytics-resource-config.xml"
})
public class GeneratorTest {
I did some lateral thinking after I read up on Profiles in Spring configurations. In fact I did not need a profile, it was just as easy as taking another spring configuration in test mode.

Spring integration http testing

I am trying to test the routing I have configured on my http inbound channel. The test is working if I have the following test code:
#Test
public void success() throws JsonProcessingException, ServletException, IOException, Exception {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(createRequest());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setRequestURI("/service/agent/onbreak");
request.setContent(json.getBytes());
request.setContentType("application/json");
Map<String, String> pathVars = new AntPathMatcher().extractUriTemplateVariables(
"/service/agent/{function}", "/service/agent/onbreak");
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, pathVars);
MockHttpServletResponse response = new MockHttpServletResponse();
inboundGateway.handleRequest(request, response);
Assert.assertEquals(HttpStatus.OK.value(), response.getStatus());
verify(mockAgentService, times(1)).onBreak(any(AgentOnBreakRequest.class));
}
My issue with the above method is that I need to apply set the pathVars on the mock request. I have been trying unsuccessfully to use the MockMvc classes. I was at the point where I could submit the json payload successfully however it is not being passed on to the http inbound channel adapter.
Spring config:
<int-http:inbound-channel-adapter channel="http.incoming.agent.request.channel" supported-methods="POST"
path="service/agent/{function}">
<int-http:header name="function" expression="#pathVariables.function"/>
</int-http:inbound-channel-adapter>
<int:router input-channel="http.incoming.agent.request.channel" expression="headers.function">
<int:mapping value="onbreak" channel="asl.agent.convert.on.break" />
</int:router>
<int:json-to-object-transformer input-channel="asl.agent.convert.on.break"
output-channel="asl.agent.request.channel"
type="agent.dto.AgentOnBreakRequest"/>
<int:payload-type-router input-channel="asl.agent.request.channel">
<int:mapping channel="request.asl.agent.on.break" type="com.mhgad.za.vitel.server.agent.dto.AgentOnBreakRequest"/>
</int:payload-type-router>
<int:service-activator input-channel="request.asl.agent.on.break" output-channel="asl.agent.response.channel"
ref="agentService" method="onBreak" />
<bean id="agentService" class="service.agent.impl.AgentServiceImpl"/>
<mvc:annotation-driven/>
<mvc:default-servlet-handler default-servlet-name="AgentService"/>
<mvc:view-controller path="/*" view-name="initialView" />
Test code:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration("test/resources/webapp")
#ContextConfiguration(locations = {"classpath:spring/agent-integration.xml", "classpath:spring/agent-beans.xml",
"classpath:spring/test-router-config.xml"})
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class AgentOnBreakRouteTest {
#Autowired
private WebApplicationContext webCtx;
#Test
public void successful() throws JsonProcessingException, Exception {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(createRequest());
MockMvc mvc = webAppContextSetup(webCtx).build();
mvc.perform(post("service/agent/onbreak").content(json)).andExpect(status().isOk());
}
}
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<servlet>
<servlet-name>aslAgentGateway</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>aslAgentGateway</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
log:
08:55:25.121 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [service/agent/onbreak]
08:55:25.124 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path service/agent/onbreak
08:55:25.124 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Did not find handler method for [service/agent/onbreak]
08:55:25.124 [main] DEBUG o.s.i.h.i.IntegrationRequestMappingHandlerMapping - Looking up handler method for path service/agent/onbreak
08:55:25.125 [main] DEBUG o.s.i.h.i.IntegrationRequestMappingHandlerMapping - Did not find handler method for [service/agent/onbreak]
08:55:25.125 [main] WARN o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI [service/agent/onbreak] in DispatcherServlet with name ''
08:55:25.126 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
Judging from the log, the dispatcher cannot route the request to the inbound channel. Can anyone advise me on how to accomplish this? I have looked through various examples and postings but have come up short so far.

Spring integration mail inbound channel

i'm new to Spring and Spring integration, and i have a simple task to accomplish. Filtering some emails by it's subject though a regex and register some info in the db.
I've set the JavaMailProperties and the test gives me the output of the read emails but the method i'm setting with service-activator is never called and this is actually making me have a strong headache.
The following is the xml configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mail="http://www.springframework.org/schema/integration/mail"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/integration/mail
http://www.springframework.org/schema/integration/mail/spring-integration-mail-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<util:properties id="javaMailProperties">
<prop key="mail.store.protocol">pop3</prop>
<prop key="mail.debug">true</prop>
</util:properties>
<mail:inbound-channel-adapter id="pop3Adapter"
store-uri="pop3://username:password#mail..example.com:110/INBOX"
channel="recieveEmailChannel"
should-delete-messages="false"
auto-startup="true"
java-mail-properties="javaMailProperties"
mail-filter-expression="subject matches '(^Presente+\\s([1-9]{1})+(\\s[-]\\s)+([A-Z]{4,})+(\\s[A-Z]{6,})$)'">
<int:poller max-messages-per-poll="10" fixed-delay="10000"/>
</mail:inbound-channel-adapter>
<int:channel id="recieveEmailChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:logging-channel-adapter id="logger" level="DEBUG"/>
<int:service-activator input-channel="recieveEmailChannel" ref="leggiMail" method="processa_mail"/>
<bean id="leggiMail" class="it.jenia.ac.mail.rapportini.LeggiMail">
</bean>
</beans>
The LeggiMail class with the processa_mail method is very simple:
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.stereotype.Service;
#Service
public class LeggiMail {
private static Logger logger = Logger.getLogger(LeggiMail.class);
public static int count_get = 0;
#ServiceActivator
public void processa_mail(MimeMessage mimeMessage) {
count_get++;
logger.debug("porcessa_mail working");
}
The test class i'm using this application in:
#ContextConfiguration(locations = { "classpath*:/test-spring-configuration.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class LeggiMailTest {
private static Logger logger = Logger.getLogger(LeggiMailTest.class);
#Autowired
LeggiMail lm;
#Test
#Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
public void test_processa_mail(){
logger.debug("Test started");
}
}
The log Test started appears correctly in the console, but the log porcessa_mail working never shows up..
The first tutorial i found on this subject just spoke about a method that would have been called by default by the context. http://blog.solidcraft.eu/2011/04/read-emails-from-imap-with-spring.html (And it says that the method "processa_mail" should be called by default when the context is loaded, cause it's a service-activator.
Reading this tutorial about service activator didn't help enough: http://docs.spring.io/spring-integration/reference/html/messaging-endpoints-chapter.html
When you try to test some async stuff you some barrier to prevent the main thread to be stopped early, than it is neccessary for entire test-case.
The simples way is add Thread.sleep() before the end of test method.
But better solution is based on some synchonizer, like CountDonwLatch.
From other side there is QueueChannel in the Spring Integration. You can use it as an output-channel for <service-activator>. Inject it to the test class and wait on the output.receive(10000). And assert... the result message to make your test realy unit-test.

Jersey + Spring = #Transactional not working

Hello I started an app with Jersey integrated with spring. To test my resources I´m using spring-test, like this:
#ContextConfiguration(locations = { "classpath*:testApplicationContext.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
#TransactionConfiguration(defaultRollback = false) //just to check if txmanager was working
public class UserDAOTest {
#Autowired
private UserDAO dao;
#Autowired
private AuthorizationVerifyer verifyer;
#Before
public void init() {
User user = new User(null, "name", "email", "pass", DateTime.now(), true);
User savedUser = dao.save(user);
assertNotNull(savedUser);
assertNotNull(savedUser.getId());
}
the problem is that all my tests break in the #Before method. Why? Because the User ID is null.
Lets go over my testApplicationContext.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.sifionsolution.sig.authorization" />
<!-- Inject properties -->
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>testDatabase.properties</value>
</list>
</property>
</bean>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</bean>
<!-- JPA EntityManagerFactory -->
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
depends-on="flyway">
<property name="dataSource" ref="dataSource" />
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" />
</property>
<property name="packagesToScan">
<list>
<value>com.sifionsolution.sig.authorization.entity</value>
</list>
</property>
</bean>
<!-- Transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<bean id="flyway" class="org.flywaydb.core.Flyway" init-method="migrate">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
My UserDAO class:
#Component
public class UserDAO {
private GenericDAO<Long, User> dao;
#PersistenceContext
private EntityManager manager;
#Transactional
User save(User user) {
return dao.save(user);
}
...
Can some one help me to get this working?
thank you
EDIT Adding some of the Console logs:
13/10/14 14:16:50 INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader:315
Loading XML bean definitions from URL [file:/D:/workspace/sig-authorization-jax-rs/bin/testApplicationContext.xml]
13/10/14 14:16:50 INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader:315
Loading XML bean definitions from URL [file:/D:/workspace/sig-authorization-jax-rs/bin/testApplicationContext.xml]
13/10/14 14:16:50 INFO org.springframework.context.annotation.ClassPathBeanDefinitionScanner:231
JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
13/10/14 14:16:50 INFO org.springframework.context.annotation.ClassPathBeanDefinitionScanner:231
JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
13/10/14 14:16:50 INFO org.springframework.context.annotation.ClassPathBeanDefinitionScanner:239
JSR-330 'javax.inject.Named' annotation found and supported for component scanning
13/10/14 14:16:50 INFO org.springframework.context.annotation.ClassPathBeanDefinitionScanner:239
JSR-330 'javax.inject.Named' annotation found and supported for component scanning
13/10/14 14:16:50 INFO org.springframework.context.support.GenericApplicationContext:510
Refreshing org.springframework.context.support.GenericApplicationContext#162cc04e: startup date [Mon Oct 13 14:16:50 BRT 2014]; root of context hierarchy
13/10/14 14:16:50 INFO org.springframework.context.support.GenericApplicationContext:510
Refreshing org.springframework.context.support.GenericApplicationContext#162cc04e: startup date [Mon Oct 13 14:16:50 BRT 2014]; root of context hierarchy
13/10/14 14:16:50 INFO org.springframework.beans.factory.config.PropertyPlaceholderConfigurer:172
Loading properties file from class path resource [testDatabase.properties]
13/10/14 14:16:50 INFO org.springframework.beans.factory.config.PropertyPlaceholderConfigurer:172
Loading properties file from class path resource [testDatabase.properties]
13/10/14 14:16:50 INFO org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor:141
JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
13/10/14 14:16:50 INFO org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor:141
JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
13/10/14 14:16:50 INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean:287
Building JPA container EntityManagerFactory for persistence unit 'default'
13/10/14 14:16:50 INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean:287
Building JPA container EntityManagerFactory for persistence unit 'default'
13/10/14 14:16:51 INFO org.springframework.beans.factory.support.DefaultListableBeanFactory:603
Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#247fd5c5: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,tokenDAO,userDAO,tokenCreator,tokenValidator,authorizationVerifyer,authenticatedUserBuilder,permissionBuilder,roleWrapperBuilder,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,dataSource,emf,transactionManager,flyway,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
13/10/14 14:16:51 INFO org.springframework.beans.factory.support.DefaultListableBeanFactory:603
Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#247fd5c5: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,tokenDAO,userDAO,tokenCreator,tokenValidator,authorizationVerifyer,authenticatedUserBuilder,permissionBuilder,roleWrapperBuilder,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,dataSource,emf,transactionManager,flyway,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
13/10/14 14:16:51 INFO org.springframework.context.support.GenericApplicationContext:1042
Closing org.springframework.context.support.GenericApplicationContext#162cc04e: startup date [Mon Oct 13 14:16:50 BRT 2014]; root of context hierarchy
13/10/14 14:16:51 INFO org.springframework.context.support.GenericApplicationContext:1042
Closing org.springframework.context.support.GenericApplicationContext#162cc04e: startup date [Mon Oct 13 14:16:50 BRT 2014]; root of context hierarchy
13/10/14 14:16:51 INFO org.springframework.beans.factory.support.DefaultListableBeanFactory:444
Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#247fd5c5: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,tokenDAO,userDAO,tokenCreator,tokenValidator,authorizationVerifyer,authenticatedUserBuilder,permissionBuilder,roleWrapperBuilder,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,dataSource,emf,transactionManager,flyway,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
13/10/14 14:16:51 INFO org.springframework.beans.factory.support.DefaultListableBeanFactory:444
Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#247fd5c5: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,tokenDAO,userDAO,tokenCreator,tokenValidator,authorizationVerifyer,authenticatedUserBuilder,permissionBuilder,roleWrapperBuilder,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,dataSource,emf,transactionManager,flyway,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
13/10/14 14:16:51 INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean:441
Closing JPA EntityManagerFactory for persistence unit 'default'
13/10/14 14:16:51 INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean:441
Closing JPA EntityManagerFactory for persistence unit 'default'
EDIT 2 After putting Transactional annotation in my test class I got:
Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener#47b42535] to process 'after' execution for test: method [public void com.sifionsolution.sig.authorization.dao.UserDAOTest.shouldLogInActiveUser()], instance [com.sifionsolution.sig.authorization.dao.UserDAOTest#3f6df5a], exception [java.lang.AbstractMethodError: org.joda.time.contrib.hibernate.PersistentDateTime.nullSafeSet(Ljava/sql/PreparedStatement;Ljava/lang/Object;ILorg/hibernate/engine/spi/SessionImplementor;)V]
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:522)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:591)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:297)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:192)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:406)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:91)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:92)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:513)
... 25 more
Caused by: org.hibernate.AssertionFailure: null id in com.sifionsolution.sig.authorization.entity.User entry (don't flush the Session after an exception occurs)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:79)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:194)
EDIT 3 GenericDAO
public class GenericDAO<PK, T> {
private final EntityManager entityManager;
private final Class<?> clazz;
public GenericDAO(Class<?> clazz, EntityManager entityManager) {
this.clazz = clazz;
this.entityManager = entityManager;
}
#SuppressWarnings("unchecked")
public T getById(PK pk) {
return (T) entityManager.find(clazz, pk);
}
public T save(T entity) {
entityManager.persist(entity);
return entity;
}
public void update(T entity) {
entityManager.merge(entity);
}
public void delete(T entity) {
entityManager.remove(entity);
}
#SuppressWarnings("unchecked")
public List<T> findAll() {
return entityManager.createQuery(("FROM " + clazz.getName() + " obj")).getResultList();
}
public List<?> listByHql(String hql, HqlParameter... params) {
Query query = entityManager.createQuery(hql);
for (HqlParameter param : params)
param.apply(query);
return query.getResultList();
}
public Object uniqueResultByHql(String hql, HqlParameter... params) {
Query query = entityManager.createQuery(hql);
for (HqlParameter param : params)
param.apply(query);
try {
return query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
}
EDIT 4 User entity code
#Entity
#Table(name = "tb_user")
#XmlRootElement
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String password;
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime registration;
#Column(columnDefinition = "TINYINT(1)")
private Boolean active;
#OneToMany(mappedBy = "user")
private List<UserRole> userRoles;
#OneToMany(mappedBy = "user")
private Set<UserPermission> userPermissions;
public User() {
}
EDIT 5 database
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| password | varchar(128) | NO | | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
| active | tinyint(1) | NO | | NULL | |
| registration | datetime | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
6 rows in set (0.04 sec)
EDIT 6 I changed this line:
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
And now I´m getting another exception:
java.lang.AbstractMethodError: org.joda.time.contrib.hibernate.PersistentDateTime.nullSafeSet(Ljava/sql/PreparedStatement;Ljava/lang/Object;ILorg/hibernate/engine/spi/SessionImplementor;)V
at org.hibernate.type.CustomType.nullSafeSet(CustomType.java:155)
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2602)
Summary of chat discussion
Adding #Transactional to test class
Adding transactionManager in #TransactionConfiguration
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#Transactional
//Test Class
Some forum suggest to use Jadira
with this annotation
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTimeWithZone")

Hibernate Unresponsive with Spring-WS

I have a single-context Spring-WS application (that is, there is only one file in my project that contains definitions), something-servlet.xml. When I call persist through my DAOs, no entries are getting created in my database. I'm also not getting any exceptions thrown.
If there is any more information I've left out that'd be helpful in determining the issue, please let me know. Thanks.
something-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.abc.direct.mailserver" />
<context:property-placeholder location="classpath:manager.properties" />
<sws:annotation-driven />
<sws:dynamic-wsdl id="manager" portTypeName="AbcDirect"
locationUri="/mailerManagerService/" targetNamespace="http://ecsdfsds.com/direct/definitions">
<sws:xsd location="/WEB-INF/mailManagerRequest.xsd" />
</sws:dynamic-wsdl>
<bean id="mailServerPersistenceManager"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="directMailDataSource" />
<property name="packagesToScan" value="com.abc.direct.mailserver.dao"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="directMailDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driverClassName}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
</bean>
</beans>
Dao Classes:
#Entity
#Table(name="virtualusertable")
public class VirtualUser {
#Id
#Column(name="user")
private String user;
// private String domain;
// private String targetAddress;
public VirtualUser(String username) {
this.user = username;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
#Component
public class VirtualUsers {
#PersistenceContext
EntityManager entityManager;
public void save(VirtualUser user) {
this.entityManager.persist(user);
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
Endpoint:
#Endpoint
public class MailManagerEndpoint {
private static final String NAMESPACE_URI = "http://asfsdfs.com/direct/schemas";
static final Namespace NAMESPACE = Namespace.getNamespace(NAMESPACE_URI);
private MailManagerService service;
#Autowired
private VirtualUsers virtualUsers;
#Autowired
public MailManagerEndpoint(MailManagerService mailManagerService) {
this.service = mailManagerService;
}
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "MailManagerRequest")
public #ResponsePayload Element handleRequest(#RequestPayload Element element) throws JDOMException, IOException {
VirtualUser user = new VirtualUser("newuser");
virtualUsers.save(user);
return new Element("success");
}
}
Startup logs: http://pastebin.com/9Z6MWRSG
Transaction logs: http://pastebin.com/ZFEC0EMJ
In the startup logs, I"m really curious as to why this block repeats itself like 7 times:
2014-04-25 10:34:03,634 DEBUG EntityLoader:146 - Static select for entity com.abc.direct.mailserver.dao.VirtualUser [READ]: select virtualuse0_.user as user1_0_0_ from virtualusertable virtualuse0_ where virtualuse0_.user=?
2014-04-25 10:34:03,635 DEBUG QuerySpacesImpl:177 - Adding QuerySpace : uid = <gen:0> -> org.hibernate.loader.plan.build.internal.spaces.EntityQuerySpaceImpl#e58a68d]
2014-04-25 10:34:03,635 DEBUG FetchStyleLoadPlanBuildingAssociationVisitationStrategy:94 - Building LoadPlan...
2014-04-25 10:34:03,635 DEBUG LoadQueryJoinAndFetchProcessor:111 - processing queryspace <gen:0>
2014-04-25 10:34:03,636 DEBUG LoadPlanTreePrinter:72 - LoadPlan(entity=com.abc.direct.mailserver.dao.VirtualUser)
- Returns
- EntityReturnImpl(entity=com.abc.direct.mailserver.dao.VirtualUser, querySpaceUid=<gen:0>, path=com.abc.direct.mailserver.dao.VirtualUser)
- QuerySpaces
- EntityQuerySpaceImpl(uid=<gen:0>, entity=com.abc.direct.mailserver.dao.VirtualUser)
- SQL table alias mapping - virtualuse0_
- alias suffix - 0_
- suffixed key columns - {user1_0_0_}
UPDATE:
persist() output after adding #Transactional and :
2014-04-25 11:24:47,517 DEBUG SharedEntityManagerCreator$SharedEntityManagerInvocationHandler:253 - Creating new EntityManager for shared EntityManager invocation
2014-04-25 11:24:47,950 DEBUG AbstractSaveEventListener:130 - Generated identifier: newuser, using strategy: org.hibernate.id.Assigned
2014-04-25 11:24:48,011 DEBUG EntityManagerFactoryUtils:435 - Closing JPA EntityManager
If you want to insert data to DB, you need a transaction. In order for Spring to provide a transaction, you need to put <tx:annotation-driven /> to your Spring context file, and put #Transactional annotation on the method that you insert data to DB. This way, Spring initiates a transaction for you as the method execution starts, and commits it when the method execution comes to an end (or rolls it back if an exception is thrown).

Categories

Resources