I need some help with next topic.
I have a hierarchy of beans, just like that:
<bean id="father" class="myPackage.Father" abstract="true"/>
<bean id="childA" class="myPackage.ChildA" parent="father">
<property name="atrib1" value="hello"></property>
</bean>
<bean id="childB" class="myPackage.ChildB" parent="father">
<property name="atrib2" value="bye"></property>
<property name="atrib3" value="other"></property>
</bean>
I need to create another bean which contains a reference to the abstract class. Then at run-time, I will need to be able to initialize a variable of TYPE "myPackage.Father" and instantiate it with any of the children classes (the polymorphism mechanism). I mean something like that:
<bean id="reference" class="myPackage.Another">
<property name="atrib4" ref="father"></property>
</bean>
Note that reference (an instance of myPackage.Another) is not a subclass of myPackage.Father. But with these lines Spring throws the next error:
Bean definition is abstract
How could I deal with it?
I appreciate any help, thanks in advance!
abstract beans are never instantiated as objects, they exist only in the form of definitions.
From the documention:http://docs.spring.io/spring/docs/3.0.x/reference/beans.html
The parent bean cannot be instantiated on its own because it is incomplete, and it is also explicitly marked as abstract. When a definition is abstract like this, it is usable only as a pure template bean definition that serves as a parent definition for child definitions. Trying to use such an abstract parent bean on its own, by referring to it as a ref property of another bean or doing an explicit getBean() call with the parent bean id, returns an error. Similarly, the container's internal preInstantiateSingletons() method ignores bean definitions that are defined as abstract.
In your case
<bean id="reference" class="myPackage.Another">
<property name="atrib4" ref="father"></property>
</bean>
is refering to the bean defined as abstract which is causing the issue.
First of all abstract bean has nothing to do with the abstract class
they don't even need to be mapped to a class.They are used to group the common properties shared by another beans.But you can not use an abstract bean as a ref to wire a property in another bean.
If your bean myPackage.Another has a reference of type myPackage.Father and your child beans are assignable (either extends of implements) to myPackage.Father then you can wire either childA or childB
in your myPackage.Another bean like this
<bean id="reference" class="myPackage.Another">
<property name="atrib4" ref="childA"></property>
</bean>
There is no different between abstract class and abstract beans.When you use beans and refer to another bean which is abstract , it means you want to instantiate an abstract class it and it can not work surely !
Be careful when you are using an abstract class ! An abstract class is used for template class and you can just extend it !
Related
A class named DefaultGetFreeSchedulePolicyImpl have a field whose type is an interface named IRemoveSchedulePolicy, while IRemoveSchedulePolicy have 2 implements: DefaultRemoveFreeSchedulePolicyImpl and DefaultRemoveSchedulePolicyImpl.
public class DefaultGetFreeSchedulePolicyImpl {
...
IRemoveSchedulePolicy removeSchedulePolicy;
}
In spring xml, there do exist two version of class DefaultGetFreeSchedulePolicyImpl bean configs, but both of them use the same removeSchedulePolicy :
<bean id="extendsGetFreeSchedulePolicy"
class="com.xx.xx.xx.policy.freeSchedule.impl.DefaultGetFreeSchedulePolicyImpl">
...
<property name="removeSchedulePolicy" ref="removeSchedulePolicy" />
</bean>
<bean id="dateGetFreeSchedulePolicy"
class="com.xx.xx.xx.policy.freeSchedule.impl.DefaultGetFreeSchedulePolicyImpl">
...
<property name="removeSchedulePolicy" ref="removeSchedulePolicy" />
</bean>
And bean removeSchedulePolicy has only one bean:
<bean id="removeSchedulePolicy"
class="com.xx.xx.xx.policy.freeSchedule.impl.DefaultRemoveSchedulePolicyImpl"></bean>
Base on information above, I expect that, Intellij IDEA can be as smart as human that, know which bean to go when I want to find the implement of the method, but it didn't:
Is it because I use Intellij IDEA in the wrong way? Is anywhere I can config such that Intellij IDEA can read the Spring bean definition then just show me the right bean method implement?
I'm trying to instantiate a bean, without a class definition, on Spring context by inheriting a parent bean, which is abstract. Like this:
<bean id="childBean" parent="abstractBean">
...
</bean>
<bean id="abstractBean" class="com.java.bean.AbstractBeanClass"
abstract="true" />
But Spring is giving me the following error message:
Error creating bean with name 'childBean' defined in class path resource
[project-spring.xml]:
Instantiation of bean failed; nested exception is
org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.java.bean.AbstractBeanClass]:
Is it an abstract class?;
nested exception is java.lang.InstantiationException
...
I remember having this in another project, and it works perfectly.
I remember having this in the same project, and it works perfectly.
What am I missing here?
UPDATE 1
Found another bean being intatiated exactly like the way I mentioned:
<bean id="variantOptionDataConverter" parent="abstractPopulatingConverter">
...
</bean>
UPDATE 2
Declaration of the Abstract class:
public abstract class AbstractBeanClass<SOURCE, TARGET>
extends AbstractConverter<SOURCE, TARGET>
implements PopulatorList<SOURCE, TARGET>
{
...
}
Note: There's other classes that extends this class. None of the "other spring beans that works" I mentioned above extends this class.
Note 2: I know that it's weird, and, by Java fundamentals, it should not work (like everyone mentioned). But, I don't know how, the other Spring beans are being put in the context. I tried to copy the "other spring beans that work" into my code, change some duplicated names, and it worked. And, that's what I'm trying to understand...
This concrete example Juliano is referring to is from the hybris commerce suite.
Hybris has the concept of extensions that have dependencies on each other. Each extension defines their own application context which has access to its inherited application contexts (from those extensions that are declared as dependencies).
In this example there is an abstractPopulatingConverter bean declaration declared at the root application context where its declared java class is abstract.
However, in other application context further down the dependency tree there is an alias definition for this "abstractPopulatingConverter" that points to a bean definitions with a concrete class.
That's why in a lot of cases (namely the ones that are even further down the dependency tree) using the parent="abstractPopulatingConverter" works as it points to the new bean defined by the alias.
This is the very common message when Spring container faces with absatract Java class (not abstract bean). Check your com.java.bean.AbstractBeanClass code and probably you can find "public abstract class".
What am I missing here?
I don't know what's going on in your other project, but Spring cannot instantiate beans for classes that are abstract.
Concerning abstract beans, the Spring documentation states
A child bean definition inherits configuration data from a parent definition.
[...]
A child bean definition uses the bean class from the parent definition
if none is specified, but can also override it. In the latter case,
the child bean class must be compatible with the parent, that is, it
must accept the parent’s property values.
In other words, an bean definition declared with abstract="true" is simply used as a template for other beans.
Java does not allow instantiation of abstract classes. Spring cannot overrule this language feature. Spring cannot instantiate beans of abstract class types.
Found the answer:
Indeed, like Sotirios Delimanolis commented, "You must have something else going on, proxying of some kind maybe", Spring has a proxy that instantiate this type of bean declaration, but it can't instantiate the bean without its methods (which are just declared in the abstract class, not implemented).
So you must "implement" these methods, like this:
<bean id="childBean" parent="abstractBean">
<lookup-method name="notImplementedMethod" bean="anotherBean"/>
</bean>
The anotherBean must be the same type as notImplementedMethod.
I have the following definition:
<bean id="myInterceptor" class="info.fastpace.MyInterceptor"/>
<bean id="alikProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="myClass"/>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
I have 2 classes defined: MyInterceptor and MyClass.
The peculiar thing is that Spring knows to invoke the interceptor before invoking class MyClass (capital M), even though the class isn't configured in the commonContext.xml file. The only hint is the myClass (lowercase m) in the proxy bean definition.
When removing the alikProxy bean definition, the interceptor isn't invoked.
How does Spring know to invoke the interceptor for MyClass using an undefined myClass ref?
Looks like you defined a bean of class MyClass, but did not give it any name explicitly, so Spring just gave it a default name myClass, based on class name MyClass.
Update
I suppose somewhere in your Spring context xml you have <context:component-scan> element.
Here is a fragment of book Spring In Action, 3rd Edition:
By default, <context:component-scan> looks for classes that are annotated with one
of a handful of special stereotype annotations:
#Component—A general-purpose stereotype annotation indicating that the class
is a Spring component
...skipped...
For example, suppose that our application context only has the eddie and guitar beans in it. We can eliminate the explicit <bean> declarations from the XML configuration by using <context:component-scan> and annotating the Instrumentalist and Guitar classes with #Component.
...skipped...
When Spring scans the com.springinaction.springidol package, it’ll find that
Guitar is annotated with #Component and will automatically register it in Spring. By default, the bean’s ID will be generated by camel-casing the class name. In the case of Guitar that means that the bean ID will be guitar.
I don't want to create a default constructor for my auditRecord class.
But Spring seems to insist on it:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'auditRecord' defined in ServletContext resource
[/WEB-INF/applicationContext.xml]:
Instantiation of bean failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.bartholem.AuditRecord]:
No default constructor found;
nested exception is
java.security.PrivilegedActionException:
java.lang.NoSuchMethodException:
com.bartholem.AuditRecord
Is this really necessary?
No, you are not required to use default (no arg) constructors.
How did you define your bean? It sounds like you may have told Spring to instantiate your bean something like one of these:
<bean id="AuditRecord" class="com.bartholem.AuditRecord"/>
<bean id="AnotherAuditRecord" class="com.bartholem.AuditRecord">
<property name="someProperty" val="someVal"/>
</bean>
Where you did not provide a constructor argument. The previous will use default (or no arg) constructors. If you want to use a constructor that takes in arguments, you need to specify them with the constructor-arg element like so:
<bean id="AnotherAuditRecord" class="com.bartholem.AuditRecord">
<constructor-arg val="someVal"/>
</bean>
If you want to reference another bean in your application context, you can do it using the ref attribute of the constructor-arg element rather than the val attribute.
<bean id="AnotherAuditRecord" class="com.bartholem.AuditRecord">
<constructor-arg ref="AnotherBean"/>
</bean>
<bean id="AnotherBean" class="some.other.Class" />
nicholas' answer is right on the money for XML configuration. I'd just like to point out that when using annotations to configure your beans, it's not only simpler to do constructor injection, it's a much more natural way to do it:
class Foo {
private SomeDependency someDependency;
private OtherDependency otherDependency;
#Autowired
public Foo(SomeDependency someDependency, OtherDependency otherDependency) {
this.someDependency = someDependency;
this.otherDependency = otherDependency;
}
}
You might be able to do constructor based injection, i.e. something like this (taken from documentation found here)
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
but I'm not sure it will work.
If you are defining a JavaBean, you need to follow the convention and put a public no-arg constructor on it.
Almost all Java developers know that compiler adds a default constructor or better known as a no-argument constructor in every Java class, but many of them forget that it only does when you don't provide any other constructor. This means it becomes the developers' responsibility to add a no-argument constructor if he is adding explicit constructor. Now, Why it's important to provide default constructor in Java, What happens if your class doesn't have a no-argument constructor? Well, this is how it's asked in many Java interviews, most commonly as part of Spring and Hibernate interviews.
You should always define a no argument constructor in your Java class, even if you are writing an explicitly constructor, until you are absolutely sure that, it's won't be instantiated using reflection and instantiating it with no argument constructor is a bug, like in your example of Spring Bean.
The documentation of method context.getBean(name, user) says
Allows for specifying explicit constructor arguments / factory method
arguments
but no matter what I do (tried everything), with the most logical setting I get this when the beans are being loaded up during initialization:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'fileValidator' defined in
PortletContext resource
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied
dependency expressed through constructor argument with index 0 of type
[com.liferay.portal.model.User]: Ambiguous factory method argument
types - did you specify the correct bean references as factory method
arguments?
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'fileValidator' defined in
PortletContext resource
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied
dependency expressed through constructor argument with index 0 of type
[com.liferay.portal.model.User]: Ambiguous factory method argument
types - did you specify the correct bean references as factory method
arguments?
<bean id="fileValidator"
class="cz.instance.transl.validation.file.FileValidator"
factory-method="createInstance" />
private FileValidator(User user) {
this.user = user;
}
public static FileValidator createInstance(User user) {
return new FileValidator(user);
}
The commentary says you can do it, but if you specify constructor arguments in xml definiton of that bean or not, it fails.
The javadoc says:
args - arguments to use if creating a prototype using explicit arguments to a static factory method.
So the bean definition must be a prototype-scoped bean, i.e.
<bean id="fileValidator"
scope="prototype"
class="cz.instance.transl.validation.file.FileValidator"
factory-method="createInstance" />
Reading across 20 posts, I found that it was not apparent how to get a custom factory method to take parameters at run-time, especially since we are forced to use the constructor-arg tags and refer to an existing bean in the context as setup below and the class in question acting as a static factory method.
<bean id="user" class="something.something.User" />
<bean id="fileValidator"
class="cz.instance.transl.validation.file.FileValidator"
factory-method="createInstance" >
<constructor-args ref="user" />
</bean>
I got it working by fetching an instance of the bean used in the constructor-arg out of the context and then populating it with the values that you are working with at run-time. This bean will then be used as the parameter when you get your factory-generated bean.
public class X {
public void callFactoryAndGetNewInstance() {
User user = context.getBean("user");
user.setSomethingUsefull(...);
FileValidator validator = (FileValidator)context.getBean("fileValidator");
...
}
}
Note this doesn't solve the problem asked of using context.getBean(arg1, arg2) as that method isn't relevant in this scenario. The reason it isn't is because all these beans are singleton and at this point the constructor isn't invoked. Not a problem and not anything to care about if you are working in a single-user system as you only have 1 User bean in your context at any time anyhow!
However, For a multi-user system you will need to make sure that you have a unique User bean for each real user and that you use the correct User bean in the factory method invocation.
In order to do this in a multi-user system, you will need to change the bean types to be prototype AND you should create a bean of your FileValidator that represents the factory (if you plan to dependency injection into the factory) and another bean FileValidator that represents your new instance. They will both be of the same class type but you must give each one a unique name. See below:
<bean id="user" scope="prototype" class="something.something.User" />
<bean id="validatorFactory"
class="cz.instance.transl.validation.file.FileValidator">
<constructor-arg value="something" />
</bean>
<bean id="fileValidatorBean"
class="cz.instance.transl.validation.file.FileValidator"
scope="prototype"
factory-method="createInstance" >
<constructor-arg ref="user" />
</bean>
and in the class where you would like to get this new FileValidator bean from the factory, you can use the technique below:
public void someMethod() {
...
User user = context.getBean("user");
user.setSomethingUsefull(...);
FileValidator fileValidator =
(FileValidator)context.getBean("fileValidatorBean",
user);
...
}
In order to call your factory method Spring needs access to a user instance to pass to createInstance. In this case I am just creating a bean and passing it in:
<bean id="user" class="something.something.User">
</bean>
<bean id="validator" class="cz.instance.transl.validation.file.FileValidator" factory-method="createInstance">
<constructor-arg ref="user"/>
</bean>
You can use an abstract factory too setting the factory-bean attribute. Here we have an ActionFactory which create actions.
<bean id="actions_factory" class="com.imagina.control.actions.impl.ActionFactoryImpl"/>
<bean id="load_person_action" class="com.imagina.control.actions.impl.LoadPersonAction"
factory-bean="actions_factory" factory-method="create">
<constructor-arg value="load_person_action"/>
</bean>
To use this configuration you have to take this points in account:
create method is not static. Now belongs to an instance
constructor-arg is the parameter of factory method