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 {
[...]
Related
I have this maven project with its modules
Parent
|_____Model
|_____Persistence
|_____Service
|_ service-context.xml
|_____View
|_ spring/app-config.xml
I have this controller
controllers.HomeController in the View module
#Controller
public class HomeController {
protected final Log logger = LogFactory.getLog(getClass());
private IServicioService servicioService;
#RequestMapping(value="/home.htm")
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
logger.info("Returning hello view");
return new ModelAndView("home.jsp");
}
#Autowired
public void setServicioService(IServicioService servicioService) {
this.servicioService = servicioService;
}
And my service servicios.ServicioService in the services module
#Service
public class ServicioService implements IServicioService{
private ServicioDao servicioDao;
public ServicioService(){}
/*************************** Gett&Sett ****************************/
public ServicioDao getServicioDao() {
return servicioDao;
}
public void setServicioDao(ServicioDao servicioDao) {
this.servicioDao = servicioDao;
}
}
The IServicioService hasnt a #Service
The ServicioService bean is defined in service-context.xml like this
<bean id="servicioService" class="servicios.ServicioService">
<property name="servicioDao" ref="servicioDao" />
</bean>
**And my app-config.xml is importing the service-context.xml **
<import resource="classpath*:service-context.xml" />
<context:component-scan base-package="controllers" />
Idk why is giving me this
No matching bean of type [servicios.ServicioService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Help!!
Your problem probably lies inside of xml configuration.
Try adding in your app-config.xml line:
<context:component-scan base-package="servicios" />
After that you should do the same with your daos
I'm using to redis in spring mvc based web application.
so I used spring-data-redis & jedis.
The library version is the following.
Spring MVC 4.1.6
jedis 3.0
Spring data redis 1.6 SNAPSHOT
Redis Server 3.0.2 (installed on Cent OS 7)
Application configuration is following:
-spring configuration xml(applicationContext.xml)
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxWaitMillis" value="3000"/>
<property name="maxTotal" value="50"/>
<property name="testOnBorrow" value="true"/>
</bean>
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:database="16" p:usePool="true"
p:poolConfig-ref="jedisPoolConfig" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}"/>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connectionFactory-ref="connectionFactory" />
-RedisServices.java
public interface RedisServices {
List getAppInfos();
void add_appinfo(List data);
}
-RedisServicesImpl.java
#Service
public class RedisServicesImpl implements RedisServices{
#Autowired
private RedisTemplate<String, Object> redisTemplate;
#Resource(name="redisTemplate")
private ValueOperations<String, Object> valueOps;
#Override
public List getAppInfos() {
return (List)valueOps.get(Constants.APP_INFO_KEY);
}
#Override
public void add_appinfo(List data) {
valueOps.set(Constants.APP_INFO_KEY, data);
}
}
- AppController.java
#RestController
#RequestMapping(value = "/appinfo")
public class AppsController {
#Autowired
private RedisServices redis;
#RequestMapping(value = "/mobiles",method = RequestMethod.GET)
public List view_apps_register(){
List data=new ArrayList();
List lst=services.view_app_register(apps);
for (int i = 0; i < lst.size(); i++) {
Map ap = (Map) lst.get(i);
String server=(String) ap.get("server");
if(server.equals(apps)){
data.add(ap);
}
}
redis.add_appinfo(data);
return null;
}
}
The following errors raised
java.lang.IllegalAccessError: tried to access method redis.clients.util.Pool.returnResource(Ljava/lang/Object;)V from class org.springframework.data.redis.connection.jedis.JedisConnection
at org.springframework.data.redis.connection.jedis.JedisConnection.close(JedisConnection.java:251)
at org.springframework.data.redis.connection.jedis.JedisConnection.<init>(JedisConnection.java:184)
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:252)
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:58)
at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:128)
at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:91)
at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:78)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:178)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153)
at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:86)
at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:169)
at com.wwzz.services.redis.RedisServicesImpl.add_appinfo(RedisServicesImpl.java:63)
Help me!!!!
Java 1.7
Spring 3.1.1 with Spring-WS 2.1.1
Joda
Hibernate 3.6
MySQL 5.0.57
Maven 3
Tomcat 7
Eclipse 3.7
So the SOAP web service is up and running.
And my standalone Java app can access it.
Now I'm trying to build a Spring MVC web client to access it. So by my way of thinking I can just replace the standard webapp's service layer with the web service endpoint .
Patterning after this
http://ankeetmaini.wordpress.com/2013/03/04/jax-ws-client-consuming-the-jax-ws-webservice
after switching his naming conventions to be more canonical I wound up with
FormsEndpointImplService
#WebServiceClient(name = "FormsEndpointImplService",
wsdlLocation = "http://localhost:8080/dept_forms_webservice/formsService?wsdl",
targetNamespace = "http://endpoint.web.forms.azdeq.gov/")
public class FormsEndpointImplService extends Service
{
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://endpoint.web.forms.azdeq.gov/", "FormsEndpointImplService");
public final static QName FormsEndpointImplPort = new QName("http://endpoint.web.forms.azdeq.gov/", "FormsEndpointImplPort");
static {
URL url = null;
try {
url = new URL("http://localhost:8080/dept_forms_webservice/formsService?wsdl");
} catch (MalformedURLException e) {
java.util.logging.Logger.getLogger(FormsEndpointImplService.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "http://localhost:8080/dept_forms_webservice/formsService?wsdl");
}
WSDL_LOCATION = url;
}
public FormsEndpointImplService(URL wsdlLocation) {
super(wsdlLocation, SERVICE);
}
public FormsEndpointImplService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public FormsEndpointImplService() {
super(WSDL_LOCATION, SERVICE);
}
//This constructor requires JAX-WS API 2.2. You will need to endorse the 2.2
//API jar or re-run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1
//compliant code instead.
public FormsEndpointImplService(WebServiceFeature ... features) {
super(WSDL_LOCATION, SERVICE, features);
}
//This constructor requires JAX-WS API 2.2. You will need to endorse the 2.2
//API jar or re-run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1
//compliant code instead.
public FormsEndpointImplService(URL wsdlLocation, WebServiceFeature ... features) {
super(wsdlLocation, SERVICE, features);
}
//This constructor requires JAX-WS API 2.2. You will need to endorse the 2.2
//API jar or re-run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1
//compliant code instead.
public FormsEndpointImplService(URL wsdlLocation, QName serviceName, WebServiceFeature ... features) {
super(wsdlLocation, serviceName, features);
}
/**
*
* #return
* returns FormsEndpoint
*/
#WebEndpoint(name = "FormsEndpointImplPort")
public FormsEndpoint getFormsEndpointImplPort() {
return super.getPort(FormsEndpointImplPort, FormsEndpoint.class);
}
/**
*
* #param features
* A list of {#link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* #return
* returns FormsEndpoint
*/
#WebEndpoint(name = "FormsEndpointImplPort")
public FormsEndpoint getFormsEndpointImplPort(WebServiceFeature... features) {
return super.getPort(FormsEndpointImplPort, FormsEndpoint.class, features);
}
}
FormsEndpoint ( the SEI )
#WebService(targetNamespace = "http://endpoint.web.forms.azdeq.gov/", name = "FormsEndpoint")
#XmlSeeAlso({ObjectFactory.class})
public interface FormsEndpoint
{
#RequestWrapper(localName = "insertCompletedForm", targetNamespace = "http://endpoint.web.forms.azdeq.gov/", className = "gov.azdeq.forms.web.endpoint.InsertCompletedForm")
#WebMethod
#ResponseWrapper(localName = "insertCompletedFormResponse", targetNamespace = "http://endpoint.web.forms.azdeq.gov/", className = "gov.azdeq.forms.web.endpoint.InsertCompletedFormResponse")
public void insertCompletedForm(
#WebParam(name = "arg0", targetNamespace = "")
gov.azdeq.forms.web.endpoint.CompletedForm arg0
);
....
}
and my servlet-context.xml
...
<bean id="formsWebServiceProxy" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="wsdlDocumentUrl" value="http://localhost:8080/dept_forms_webservice/formsService?wsdl"/>
<property name="serviceInterface" value="gov.azdeq.forms.web.endpoint.FormsEndpoint"/>
<property name="serviceName" value="FormsEndpointImplService"/>
<property name="portName" value="FormsEndpointImplPort"/>
<property name="namespaceUri" value="http://endpoint.web.forms.azdeq.gov/"/>
<!-- <property name="endpointAddress" value="http://endpoint.web.forms.azdeq.gov/" /> -->
</bean>
<bean id="baseController" class="gov.azdeq.forms.web.controller.BaseController">
<property name="service" ref="formsWebServiceProxy" />
</bean>
...
and Base Controller
#RequestMapping
#Controller
public class BaseController
{
private static final Logger logger = Logger.getLogger( BaseController.class);
#Resource
FormsEndpoint service; // should come in from bean
...
}
So this all compiles and deploys to Tomcat just fine.
But when I click on dept_forms_webclient in localhost:8080/manager it throws this:
org.springframework.beans.NotWritablePropertyException: Invalid property 'service' of bean class [gov.azdeq.forms.web.controller.BaseController]: Bean property 'service' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
Seems like the proxy bean is being injected ok, it seems like I should not be setting it to FormsEndpoint regardless of what various tuts say.
So, more configuration confusion, can anyone spot what's wrong here?
TIA,
Still-learning Stev
I got it all working by losing the dependency-injection in the context file and using #Autowired in the controller like so:
<!-- controllers -->
<bean id="baseController" class="gov.azdeq.forms.web.controller.BaseController" />
and
#RequestMapping
#Controller("baseController")
public class BaseController
{
#Autowired
#Resource(name="formsWebServicePortProxy")
FormsEndpoint formsWebServicePortProxy;
Not sure why using #Autowired works but manual property injection does not. Huh.
Thanks to all who replied, it did give me a bit of insight.
CASE CLOSED
Still-learning Steve
This is my applicationContext.xml
<bean id="JdbcUserDao" class="controller.User.JdbcUserDao">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="org.apache.derby.jdbc.ClientDriver"
p:url="jdbc:derby://localhost:1527/TodoDb"
p:username="root"
p:password="root" />
This is my implDao class :
#Repository
public class JdbcUserDao implements IUserDao {
private JdbcTemplate jt;
#Autowired
private DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
jt = new JdbcTemplate(this.dataSource);
}
public JdbcTemplate getJt() {
return jt;
}
public void setJt(JdbcTemplate jt) {
this.jt = jt;
}
#Override
public List<User> getUsers(final String username, final String password) {
List<User> users = this.jt.query("SELECT username, password FROM USERS",
new RowMapper<User>() {
#Override
public User mapRow(ResultSet rs, int i) throws SQLException {
User user = new User();
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
return user;
}
});
return users;
}
}
Problems:
this.dataSource available when it sets the dataSource through #Autowired like the configs in xml
when I use dataSource in getUsers, it become null ?
Questions:
How can I get this works ?
I'm new to spring3 so I really need your help.
In order to use autowiring, you need to add the following to your xml file configuration.
<context:annotation-config />
If it doesn't help then please add
<context:component-scan base-package="org.springframework.jdbc.datasource" />
Try adding the AutowiredPostProcessor to the config
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
</bean>
You could try adding the autowire to the set method instead of the property.
you need to import the class which you are doing autowired without access modifiers in repository class file
com.<your project>.controller.User.JdbcUserDao
and spring annotation
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.CrudRepository;
#Repository
public class JdbcUserDao implements IUserDao {
#Autowired
DataSource dataSource;
I am using seam with tomcate and icefaces the problem is when I inject entity manager in component bean it works well but if put it in generic DAO it returns null my code is like that:
this the bean
#Scope(ScopeType.PAGE)
#Name("TestBean")
public class TestBean {
public void test(ActionEvent actionEvent) {
Roles entity = new Roles();
entity.setName("cons");
RolesDao dao = new RolesDao();
dao.emPrisit(entity);
}
}
DAO
public class RolesDao {
#In
EntityManager em;
public void emPrisit(Roles entity) {
em.persist(entity);
}
}
Component.xml
<persistence:entity-manager-factory name="bookingDatabase"/>
<persistence:managed-persistence-context name="em"
auto-create="true"
entity-manager-factory="#{bookingDatabase}"/>
persistence.xml
<persistence-unit name="bookingDatabase"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence </provider>
<jta-data-source>java:comp/env/AP</jta-data-source>
<properties>
<property name="transaction.flush_before_completion" value="true" />
<property name="transaction.factory_class"
value="org.hibernate.transaction.JDBCTransactionFactory" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<!--
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
-->
</properties>
</persistence-unit>
if I inject entitymanger in bean not dao it runs well the second problem when I add this annotation before entitymanger
#In
#PersistenceContext(type = PersistenceContextType.EXTENDED)
EntityManager em;
it give this exception
caused by: java.lang.IllegalArgumentException: #PersistenceContext may only be used on session bean or message driven bean components: TestBean
at org.jboss.seam.Component.checkPersistenceContextForComponentType(Component.java:901)
at org.jboss.seam.Component.scanField(Component.java:877)
at org.jboss.seam.Component.initMembers(Component.java:557)
at org.jboss.seam.Component.<init>(Component.java:244)
at org.jboss.seam.Component.<init>(Component.java:205)
at org.jboss.seam.init.Initialization.addComponent(Initialization.java:1186)
... 13 more
You don't need both #In and #PersistenceContext on your EntityManager. It is enough with one of them.
Injection only occurs in Beans, so your DAO should have a #Name("something"), otherwise Seam doesn't knows what to do with your class.
#Name("RolesDao")
public class RolesDao {
#In
EntityManager em;
public void emPrisit(Roles entity) {
em.persist(entity);
}
}
Then to use this class you should either do:
#In(value="RolesDao") // value="..." is optional
private RolesDao rolesDao;
or
org.jboss.seam.Component.getInstance(RolesDao.class)
Sorry if the sample code has some errors, didn't had eclipse to try it.
Hope this helps