I know there are threads similar to this issue. Below is my class and I am configuring it in spring.xml file. Actually HumanResourceService is an interface having only one method.
#Endpoint
public class HolidayEndpoint {
#Autowired
private HumanResourceService humanResourceService;
#Autowired
public HolidayEndpoint(HumanResourceService humanResourceService) throws JDOMException {
this.humanResourceService = humanResourceService;
}
}
My problem is that in my spring.xml file, when I define HumanResourceService as bean, it cannot be instantiated as this is an interface. How can I mention an interface in spring configuration file. My spring.xml file is below
<bean id="holidayEndpoint" class="com.mycompany.hr.ws.HolidayEndpoint" autowire="constructor" >
<property name="humanResourceService" ref="humanResourceService" />
</bean>
<bean id="humanResourceService" class="com.mycompany.hr.service.HumanResourceService" />
You can't, Spring needs something it can make an instance from, the interface isn't enough.
In your spring.xml, the value of the class attribute for your bean with id="humanResourceService" should be the name of your implementation class, not the interface. Spring needs you to tell it what implementation class you want it to use for this.
Related
I have a question around the usage of new keyword being used when using java configuration in spring. What is the need of using new keyword
Refer below mentioned example:
Code implemented using Java Config
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
The above code will be equivalent to the following XML configuration
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
In XML config, we do not use new keyword whereas in java config we are using new keyword. can someone please explain the difference
In the XML configuration, you explain to the system what class should be instanciated (there is a "new" but it is behind the scene) but in the Java Config you actually have to return an instance so that is why we use the 'new' keyword. 'new' simply creates an instance of your class.
The two examples shown in question are not really equivalent.
What the
<beans>
<bean id="helloWorld"
class="com.test.HelloWorld" />
</beans>
really does, is it tells Spring to instantiate class com.test.HelloWorld, and name the resulting bean "helloWorld".
Then the java-config approach is not really doing this. Instead this follows the factory-method pattern, when we tell Spring, that the return value of the method is the bean, and the method name is the name of that bean.
An equivalent of that in XML would be the mentioned factory-method approach, which in this case would look something like this:
<beans>
<bean id="helloWorldConfig"
class="com.test.HelloWorldConfig" />
<bean id="helloWorld"
factory-bean="helloWorldConfig"
factory-method="helloWorld" />
</beans>
Note that there are several approaches to factory-method. In the above, we are assuming, the `helloWorldConfig" is the factory, and we're specifying the method on that bean. Theare are cases with static factory methods too. See here for more examples.
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
This XML configurations tells Spring to "create an instance of com.test.HelloWorld and put it in the bean context with bean id helloWorld".
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
In this Java configuration, we are returning an instance of com.test.HelloWorld. Because of the #Bean annotation, this instance is put into the bean context. As no specific bean id is given, the bean id is derived from the method hellowWorld() and thus becomes helloWorld.
As you can see, both configurations require an instance of com.test.HelloWorld. The XML configuration implicitly creates the instance whereas in the Java configuration you have to explicitly do it yourself.
I have a singleton service class like the below.
#Service
public class SingletonClass{
#Autowired
private ContextProvider provider;
public Context run(){
context = provider.createContext();
updateContext(context)
}
ContextProvider class:
public abstract class ContextProvider implements MyInterface{
public abstract Context createContext();
}
configuration:
<bean name="provider"
class="xyz.s.s.ContextProvider" >
<lookup-method name="createContext"
bean="someBean" />
</bean>
<bean id="somebean" class="com.x.y.someclass" />
<bean id="singletonService" class="com.x.y.SingletonClass" />
When i try to run the above using Junit ->instead of creating the lookup bean on demand, I am getting the below error
org.springframework.beans.factory.BeanCreationException:
aused by: java.lang.AbstractMethodError
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1585)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
It seems, the lookup method injection is not working in my case
I found the issue and fixed it.
I was having the abstract class implemented an interface. So at run time,
CGLIB unable to create a proxy class since there are unimplemented methods.
Compiler also did not complain, because this is abstract class and it did not expect us to add all implementations of the interface.
I removed the 'implements ' and it just works fine.
So the contextprovider will become,
public abstract class ContextProvider {
public abstract Context createContext();
}
Posting this message, since people might face same situation.
I have a bean I am trying to configure in Spring context using Constructor injection. When I pass subclass for one of the constructor arguments, the bean is instantiated by Spring container only if I do not specify the "type" attribute. Would anybody have any idea what's wrong? Below are more specifics.
class MyClass{
public MyClass(SomeAbstractBase absObject){
//do stuff
}
}
class ConcreteClass extends SomeAbstractBase{
//
}
Spring configs (First and second do not work but the third one using type attribute works)-
Config I-
<bean id="concreteclass"
class="ConcreteClass"/>
<bean id="myclass"
class="MyClass">
<constructor-arg type="ConcreteClass" ref="concreteclass"/>
</bean>
Config II-
<bean id="concreteclass"
class="ConcreteClass"/>
<bean id="myclass"
class="MyClass">
<constructor-arg type="SomeAbstractBase" ref="concreteclass"/>
</bean>
Config III-
<bean id="concreteclass"
class="ConcreteClass"/>
<bean id="myclass"
class="MyClass">
<constructor-arg ref="concreteclass"/>
</bean>
I get the following exception at initialization-
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'jedispool' defined in class path resource
[cache-spring-config.xml]: Could not resolve matching constructor
(hint: specify index/type/name arguments for simple parameters to
avoid type ambiguities)
Why would neither of the first or second config work?
Thank you
Type argument accept only the full qualified type (because if not spring cannot determine exactly the package and the type will not match your class):
So you need to use the canonical name of your class to be a type
ConcreteClass => com.your.app.ConcreteClass
A class is not just a name, is a package + name (too be short)
I believe the error you had appeared because you had static nested classes. Here's an SSCCE
package test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(MyClass.class.getName());
System.out.println(ConcreteClass.class.getName());
System.out.println(SomeAbstractBase.class.getName());
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
}
static class MyClass {
public MyClass(SomeAbstractBase absObject) {
}
}
static class ConcreteClass extends SomeAbstractBase {
//
}
static abstract class SomeAbstractBase {
}
}
With spring.xml containing
<bean id="concreteclass" class="test.Test.ConcreteClass" />
<bean id="myclass" class="test.Test.MyClass">
<constructor-arg type="test.Test.SomeAbstractBase" ref="concreteclass" />
</bean>
The above fails with a UnsatisfiedDependencyException. In this specific example, the class attribute isn't used correctly. The fully qualified class name for ConcreteClass is test.Test$ConcreteClass, not test.Test.ConcreteClass as I've specified. The same applies to MyClass and SomeAbstractBase.
However, specifying test.Test.ConcreteClass in the class attribute for the concreteclass bean doesn't fail because at some point during processing of bean declarations, Spring tries to resolve the class String into a Class object using Class.forName(String). It will call ClassUtils.forName(String, ClassLoader) to do this. Initially it will fail because there is no such class test.Test.ConcreteClass. However, this is done in a try-catch which on ClassNotFoundException will transform the String class name from test.Test.ConcreteClass to test.Test$ConcreteClass and try again. It will work and correctly create a bean of type test.Test$ConcreteClass for your concreteclass bean.
When it tries to create your myclass bean, however, it does not apply such logic for resolving which constructor to use and therefore cannot understand that with the type attribute value of test.Test.SomeAbstractBase, you actually meant test.Test$SomeAbstractBase, so it fails saying the type is ambiguous.
Change your bean declarations to correct types
<bean id="concreteclass" class="test.Test$ConcreteClass" />
<bean id="myclass" class="test.Test$MyClass">
<constructor-arg type="test.Test$SomeAbstractBase" ref="concreteclass" />
</bean>
and it will work.
Take a look at kakawait's answer, you need to specify the fully qualified class name for the bean you are trying to instantiate.
I'm trying to inject (autowire) a spring bean to an abstract class but it doesn't seem to work.
public abstract class BaseEntity {
#Autowired(required = true)
protected SecurityProvider securityService;
public BaseEntity() {
}
}
And the injected class:
#Component
public class SecurityService extends SecurityProviderImpl implements SecurityProvider {
#Autowired
public SecurityService(ICipherDescriptor cipherDescriptor) {
super(cipherDescriptor);
}
}
The SecurityService gets initialized just fine (I can see it while debugging) but the class that inherit from BaseEntity cannot use the injected SecurityService since it is null (doesn't get injected for some reason).
I tried doing it via XML as well, defining the BaseEntity as abstract:
<bean id="baseEntity" abstract="true" class="com.bs.dal.domain.BaseEntity">
<property name="securityService" ref="securityService"/>
</bean>
<bean id="securityService" class="com.bs.dal.secure.SecurityService">
<constructor-arg ref="cipherDescriptor" />
</bean>
but still with no success.
Where am I going wrong?
I think I know what's wrong here. I'm trying to inject a spring bean to an entity - which is impossible (unless you use aspectJ weaving) since the entities are not instantiated/managed by Spring. Make sense, isn't it?
If your BaseEntity is also instantiated by spring, you just need to add a parent attribute to the bean definition to link it to your BaseEntity definition like so:
<bean id="baseEntity" abstract="true" class="com.bs.dal.domain.BaseEntity">
<property name="securityService" ref="securityService"/>
</bean>
<bean id="derivedEntity" parent="baseEntity" class="com.bs.dal.domain.DerivedEntity"/>
<bean id="securityService" class="com.bs.dal.secure.SecurityService">
<constructor-arg ref="cipherDescriptor" />
</bean>
In short, the two key parts to such a definition are the abstract attribute on the parent class and the parent attribute on the subclass.
I have the bean config:
<bean id="PostLoginUpdater" class="xyz.auth.PostLoginUpdater" autowire="byType" />
and
public class PostLoginUpdater implements PostLoginStatePersonalizer {
//#Qualifier("CustomerManager")
#Inject
//#Resource(name = "CustomerManager")
private CustomerManager customerManager;
public void setCustomerManager(CustomerManager customerManager)
{
this.customerManager = customerManager;
}
}
Because there are two beans that implement CustomerManager I get this error:
No unique bean of type [CustomerManager] is defined: expected single
matching bean but found 2
As you can see, I'v tried several combinations (#Inject along with #Qualifier, #Ressource, only #Qualifier) But I don't get rid of this error message.
According to Spring In Depth, #Qualifier can be used along with #Inject. Can't I used them together if I defined autowire="byType" in bean config?
And I don't use <context:annotation-config /> or <context:component-scan />
You should be able to use a combination of '#Inject' and '#Qualifier', if you have multiple beans of the same type. Here is how to configure it -
<bean id="PostLoginUpdater" class="xyz.auth.PostLoginUpdater" autowire="byType" />
<bean id="firstManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>first</qualifier>
</bean>
<bean id="secondManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>second</qualifier>
</bean>
If you had two beans of type 'CustomerManager' as shown above, you could use the snippet shown below for injection -
public class PostLoginUpdater implements PostLoginStatePersonalizer {
#Inject
#Qualifier("first")
private CustomerManager customerManager;
public void setCustomerManager(CustomerManager customerManager)
{
this.customerManager = customerManager;
}
}
Also, on a side note -
If you keep using one of the beans more often than another you could use the 'primary' attribute.
For example, in the above example, if you always tend to use 'firstManager', you could mark it as primary as shown below.
<bean id="PostLoginUpdater" class="xyz.auth.PostLoginUpdater" autowire="byType" />
<bean id="firstManager" class="xyz.manager.CustomerManager" autowire="byType" primary="true" >
</bean>
<bean id="secondManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>second</qualifier>
</bean>
If you have above configuration, the following code will always injects 'firstManager' when no qualifier is used -
public class PostLoginUpdater implements PostLoginStatePersonalizer {
#Inject
private CustomerManager customerManager;
public void setCustomerManager(CustomerManager customerManager)
{
this.customerManager = customerManager;
}
}
It doesn't make any sense to try to autowire by type, and simultaneously specify a name. Choose one approach or the other.
I have also had trouble in the past trying to use #Qualifier with #Inject. One thing to note is that there are two annotations with that name, one in Spring and one in Java:
org.springframework.beans.factory.annotation.Qualifier
javax.inject.Qualifier
However, if using the spring framework one, then the suggested usage is to explicitly name your component via #Component or #Named [#Component("beanName")] (if annotated), or in the <bean> definition. Be aware that autowiring wants the bean name, not the Class name as in your example (i.e. do not use "CustomerManager"). For example, if you have two bean definitions like in Sashi's example:
<bean id="firstManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>first</qualifier>
</bean>
<bean id="secondManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>second</qualifier>
</bean>
then declare the field like this:
#Inject
#Qualifier("firstManager")
private CustomerManager customerManager;