There is a spring componet with #Component annotation, it is just java class (not interface) with annotated #Autowired fields. I am trying to create mock like that:
<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.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
>
<bean id="myComponent" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.MyComponent"/>
</bean>
</beans>
And got an exception that some of fields are not autowired. This happens, because when Spring see <constructor-arg value="com.MyComponent"/> it try to instantiate MyComponent bean and pass it to factory method.
I have tried to extract interface from component, in that case mocking works, but is there a way to make it working without extracting interface?
Also
I have tried adding type="java.lang.Class" but got same errors.
<bean id="myComponent" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg type="java.lang.Class" value="com.MyComponent"/>
</bean>
Any ideas?
Spring cannot autowire the bean because the type of the created bean is java.lang.Object and not com.myComponent. Apparently the order of the definitions in the XML matters as well.
Jayway has a very nice blog post about this: Spring Integration Tests - Creating Mock Objects
You can create a FactoryBean which returns the correct class:
public class MockitoFactoryBean<T> implements FactoryBean<T> {
private Class<T> classToBeMocked;
/**
* Creates a Mockito mock instance of the provided class.
* #param classToBeMocked The class to be mocked.
*/
public MockitoFactoryBean(Class<T> classToBeMocked) {
this.classToBeMocked = classToBeMocked;
}
#Override
public T getObject() throws Exception {
return Mockito.mock(classToBeMocked);
}
#Override
public Class<?> getObjectType() {
return classToBeMocked;
}
#Override
public boolean isSingleton() {
return true;
}
}
Using this factory bean, you can create a config like this:
<bean id="myComponent" class="com.yourpackage.MockitoFactoryBean">
<constructor-arg name="classToBeMocked" value="com.myComponent" />
</bean>
This will mock your component and the object type will com.myComponent.
Update
This is the original answer and explanation (using EasyMock): Autowiring of beans generated by EasyMock factory-method?
Related
I'm running into an issue trying to use Spring caching with ehcache in my application. For reasons that I can't elaborate on, my application uses a graph of BeanFactories instead of ApplicationContexts. This approach has worked well as long as we manually register our BeanPostProcessors, as is called out in the Spring documentation.
We are now adding caching to the app. When we used the simplest annotation configuration, it works.
// This works
package com.x.y.z;
public class RoleManager {
private String user;
public RoleManager( String user ) {
this.user = user;
}
public String getName() {
return user;
}
#Cacheable("user")
public boolean isAllowed(String permissionId, Map<String,?> params)
{
... lengthy and expensive operation to determine if user is permitted to do something
}
}
We configure this to using spring xml for this bean factory:
<?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:util="http://www.springframework.org/schema/util"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-driven/>
<bean id="roleManager" class="com.x.y.z.RoleManager" scope="prototype"/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManager"/>
</bean>
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="file:${conf.dir}/ehcache.xml"/>
<property name="shared" value="true"/>
</bean>
</beans>
... unrelated business beans elided ...
We are using Spring 4.1.9 and ehcache 2.10.2
The above code works quite well. Our ehcache instance for "user" begins to fill as we get cache misses, and returns cached values for hits.
Once this was running correctly, we found that it isn't possible to evict all the entries for a particular user because the cache key is a concatenation of the permissionid and the Map::toString result. We decided to create a cache per user so we would have more control over eviction. To use Spring, we need to use a CacheResolver to accomplish this.
package com.x.y.z;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.AbstractCacheResolver;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import java.util.Collection;
import java.util.Collections;
public class MyCacheResolver extends AbstractCacheResolver {
public MyCacheResolver() {
}
public MyCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> cacheOperationInvocationContext) {
if(cacheOperationInvocationContext.getTarget() instanceof RoleManager) {
return Collections.singleton(((RoleManager) cacheOperationInvocationContext.getTarget()).getName());
}
return Collections.singleton("user");
}
}
We wire this up by adding a new bean definition
<bean id="myCacheResolver" class="com.x.y.z.MyCacheResolver">
<constructor-arg index="0" ref="cacheManager"/>
</bean>
And change the annotation in RoleManager to
#Cacheable(cacheResolver="myCacheResolver")
Once we do this, however, we get the following exception when the isAllowed method is invoked:
java.lang.NullPointerException
at org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactoryAnnotationUtils.java:57)
at org.springframework.cache.interceptor.CacheAspectSupport.getBean(CacheAspectSupport.java:282)
at org.springframework.cache.interceptor.CacheAspectSupport.getCacheOperationMetadata(CacheAspectSupport.java:254)
at org.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:226)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContexts.<init>(CacheAspectSupport.java:500)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy61.isAllowed(Unknown Source)
at com.x.y.z.RoleManager.isAllowed(CompositeRoleManager.java:61)
When I look at the CacheAspectSupport class from the stack trace, I see that it has a member, applicationContext, which is null.
protected <T> T getBean(String beanName, Class<T> expectedType) {
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.applicationContext, expectedType, beanName);
}
This seems like a bug in Spring to me since we do not use ApplicationContexts, and yet caching works until we need to use a CacheResolver. I've looked over the documentation and I see no mention that one must use ApplicationContexts in order to use the Spring caching abstraction.
I guess my question is, has anyone experienced this problem, and if so, what did you do to resolve it? We absolutely cannot use ApplicationContexts in our application, and I'd rather not throw out a perfectly usable abstraction and code directly to the ehcache (or JSR-107) APIs.
Thanks in advance!
Spring 4.3 has fixed the problem by adding a setBeanFactory() method and using the BeanFactory thus set to call the CacheResolvers. Unfortunately I am unable to update our Spring library code to 4.3 at this time, but it will work when we are able to upgrade in the future.
I am trying to autowire some beans (for dependency injection) using Spring for a webapp. One controller bean contains another bean which in turn holds a hashmap of another set of beans. For now the map only has one entry. When i run in tomcat and call the service I get an error saying that the second bean (held in the controller) is not unique
No unique bean of type [com.hp.it.km.search.web.suggestion.SuggestionService] is defined: expected single matching bean but found 2: [suggestionService, SuggestionService]
I cannot see where I am defining the bean twice however am new to Spring and autowiring so I may be missing something fundamental. Source code for xml and 2 class listed below...
<?xml version="1.0" encoding="UTF-8"?>
<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"
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">
<context:component-scan base-package="com.hp.it.km.search.web.suggestion" />
<mvc:annotation-driven />
<context:annotation-config />
<bean id="SuggestionController" class="com.hp.it.km.search.web.suggestion.SuggestionController">
<property name="service">
<ref bean="SuggestionService" />
</property>
</bean>
<bean id="SuggestionService" class="com.hp.it.km.search.web.suggestion.SuggestionService">
<property name="indexSearchers">
<map>
<entry key="KMSearcher"> <ref bean="KMSearcherBean"></ref></entry>
</map>
</property>
</bean>
<bean id="KMSearcherBean" class="com.hp.it.km.search.web.suggestion.SuggestionIndexSearcher">
<constructor-arg index="0" value="KMSearcher" />
<constructor-arg index="1" value="C://dev//workspace//search-restful-webapp//src//main//resources//indexes//keyword" />
</bean>
The class asscoaites with the autowired controller and service bean are here...
#Controller
public class SuggestionController {
private SuggestionService service;
#Autowired
public void setService(SuggestionService service) {
this.service = service;
}
public SuggestionService getService() {
return service;
}
and...
#Component
public class SuggestionService {
private Map<String, IndexSearcher> indexSearchers = new HashMap<String, IndexSearcher>();
#Autowired
public void setIndexSearchers(Map<String, IndexSearcher> indexSearchers) {
this.indexSearchers = indexSearchers;
}
public SuggestionService() {
super(); }
Please Help!
The issue is because you have a bean of type SuggestionService created through #Component annotation and also through the XML config . As explained by JB Nizet, this will lead to the creation of a bean with name 'suggestionService' created via #Component and another with name 'SuggestionService' created through XML .
When you refer SuggestionService by #Autowired, in your controller, Spring autowires "by type" by default and find two beans of type 'SuggestionService'
You could do one of the following
Remove #Component from your Service and depend on mapping via XML - Easiest
Remove SuggestionService from XML and autowire the dependencies - use util:map to inject the indexSearchers map.
Use #Resource instead of #Autowired to pick the bean by its name .
#Resource(name="suggestionService")
private SuggestionService service;
or
#Resource(name="SuggestionService")
private SuggestionService service;
both should work.The third is a dirty fix and it's best to resolve the bean conflict through other ways.
If you have 2 beans of the same class autowired to one class you shoud use #Qualifier (Spring Autowiring #Qualifier example).
But it seems like your problem comes from incorrect Java Syntax.
Your object should start with lower case letter
SuggestionService suggestion;
Your setter should start with lower case as well and object name should be with Upper case
public void setSuggestion(final Suggestion suggestion) {
this.suggestion = suggestion;
}
For me it was case of having two beans implementing the same interface. One was a fake ban for the sake of unit test which was conflicting with original bean.
If we use
#component("suggestionServicefake")
, it still references with suggestionService.
So I removed #component and only used
#Qualifier("suggestionServicefake")
which solved the problem
If I'm not mistaken, the default bean name of a bean declared with #Component is the name of its class its first letter in lower-case. This means that
#Component
public class SuggestionService {
declares a bean of type SuggestionService, and of name suggestionService. It's equivalent to
#Component("suggestionService")
public class SuggestionService {
or to
<bean id="suggestionService" .../>
You're redefining another bean of the same type, but with a different name, in the XML:
<bean id="SuggestionService" class="com.hp.it.km.search.web.suggestion.SuggestionService">
...
</bean>
So, either specify the name of the bean in the annotation to be SuggestionService, or use the ID suggestionService in the XML (don't forget to also modify the <ref> element, or to remove it, since it isn't needed). In this case, the XML definition will override the annotation definition.
I am new to Spring.
Currently, I am trying to achieve following:
A method in class A calls a method in class B with a String parameter. Class B then creates a bean after processing the string (just doing some basic string operations) as:
GenericApplicationContext context = new GenericApplicationContext();
DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();
BeanDefinitionBuilder bean1 = BeanDefinitionBuilder.rootBeanDefinition("className");
bean1.addPropertyReference("sampleString", "sampleBean");
bean1.addPropertyValue("sampleString", "processed string here");
factory.registerBeanDefinition("sampleBean", bean1.getBeanDefinition());
context.refresh();
(I am not sure if my approach to creating bean here is correct. If not, please suggest the appropriate way).
I want this bean to be passed to class A (ofcourse the Spring Way). The name of variable is sampleString.
So far I had been using something like:
<?xml version="1.0" encoding="UTF-8"?>
<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-3.0.xsd">
<bean id="proc" class="A">
</bean>
<bean id="result" class="B">
<property name="sampleString" value="#{proc.sampleString}"/>
</bean>
</beans>
But this copies null value to the variable in class A (ofcourse because the method executes only when a button is pressed).
So is there a cleaner way to do this?
I have started learning hibernate and spring through an assignment in which i am trying to use session factory instance through spring. I understood the hibernate part but just cant go on with spring. I have tried numerous tutorials and examples but just cant get my spring working. Although it works when i instantiate it directly.
Here are the problem related details of my project...
applicationContext.xml (inside WEB-INF)
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config />
<context:component-scan
base-package="com.nagarro.training.assignment6.dao.entity.Student" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven />
<bean id="studentDAO"
class="com.nagarro.training.assignment6.dao.impl.StudentDAOImplementation">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
Edit: including changes as suggested
StudentDAOImplementaion.java (the file where it is being used )
public class StudentDAOImplementation implements StudentDAO {
/**
* single instance of hibernate session
*/
#Autowired
private SessionFactory sessionFactory;
// HibernateUtil.getSessionFactory().openSession()
/**
* #param sessionFactory
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* #return the sessionFactory
*/
public SessionFactory getSessionFactory() {
return sessionFactory;
}
private Session getSession() {
return this.sessionFactory.getCurrentSession();
}
/**
* #return list of all the students
*/
public List<Student> getStudentList() {
System.out.println(this.getSession().getStatistics());
return (List<Student>) this.getSEssion.createQuery("from Student")
.list();
}
}
And here is the snip of my jar files in lib folder:
I think that i dont need to include hibernate files and beans as it is working fine without spring. Its the spring i cant get to work.I have tried many different implementation from the web but i just cannot get it working. It just says null pointer exception on ** System.out.println(sessionFactory.getStatistics());** line in StudentDAOImplementation.
Test class that calls StudentDAO
public class Test {
public static void main(String[] args) {
StudentDAOImplementation sd = new StudentDAOImplementation();
List<Student> list = sd.getStudentList();
for(Student s : list) {
System.out.println(s.getName());
}
}
}
Stack trace
Exception in thread "main" java.lang.NullPointerException
at StudentDAOImplementation.getStudentList(StudentDAOImplementation.java:116)
at Test.main(Test.java:13)
Your sessionFactory variable is misleadingly named, since the type is actually Session. Session != SessionFactory. You're getting a NPE on sessionFactory.getStatistics() because there's no way that Spring can autowire a Session into a DAO like that. If you're not seeing an error before the NPE, then you're not actually instantiating the DAO with Spring, or else you'd get an error about not being able to find a dependency of type Session. The appropriate way to use a Hibernate-based DAO is to inject it with a SessionFactory and call getCurrentSession() in your methods where you need a Session. See "Implementing DAOs based on plain Hibernate 3 API" and following for details about this approach and about setting up appropriate transaction management.
Update: On a second glance, I see that the package for your component-scan is set to com.nagarro.training.assignment6.dao.entity.Student, which looks exactly like a class, not a package. It's also not even close to anything you'd actually want to component-scan. Maybe you don't understand what component-scan is for. It's covered under "Annotation-based container configuration" in the reference guide.
Update 2: About your "test" code: you're not using Spring at all, so you might as well remove the XML and save yourself the trouble. On the other hand, if you'd like to actually use Spring, you'd need to create a context in your main method based on said XML file, such as:
ApplicationContext context = new FileSystemXmlApplicationContext(locationOfXmlFile);
Then if you want a Spring-managed DAO, you can't just create one with new. Spring isn't magic. It doesn't grab control away from you just because you have it loaded somewhere in the same JVM.* You have to ask Spring for the DAO that it created, like:
StudentDAO dao = context.getBean(StudentDAO.class);
Note that I used the interface type, not the concrete type. That's always an advisable practice for numerous reasons.
This (not starting Spring) is your first problem. As soon as you do this, you're going to run into other problems with your configuration. You should post a new question if you need help solving one of them.
*Unless you're using AspectJ weaving to inject arbitrary objects.
You are injecting a Session instead of SessionFactory with #Autowired private Session sessionFactory; in the DAO class. It needs to be a SessionFactory , like this
#Autowired SessionFactory sessionFactory;
And then use it like this to do a DAO operations like save
Session session = sessionFactory.getCurrentSession()
session.persist(entity);
EDIT
Your testcase should be something like this
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:<path_to_your_appcontext.xml>" })
public class StudentDAOTest {
#Autowired
private StudentDAO studentDAO
#Test
public void test() {
List<Student> list = studentDAO.getStudentList();
assertNotNull(list)
}
}
I am new at Spring and am wondering if one can load an application just by annotating the class whose variables must be injected (instead of using ApplicationContext ctx = new ApplicationContext("myAppContext")).
Let me give the following example:
I have this class TestSpring.java in which a string should be autowired
package mytest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
//Is it possible to put an annotation here that loads the application context "TestSpringContext.xm"??
public class TestSpring {
#Autowired
#Qualifier("myStringBean")
private String myString;
/**
* Should show the value of the injected string
*/
public void showString() {
System.out.println(myString);
}
}
The spring bean configuration file (TestSpringContext.xml) looks like this
<?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:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
>
<context:annotation-config />
<bean id="myStringBean" class="java.lang.String">
<constructor-arg value="I am an injected String."/>
</bean>
</beans>
Now I would like to display the value of the autowired string myString (declared in TestSpring.java) using following code in RunTestSpring.java:
package mytest;
public class RunTestSpring {
public static void main(String[] args) {
TestSpring testInstance = new TestSpring();
testInstance.showString();
}
}
Now my question, is it possible to run "RunTestSpring.java" successfully while loading the application context by just annotating RunTestSpring.java. If yes, with which annotation?
#Configurable is probably what you are looking for, it will ensure that objects which are not instantiated by Spring can have their dependencies autowired by Spring. However the catch is that it requires AspectJ compile time/load time weaving for it to work(not Spring AOP).
Here is one reference:
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-atconfigurable
I would suggest writing a JUnit class that would use spring injection for environment initialization. Something like this -
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations="/spring/spring-wireup.xml", inheritLocations = true)
public class MyTestCase extends TestCase {
// your test methods ...
}