I have controller
#Controller
public class AuthorController {
#Autowired
private AuthorDAO authorDao;
#RequestMapping("/authors")
public String showAuthor(#RequestParam String name, ModelMap model) {
Author author = authorDao.findByName(name);
model.addAttribute("author", author);
return "authors";
}
}
I wrote test for it
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:test-application-context.xml"})
public class AuthorControllerTest {
private static final String JACK_C = "Jack C.";
#Autowired
AuthorController controller;
#Test
public void testShowAuthor() {
Author expectedAuthor = new Author();
AuthorDAO daoMock = mock(AuthorDAO.class);
when(daoMock.findByName(JACK_C)).thenReturn(expectedAuthor);
ModelMap model = new ModelMap();
String view = controller.showAuthor(JACK_C, model);
assertEquals("View name is incorrect","authors", view);
assertSame(expectedAuthor, model.get("author"));
verify(daoMock).findByName(JACK_C);
}
}
test-application-context.xml:
<context:annotation-config />
<context:component-scan base-package="com.github.futu" />
<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/blog" /> <property name="username"
value="blogger" /> <property name="password" value="blogger" /> </bean>
<bean id="com.github.futu.dao.AuthorDAO" class="com.github.futu.dao.impl.AuthorDAOXml"/>
<bean id="com.github.futu.dao.PostDAO" class="com.github.futu.dao.impl.PostDAOXml" />
<bean id="validator" class="com.github.futu.validator.PostValidator" />
But real dao is called. What have I missed?
You're creating a mock here
AuthorDAO daoMock = mock(AuthorDAO.class);
that is completely unrelated to your controller injected into your test class
#Autowired
AuthorController controller;
Of course the autowired AuthorDao target is going to come from your XML configuration
#Autowired
private AuthorDAO authorDao;
Ideally you would change your XML configuration only produce a #Controller bean and add a setter to it to set the AuthorDao from within the test, using your mock.
Related
I have my datasource in below class. Is there any way I can use that in config.xml?
I am getting an Error creating bean with name 'cmsTemplate' defined in file: cannot resolve reference bean 'contentDataSource' while setting constructor argument.
JdbcConfiguration.java
#Configuration
public class JdbcConfiguration{
#Value("$comContent.url")
private String dbUrl;
#Value("$comContent.dbUser")
private String dbUser;
#Value("$comContent.dbPass")
private String dbPass;
//rest of the properties
#Bean
#Primary
public DataSource contentDataSource() throws SQLException {
//code
}
}
config.xml
<bean id="cmsTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-args type="javax.sql.DataSource">
<ref bean="contentDataSource"/>
</constructor-args>
<property name="fetchSize" value="{systemProperties['jdbcFetchSize']}" />
</bean>
//Need to create datasource before spring context is getting created. Previously it was like below commented code.
<!-- <bean id="contentDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/comContent</value>
</property>
</bean> -->
I am trying to integrate test a Spring Controller method that uses a spring session scoped bean which is injected into the controller. In order for my test to pass I must be able to access my session bean to set some values on it before I make my mock call to this controller method. Issue is a new session bean is created when I make the call instead of using the one I pulled of the mock application context. How can I make my controller use the same UserSession bean?
Here is my test case
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration("src/main/webapp")
#ContextConfiguration({"file:src/main/webapp/WEB-INF/applicationContext.xml",
"file:src/main/webapp/WEB-INF/rest-servlet.xml",
"file:src/main/webapp/WEB-INF/servlet-context.xml"})
public class RoleControllerIntegrationTest {
#Autowired
private WebApplicationContext wac;
protected MockMvc mockMvc;
protected MockHttpSession mockSession;
#BeforeClass
public static void setupClass(){
System.setProperty("runtime.environment","TEST");
System.setProperty("com.example.UseSharedLocal","true");
System.setProperty("com.example.OverridePath","src\\test\\resources\\properties");
System.setProperty("JBHSECUREDIR","C:\\ProgramData\\JBHSecure");
}
#Before
public void setup(){
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
mockSession = new MockHttpSession(wac.getServletContext(), UUID.randomUUID().toString());
mockSession.setAttribute("jbhSecurityUserId", "TESTUSER");
}
#Test
public void testSaveUserRole() throws Exception {
UserSession userSession = wac.getBean(UserSession.class);
userSession.setUserType(UserType.EMPLOYEE);
userSession.setAuthorizationLevel(3);
Role saveRole = RoleBuilder.buildDefaultRole();
Gson gson = new Gson();
String json = gson.toJson(saveRole);
MvcResult result = this.mockMvc.perform(
post("/role/save")
.contentType(MediaType.APPLICATION_JSON)
.content(json)
.session(mockSession))
.andExpect(status().isOk())
.andReturn();
MockHttpServletResponse response = result.getResponse();
}
Here is my controller method I am needing tested
#Resource(name="userSession")
private UserSession userSession;
#RequestMapping(method = RequestMethod.POST, value = "/save")
public #ResponseBody ServiceResponse<Role> saveRole(#RequestBody Role role,HttpSession session){
if(userSession.isEmployee() && userSession.getAuthorizationLevel() >= 3){
try {
RoleDTO savedRole = roleService.saveRole(role,ComFunc.getUserId(session));
CompanyDTO company = userSession.getCurrentCompany();
It is not passing this line because the UserSession Object is not the same
if(userSession.isEmployee() && userSession.getAuthorizationLevel() >= 3){
This is the declaration of my user session bean.
#Component("userSession")
#Scope(value="session",proxyMode= ScopedProxyMode.INTERFACES)
public class UserSessionImpl implements UserSession, Serializable {
private static final long serialVersionUID = 1L;
Both controlle and bean are created using component scan in my applicationContext.xml
<context:annotation-config />
<!-- Activates various annotations to be detected in bean classes -->
<context:component-scan
base-package="
com.example.app.externalusersecurity.bean,
com.example.app.externalusersecurity.service,
com.example.app.externalusersecurity.wsc"/>
<mvc:annotation-driven />
Add the following bean configuration, which adds a session context for each thread
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="session">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
An equivalent in Java's configuration class would the following bean declaration
#Bean
public CustomScopeConfigurer scopeConfigurer() {
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
Map<String, Object> workflowScope = new HashMap<String, Object>();
workflowScope.put("session", new SimpleThreadScope());
configurer.setScopes(workflowScope);
return configurer;
}
For more details, see
http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/beans.html#beans-factory-scopes-custom-using
Using different Bean definition profiles for test and production worked for me - here's how a XML based setup could look like:
<beans profile="production">
<bean id="userSession" class="UserSessionImpl" scope="session" >
<aop:scoped-proxy/>
</bean>
</beans>
<beans profile="test">
<bean id="userSession" class="UserSessionImpl" >
</bean>
</beans>
To use the test profile for your test, add #ActiveProfiles to your test class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration("src/main/webapp")
#ContextConfiguration({"file:src/main/webapp/WEB-INF/applicationContext.xml",
"file:src/main/webapp/WEB-INF/rest-servlet.xml",
"file:src/main/webapp/WEB-INF/servlet-context.xml"})
#ActiveProfiles(profiles = {"test"})
public class RoleControllerIntegrationTest {
[...]
I was trying to access database using jdbcdao as per the following example:
http://www.mkyong.com/spring/spring-jdbctemplate-jdbcdaosupport-examples/
userdao, userdaoimpl,daocontext and datacontext.xml are as follows:
DAOIMPL
public class UserDAOImpl extends JdbcDaoSupport implements UserDAO {
/*Creates User */
public void insertUser(User user){
String sql = "INSERT INTO Users " +
"(id, username, password,role) VALUES (?, ?, ?,?)";
getJdbcTemplate().update(sql, new Object[] { user.getUserId(),
user.getUserName(),user.getPassWord()
});
}
}
DAO
import java.util.List;
import spring.web.models.User;
public interface UserDAO {
public void insertUser(User user);
}
DAOCONTEXT.XML
<beans xmlns="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.0.xsd">
<bean id="userDAO" class="spring.web.dao.impl.UserDAOImpl">
<property name="primaryDataSource" ref="oracleDataSource" />
</bean>
</beans>
DATA-CONTEXT.XML
<?xml version="1.0"?>
<beans
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans">
<bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property value="oracle.jdbc.OracleDriver" name="driverClassName" />
<property value="jdbc:oracle:thin:#192.168.72.68:1521:d2he"
name="url" />
<property value="aaryal_1" name="username" />
<property value="oracle" name="password" />
</bean>
</beans>
The error I am facing is as follows:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDAO' defined in class path resource [dao-context.xml]:
Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException:
Invalid property 'primaryDataSource' of bean class [spring.web.dao.impl.UserDAOImpl]:
Bean property 'primaryDataSource' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?
Please suggest me what did I miss.
You need a setPrimaryDataSource method in UserDAOImpl class. The error says it all. It's expecting a property called primaryDataSource in your class, but can't find it. Hence the error.
You'll need to do this:
private DataSource dataSource;
public void setPrimaryDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
EDIT:
If you go through the API of JdbcDaoSupport, the setDataSource method already exists. So to solve your error, you can either do the above, or simply rename your DataSource bean name to dataSource
I want to use JSON (jackson library) with my existing app by using JavaConfig (Spring MVC 4.0)
I have my configuration :
#Configuration
#EnableWebMvc
#ComponentScan({ "my.package.controller" })
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Bean(name = "viewResolver")
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
I want to apply JSON configuration but I don't find a solution.
I think I must extends WebMvcConfigurerAdapter. And another detail, I use Spring Security.
Could you help me ?
Thanks
Try this one:
#Bean
public ViewResolver contentNegotiatingViewResolver(
ContentNegotiationManager manager) {
List< ViewResolver > resolvers = new ArrayList< ViewResolver >();
InternalResourceViewResolver r1 = new InternalResourceViewResolver();
r1.setPrefix("/WEB-INF/pages/");
r1.setSuffix(".jsp");
r1.setViewClass(JstlView.class);
resolvers.add(r1);
JsonViewResolver r2 = new JsonViewResolver();
resolvers.add(r2);
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setViewResolvers(resolvers);
resolver.setContentNegotiationManager(manager);
return resolver;
}
And to add Jackson support should use MappingJacksonJsonView or MappingJackson2JsonView
public class JsonViewResolver implements ViewResolver {
public View resolveViewName(String viewName, Locale locale) throws Exception {
MappingJacksonJsonView view = new MappingJacksonJsonView();
view.setPrettyPrint(true);
return view;
}
}
In application.xml just to clarify my example have this config
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
So probably need to add mediaTypes to the ContentNegotiatingViewResolver in the #Bean method.
Check this for more about the ContentNegotiation
I converted to controller to use ContentNegotiatingViewResolver instead of MessageConverters to support multiple output types. With json, I am using MappingJacksonJsonView:
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.xstream.XStreamMarshaller" />
</constructor-arg>
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
<property name="defaultContentType" value="application/json" />
</bean>
With the following controller logic:
#RequestMapping(value = "/id/{id}", method = RequestMethod.GET)
public ModelAndView getById(#PathVariable (value="id") String id) {
MyObject ret = doGetById(id);
ModelAndView modelAndView = new ModelAndView("common/single");
modelAndView.addObject("myObject", ret);
return modelAndView;
}
The json return when I access /id/1234.json is something like:
{
myObject: {
field1:"abc",
field2:"efg"
}
}
Is there a way for my to set myObject as the top level node for the result so it look like this instead:
{
field1:"abc",
field2:"efg"
}
What's happening is Spring MVC is taking the ModelAndView and serializing it to JSON. Since a ModelAndView just looks like a map, and in this case, you only have one entry in the map with a key name of myObject, that's what the JSON response looks at. In order to get just your object, you need to return just your object instead of a ModelAndView and let Jackson serialize your object to JSON.
Rather than returning a ModelAndView, return a MyObject and annotate the method with #ResponseBody, so your controller method becomes
#RequestMapping(value="/id/{id}", method=RequestMethod.GET, produces="application/json")
public #ResponeBody MyObject getById(#PathVariable (value="id") String id) {
return doGetById(id);
}
I faced same issue and following solution works for me.
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="true" />
</bean>
You should be able to remove the outer node by using MappingJacksonJsonView.setExtractValueFromSingleKeyModel(true):
Set whether to serialize models containing a single attribute as a map
or whether to extract the single value from the model and serialize it
directly.
The effect of setting this flag is similar to using
MappingJacksonHttpMessageConverter with an #ResponseBody
request-handling method.
For example:
private final MappingJacksonJsonView view = new MappingJacksonJsonView();
public MyController() {
view.setExtractValueFromSingleKeyModel(true);
}
#RequestMapping(value = "/id/{id}", method = RequestMethod.GET)
public ModelAndView getById(#PathVariable (value="id") String id) {
MyObject ret = doGetById(id);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setView(this.view);
modelAndView.addObject("myObject", ret);
return modelAndView;
}
This should also work if you prefer to do it via configuration:
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="extractValueFromSingleKeyModel" value="true" />
</bean>