my phrases is to check my controller, how does it serialize exceptions, while I am using javax.validation( JSR 380 )
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:application-context-test.xml"})
#WebAppConfiguration
public class MyDTOControllerIT {
private MockMvc mockMvc;
#Mock private MyService myService;
#Mock private MyDTOService myDTOService;
private ObjectMapper objectMapper;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc =
MockMvcBuilders.standaloneSetup(MyController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.setViewResolvers(
(ViewResolver) (viewName, locale) -> new MappingJackson2JsonView())
.build();
objectMapper = new CustomObjectMapper();
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
#Test
public void create_Illegal() throws Exception {
W req;
try (InputStream jsonInputStream1 =
this.getClass().getResourceAsStream(IILEGAL_REQ_BODY)) {
req = objectMapper.readValue(jsonInputStream1, MyDto.class);
}
mockMvc
.perform(
MockMvcRequestBuilders.post(
"/v1/somthing")
.content(objectMapper.writeValueAsString(req))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().string(containsString("\"pid\":123456")))
.andDo(MockMvcResultHandlers.print());
}
}
dto
public class W{
#NotNull(message = "xxxxxx") private String name;
}
class MyDTOController ...
#PostMapping(value = "/v1/somthing")
#RequestBody #Validated W value){
}
so I would like W to get violated ...
this is my test context
<?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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<context:component-scan
base-package="my.package">
<context:annotation-config/>
<mvc:annotation-driven>
<mvc:message-converters>
<bean id="jacksonMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
<mvc:argument-resolvers>
<ref bean="sortResolver"/>
<ref bean="pageableResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
<bean id="objectMapper" class="my.package.CustomObjectMapper"/>
<bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource"
p:basenames="WEB-INF/i18n/messages" p:fallbackToSystemLocale="false"/>
<context:exclude-filter type="assignable"
expression="my.package.MyDTOController"/>
what I an getting in the end is
Resolved Exception:
Type = org.springframework.web.bind.MethodArgumentNotValidException
MockHttpServletResponse:
Status = 400
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null Redirected URL = null
I have all the right validator dependencies
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<hibernate-validator.version>4.1.0.Final</hibernate-validator.version>
I also have
public class ControllerExceptionHandler extends ResponseEntityExceptionHandler
Which is being scanned in (exist in my.package )
org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
has
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request)
when I put a breakpoint there it's not being caught,
what can I do to get the right error messages?
mockMvc =
MockMvcBuilders.standaloneSetup(MyController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.setViewResolvers((ViewResolver) (viewName, locale) -> new MappingJackson2JsonView())
.setControllerAdvice(controllerExceptionHandler)
.build();
the
.setControllerAdvice(controllerExceptionHandler)
solved it .
Related
Have a codebase which uses SpringMVC 4.0.3.RELEASE for Restful Web Services.
Codebase contains a fully functional Restful Web Service which I can verify works using postman and curl.
However, when trying to write a unit test for the particular Restful Web Service using MockMvc, I become blocked with trying to obtain the JSON content from the unit test.
Am wondering if its a config issue or an issue where I am not creating a fake object correctly (since this doesn't rely on tomcat and is standalone).
pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.0.3.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- A bunch of other Spring libs omitted from this post -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>0.9.1</version>
<scope>test</scope>
</dependency>
WebConfig:
package com.myapp.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#EnableWebMvc
#Configuration
#ComponentScan("com.myapp.rest")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
}
ServletInitializer:
package com.myapp.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.myapp.config.WebConfig;
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
}
UserController:
#RestController
#RequestMapping("/v2")
public class UserController {
private final UserDAO dao;
private HttpHeaders headers = null;
#Autowired
public UserController(UserDAO dao) {
this.dao = dao;
headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
}
#RequestMapping(value = "users/{appId}", method = RequestMethod.GET, produces="application/json")
#ResponseBody
public ResponseEntity<Object> getUserDetails(#PathVariable String appId) {
Object jsonPayload = dao.getUser(appId);
return new ResponseEntity<Object>(jsonPayload, headers, HttpStatus.OK);
}
}
UserDAO:
#Repository
public class UserDAO {
private JdbcTemplate jdbcTemplate;
#Autowired
public UserDAO(#Qualifier("dataSourceDB") DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// Finders methods (such as the getUser(appId)) which use Spring JDBC
}
WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>MyApp</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
</web-app>
WEB-INF/mvc-dispatcher-servlet.xml:
<beans xmlns="http://www.springframework.org/schema/beans">
<import resource="classpath:database.xml" />
<context:component-scan base-package="com.myapp.rest" />
<mvc:annotation-driven />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
src/main/resources/database.xml:
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="dataSourceDB" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>${jdbc.driver}</value></property>
<property name="url"><value>${db.url}</value></property>
<property name="username"><value>${db.username}</value></property>
<property name="password"><value>${db.password}</value></property>
</bean>
</beans>
My actual unit test:
package com.myapp.rest.controllers;
RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:**/mvc-dispatcher-servlet.xml")
#WebAppConfiguration
public class UserControllerTest {
private MockMvc mockMvc;
#Mock
private UserDAO dao;
#InjectMocks
private UserController controller;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void getUserDetails() throws Exception {
String appId = "23bdr4560l";
mockMvc.perform(get("/v2/users/{appId}",appId)
.accept(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print());
}
}
When I invoke my build locally:
mvn clean install
Generated output to stdout:
Running com.myapp.rest.controllers.UserControllerTest
MockHttpServletRequest:
HTTP Method = GET
Request URI = /v2/users/23bdr4560l
Parameters = {}
Headers = {Accept=[application/json]}
Handler:
Type = com.myapp.rest.controllers.UserController
Method = public org.springframework.http.ResponseEntity<java.lang.Object> com.myapp.rest.controllers.UserController.getUserDetails(java.lang.String)
Async:
Was async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[application/json]}
Content type = application/json
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.728 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
Notice how the JSON body part is empty / null:
Body =
So, when trying to access the JSON payload using jsonPath:
#Test
public void getUserDetails() throws Exception {
String appId = "23bdr4560l";
mockMvc.perform(get("/v2/users/{appId}",appId)
.accept(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andDo(print());
}
Received the following error:
Results :
Tests in error:
getUserDetails(com.myapp.rest.controllers.UserControllerTest): json can not be null or empty
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0
What am I possbily doing wrong?
Obviously, I need to mock out the response but have Googled this and others using MockMvc were able to obtain a JSON their test.
Is this a config issue (do I need to put some type of annotation for my unit test)?
Do, I need to instantiate the controller inside my test?
What weird is that the actual Rest Call works (returns a valid JSON) using postman and curl...
This codebase does not have an #Service class / layer, its just #RestController speaking to #Repository (see above).
Really thought that testing support for Spring MVC based Restful Web Services would be a lot easier.
Am running out of ideas...
Any help would me most appreciated...
When you are trying to mock the bean like this, it tries to create the mock with the default constructor.
#Mock
private UserDAO dao
It works in case of actual rest call because you provide the dependent DataSource dataSource at runtime. Providing a valid dependent mock for the UserDAO class works.
Since you are mocking the UserDAO you need to provide some mock expectations for the call:
Object jsonPayload = dao.getUser(appId);
Inside your Controller or it will return null by default. To do this use the Mockito.when() method inside your test prior to the MockMvc call:
when(dao.getUser(anyString())).thenReturn(json)
where json is some hard coded json Object you set up yourself.
For starters, since you're using MockMvcBuilders.standaloneSetup(...) you are in fact not using the Spring TestContext Framework (TCF) to load your WebApplicationContext. So just completely delete the following declarations in your test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:**/mvc-dispatcher-servlet.xml")
#WebAppConfiguration
Also, you can completely ignore your XML configuration files since they are not used without a WebApplicationContext.
As an aside, web.xml and Servlet initializers are never used by the TCF, so you can ignore them as well.
Then, as mentioned by #Plog, you'll need to set up the expectations for your mocked UserDAO; otherwise, the invocation of dao.getUser(appId) always returns null which results in an empty response body.
Regards,
Sam (author of the Spring TestContext Framework)
I am facing issues with #PreAuthorize annotation. There are two things to be done.
Retrieving all employees should be done by one who has the authority USER or ADMIN.
Deleting employee should be done by one with authority only ADMIN.
I need to use method level authorization with spring-security-4.
User.java
package com.nikunj.SpringMethodLevelAuthorization;
public class user {
int id;
String firstName;
String type;
public user(int id, String firstName, String type){
this.id = id;
this.firstName = firstName;
this.type = type;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
userService.java
package com.nikunj.SpringMethodLevelAuthorization;
import java.util.Vector;
import org.springframework.security.access.prepost.PreAuthorize;
public interface userService {
#PreAuthorize("hasRole('ADMIN')")
public void deleteUser(int id);
#PreAuthorize("hasRole('ADMIN') or hasRole('USER')")
public Vector<user> getAllUsers();
}
userImplementation.java
package com.nikunj.SpringMethodLevelAuthorization;
import java.util.Vector;
public class userImplementation implements userService {
Vector<user> users;
public userImplementation(){
users = new Vector<user>();
users.add(new user(1,"Nikunj","SE"));
users.add(new user(2,"Abdul","SSE"));
users.add(new user(3,"Mrinal","LSE"));
users.add(new user(4,"Anurag","SE"));
users.add(new user(5,"Naresh","LSE"));
users.add(new user(6,"Mahesh","SE"));
}
public user findById(int id){
for(user u : users){
if(u.getId()==id){
return u;
}
}
return null;
}
public Vector<user> getAllUsers(){
return users;
}
public void deleteUser(int id){
user u = findById(id);
users.remove(u);
}
}
homeController.java
package com.nikunj.SpringMethodLevelAuthorization;
import java.util.Vector;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class HomeController {
userImplementation ui=new userImplementation();
Vector<user> users;
#RequestMapping(value = { "/users" },method = RequestMethod.GET)
public String getAllUsers(Model model) {
System.out.println("in getAll()");
users=ui.getAllUsers();
model.addAttribute("users", users);
return "allUsers";
}
#RequestMapping(value = { "/delete/{id}" }, method = RequestMethod.GET)
public String deleteUser(#PathVariable int id,Model model){
System.out.println("in delete()");
ui.deleteUser(id);
users=ui.getAllUsers();
model.addAttribute("users", users);
return "allUsers";
}
}
dispatcher-servlet.xml
<?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"
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">
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<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>
<context:component-scan base-package="com.nikunj.SpringMethodLevelAuthorization" />
</beans:beans>
spring-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<http auto-config="true">
<intercept-url pattern="/" access="hasRole('USER') or hasRole('ADMIN')" />
</http>
<!-- Eable method level security -->
<global-method-security pre-post-annotations="enabled"/>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="abdul" password="root123" authorities="ROLE_ADMIN"/>
<user name="nikunj" password="secret" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- Processes application requests -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/dispatcher-servlet.xml
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring Security Configuration -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Make userImplementation as a Spring bean and inject it into the HomeController either by annotation or by define it in xml.
<beans:bean name="userService" class="com.nikunj.SpringMethodLevelAuthorization.userImplementation" />
OR
#Service
public class userImplementation implements userService {
....
....
}
Then autowire it in HomeController.
#Controller
public class HomeController {
//userImplementation ui=new userImplementation();
#Autowired
UserService ui;
......
......
}
No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
when I do a test with JUnit, persist method works and I see that my object is inserted, but when I call the method via my Controller doesn't work
here is my Project :
applicationContext.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:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.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-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- <bean id="notification" class="com.app.sqli.notification.NotificationTask" /> -->
<!-- <task:scheduled-tasks> -->
<!-- <task:scheduled ref="notification" method="notifier" cron="*/2 * * * * *"/> -->
<!-- </task:scheduled-tasks> -->
<context:component-scan base-package="com.app.sqli" />
<mvc:annotation-driven />
<bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.app.sqli.entities" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/sqli" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryBean" />
</bean>
<tx:annotation-driven />
</beans>
my Model Class:
package com.app.sqli.models;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Collaborateur {
#Id
private int id;
private String nom;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
}
my DAO Class
package com.app.sqli.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import com.app.sqli.models.Collaborateur;
#Repository
public class CollaborateurDao implements IcollaborateurDao{
#PersistenceContext
private EntityManager em;
#Override
public void addCollaborateur(Collaborateur c) {
em.persist(c);
}
}
My Service Class
package com.app.sqli.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.app.sqli.dao.IcollaborateurDao;
import com.app.sqli.models.Collaborateur;
#Service
#Transactional
public class CollaborateurService implements IcollaborateurService{
#Autowired
private IcollaborateurDao cdao;
#Override
public void addCollaborateur(Collaborateur c) {
cdao.addCollaborateur(c);
}
}
And My Controller
package com.app.sqli.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.app.sqli.models.Collaborateur;
import com.app.sqli.services.IcollaborateurService;
#org.springframework.stereotype.Controller
public class Controller {
#Autowired
private IcollaborateurService cserv;
#RequestMapping(value = "/index")
public String index(Model m) {
System.out.println("insertion ...");
Collaborateur c = new Collaborateur();
c.setId(11);
c.setNom("nom");
cserv.addCollaborateur(c);
return "index";
}
}
thank you #mechkov for your time and help,
My problem is resolved by changing my configuration file, so I have used a Configuration Class with annotations and its works so fine, I still Don't know where the problem was
#Configuration
#ComponentScan(basePackages = "your package")
#EnableTransactionManagement
public class DatabaseConfig {
protected static final String PROPERTY_NAME_DATABASE_DRIVER = "com.mysql.jdbc.Driver";
protected static final String PROPERTY_NAME_DATABASE_PASSWORD = "password";
protected static final String PROPERTY_NAME_DATABASE_URL = "jdbc:mysql://localhost:3306/databasename";
protected static final String PROPERTY_NAME_DATABASE_USERNAME = "login";
private static final String PROPERTY_PACKAGES_TO_SCAN = "where your models are";
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter){
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
entityManagerFactoryBean.setPackagesToScan(PROPERTY_PACKAGES_TO_SCAN);
return entityManagerFactoryBean;
}
#Bean
public BasicDataSource dataSource(){
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(PROPERTY_NAME_DATABASE_DRIVER);
ds.setUrl(PROPERTY_NAME_DATABASE_URL);
ds.setUsername(PROPERTY_NAME_DATABASE_USERNAME);
ds.setPassword(PROPERTY_NAME_DATABASE_PASSWORD);
ds.setInitialSize(5);
return ds;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter(){
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabase(Database.MYSQL);
adapter.setShowSql(true);
adapter.setGenerateDdl(true);
//I'm using MySQL5InnoDBDialect to make my tables support foreign keys
adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");
return adapter;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
I do not know if anyone who is reading this (today) has the same case as mine, but I had the same problem. Luckly, I could fix it by simply putting the following in my spring-conf.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
...
xmlns:tx="http://www.springframework.org/schema/tx"
...
xsi:schemaLocation="
...
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="tManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<!-- This does the trick! -->
<tx:annotation-driven transaction-manager="tManager" />
Note: I'm using declarative transactions through annotations. So, if you do, annotating your method with #Transactional can also solve your problem.
REFERENCE:
http://blog.jhades.org/how-does-spring-transactional-really-work/
http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/transaction.html
Just to confirm, that adding last bean definition solves this issue !
My config class is as below :
#Configuration
#EnableTransactionManagement
#ComponentScan
public class OFSConfig {
#Bean
public IDAO<FuelStation> getFSService() {
return new FSService();
}
#Bean
public LocalEntityManagerFactoryBean emfBean() {
LocalEntityManagerFactoryBean e = new LocalEntityManagerFactoryBean();
e.setPersistenceUnitName("org.superbapps.db_OWSDB_PU");
return e;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory em) {
return new JpaTransactionManager(em);
}
}
The service itself is as follows :
#Transactional
#Repository
public class FSService implements IDAO<FuelStation> {
#PersistenceContext
private EntityManager EM;
public EntityManager getEM() {
return EM;
}
public void setEM(EntityManager EM) {
this.EM = EM;
}
#Override
public List<FuelStation> getAll() {
return EM.createNamedQuery("FuelStation.findAll")
.getResultList();
}
#Override
public FuelStation getByID(String ID) {
FuelStation fs = (FuelStation) EM.createNamedQuery("FuelStation.findById")
.setParameter("id", ID)
.getSingleResult();
return fs;
}
#Override
public void update(FuelStation entity) {
EM.merge(entity);
}
}
When i create MockMvc for restful-webservice testing with spring MVC 3.2.3 using WebApplicationContext like this:
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
// ...
}
Then when i run my test, it will fail with return code 404 and my log says that
Did not find handler method for [my/path]
But if i change to this way
public class MyWebTests {
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
}
// ...
}
Then my test will run well without any error.
The only difference i know is that if i use WebApplicationContext to create MockMvc then it will load my Spring Confuguration, while if i use Controller then it will not.
What can possibly cause that error (did not find handler method ...) in my case?
EDIT
My test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:restful-test-context.xml")
#WebAppConfiguration
public class TestSourceController {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
private ObjectMapper mapper;
#Autowired
DeviceDAO deviceDAO;
#AfterClass
public static void tearDownAfterClass() throws Exception {
}
#Before
public void setUp() throws Exception {
Mockito.reset(deviceDAO);
mockMvc = MockMvcBuilders.standaloneSetup(new SourceController()).build();
mapper = new ObjectMapper();
}
#After
public void tearDown() throws Exception {
}
#Test
public void testGetAllDevice() throws UnsupportedEncodingException,
Exception {
Device device1 = new Device();
device1.setId("switch1");
device1.setIsRoot(true);
device1.setName("switch1");
device1.setStatus("ONLINE");
device1.setType("SWITCH");
Device device2 = new Device();
device2.setId("switch2");
device2.setIsRoot(true);
device2.setName("switch2");
device2.setStatus("OFFLINE");
device2.setType("SWITCH");
List<Device> devices = Arrays.asList(device1, device2);
when(deviceDAO.getAllDevices()).thenReturn(devices);
String expected = mapper.writeValueAsString(devices);
String result = mockMvc
.perform(get("/api/devices").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andReturn().getResponse()
.getContentAsString();
verify(deviceDAO).getAllDevices();
assertEquals(expected, result);
}
}
My Controller
#Controller
public class SourceController {
private static final Logger logger = LoggerFactory.getLogger("SourceController");
#RequestMapping(value = "/api/devices", method = RequestMethod.GET)
#ResponseBody
public List<Device> getAllDevice() {
DeviceDAO deviceDAO = AppContext.getService(DeviceDAO.class,
"deviceDAO");
logger.info("The deviceDAO is" + deviceDAO.toString() + "!");
return deviceDAO.getAllDevices();
}
}
My web.xml
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Spring Web MVC Application</display-name>
<servlet>
<servlet-name>nhduc-training-app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>nhduc-training-app</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/nhduc-training-app-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
My restful-test-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:oxm="http://www.springframework.org/schema/oxm"
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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd">
<context:annotation-config />
<mvc:annotation-driven />
<context:component-scan base-package="com.tma.nhduc.controller" />
<bean id="daoUtils" class="com.tma.nhduc.dao.DAOUtils" />
<bean id="counterService" class="com.tma.nhduc.dao.SequenceService" />
<bean id="portDAO" class="com.tma.nhduc.dao.PortDAO" />
<bean id="alarmDAO" class="com.tma.nhduc.dao.AlarmDAO" />
<bean id="deviceDAO" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.tma.nhduc.dao.DeviceDAO"></constructor-arg>
</bean>
<bean id="appContext" class="com.tma.nhduc.ctx.AppContext" />
<mongo:mongo host="localhost" port="27017" />
<mongo:db-factory dbname="nms" mongo-ref="mongo" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
</bean>
MockMvc expect Controller class initialization.See how i have done this.
#InjectMocks
private SampleController controller = new SampleController();
#Before
public void before() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.dispatchOptions(true).build();
}
When i tried to connect my Cloud SQL via JPA the following error is generated :
2012-10-25 10:07:38.439
Error for /jpatest
java.lang.NoClassDefFoundError: Could not initialize class com.my.jpa.EMF
at com.my.jpa.ContactService.createContact(ContactService.java:20)
at com.my.jpa.JPATestServlet.doGet(JPATestServlet.java:14)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
2012-10-25 10:07:38.440
Uncaught exception from servlet
java.lang.NoClassDefFoundError: Could not initialize class com.my.jpa.EMF
at com.my.jpa.ContactService.createContact(ContactService.java:20)
at com.my.jpa.JPATestServlet.doGet(JPATestServlet.java:14)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
My EMF Class is
public final class EMF {
private static final EntityManagerFactory emfInstance = Persistence
.createEntityManagerFactory("JPATest");
private EMF() {
}
public static EntityManagerFactory get() {
return emfInstance;
}
}
EMF initialising portion is
public class ContactService {
private static Logger logger = Logger.getLogger(ContactService.class
.getName());
public void createContact(Contact c) {
logger.info("Entering createContact: [" + c.getFirstName() + ","
+ c.getLastName() + "]");
EntityManager mgr = EMF.get().createEntityManager();
try {
mgr.getTransaction().begin();
mgr.persist(c);
mgr.getTransaction().commit();
} finally {
mgr.close();
}
logger.info("Exiting createContact");
}
}
My Servlet is :
public class JPATestServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
ContactService service = new ContactService();
service.createContact(new Contact("Manu", "Mohan", "686019", "TVM"));
resp.setContentType("text/plain");
resp.getWriter().println("Hello, world");
}
}
web.xml is
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
<servlet-name>JPATest</servlet-name>
<servlet-class>com.my.jpa.JPATestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>JPATest</servlet-name>
<url-pattern>/jpatest</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="JPATest">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.my.jpa.Contact</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.google.cloud.sql.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:google:rdbms://instance-name/stock" />
<property name="javax.persistence.jdbc.user" value="" />
<property name="javax.persistence.jdbc.password" value="" />
<!-- EclipseLink should create the database schema automatically -->
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode"
value="database" />
</properties>
</persistence-unit>
</persistence
Do you need to use final for EntityManagerFactory in EMF. Try to use Singleton Design Pattern for EMF. EntityManagerFactory class is thread-safe.
EMF.java
public final class EMF {
private EntityManagerFactory emfInstance;
private static EMF emf;
private EMF() {
}
public EntityManagerFactory get() {
if(emfInstance == null) {
emfInstance = Persistence.createEntityManagerFactory("JPATest");
}
return emfInstance;
}
public static EMF getInstance() {
if(emf == null) {
emf = new EMF();
}
return emf;
}
}
// usages
EntityManagerFactory emf = Emf.getInstance().get();
Here better way to use EntityManagerFactory in web applicaiton.