unable to child autowire bean in abstract parent class - spring

abstract class Parent {
private Parent self;
private ParentMember parentMember;
#MyAspect
private void functionality() {
//some functionality
}
}
#Component
class Child1 extends Parent {
#Autowire
private ChildMember childMember;
}
Restrictions -
There are more than 50 classes implementing Parent. And I dont want to make changes to them.
I have to add some functionality in parent now in legacy code. And for that I need to self inject the child bean into parent to access the inner method call functionality via spring AOP.
Another issue is the parent class is in a library where spring is not a dependency so spring annotations like #Autowire, etc are not available.
I can create abstract class parent bean in xml probably in the service where child class is defined.
Child class beans are created using component scan in a package. So, these child classes dont have any beans defined in XML.
With so much restrictions, do we have a way to inject the created child bean into parent post construction of bean? I don't think this is possible now.

Related

How do I #Autowire to an extended class when #Qualifier is used in Spring?

I have the following classes:
public class Service
{
#Autowired
#Qualifier(Helper.BEAN_NAME)
protected Helper helper;
...
}
#Component(Helper.BEAN_NAME)
public class Helper
{
public static final String BEAN_NAME = "Helper";
...
}
#Component(Helper.BEAN_NAME)
public class ExtHelper extends Helper
{
...
}
My goal is to not touch the Service or Helper classes. My thinking is that by giving ExtHelper the same bean name as Helper, Spring will autowire ExtHelper implementation to Service instead of Helper.
I am seeing mixed results with this. If ExtHelper is included in my pom AFTER Helper, it works ok. But before, I get a ConflictingBeanDefinitionException. I understand the exception, but not why I get it if I swap the order of dependencies in the POM.
My basic question is whether I am doing this correctly conceptually. Is #Qualifier intended to prevent this kind of override of autowiring? If not, what is the rule to make Spring resolve the conflict by choosing my extension over the base class? Am I required to extend the Service class to get what I want? I am new to Spring and don't quite get how I am supposed to be doing this.
#Qualifier is intended to be used to instruct Spring which bean should be injected in case of multiple beans of type available.
In your case you have two beans that could be injected into protected Helper helper attribute so you have to tell Spring which one should be used. You can't do it with #Qualifier as both of the beans have the same name.
If you don't want to touch those classes you could use another annotation to prioritise a bean - #Primary. Add it on ExtHelper and it will be treated as a preferred bean in case of multiple bean available for injection.
If you want to stay with #Qualifier you would need to change name of one of those beans and inject preferred bean:
#Component
public class Service
{
#Autowired
#Qualifier("extHelper")
protected Helper helper; // instance of Helper or ExtHelper could be injected here
...
}
#Component // bean will be named using default naming strategy: helper. You can obviously use your own name
public class Helper
{
...
}
#Component // bean will be named using default naming strategy: extHelper. You can obviously use your own name
public class ExtHelper extends Helper
{
...
}

Not able to inject values in a field

#Component
#PropertySources({ #PropertySource("classpath:mail.properties") })
public class A implements B {
#Value("${mail.team.address}")
private String teamAddress;
// has getter and setters .not shown for brevity.
Now when i call the class i get the value of teamAddress as NULL .But in the property file mail.team.address has some value.
My property file is present under src/main/resource folder
Making a call
A a = new A ();
a.someMethodinClassA();
You can not create instance of class by yourself when you want Spring to resolve #Value annotation.
See documentation:
Note that actual processing of the #Value annotation is performed by a BeanPostProcessor which in turn means that you cannot use #Value within BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).
Simple solution for you: just annotate class with any #Component annotation and let Spring to create an instance of your class.
You can't create (with a "new" keywoard) for spring bean. If you do it like this, spring doesn't participate in the object creation and configuration, which means that there is no autowiring, the bean is not in Application Context, etc. And of course, #Value annotation won't be processed among other things
The better way is to inject the class A to the code that you used in your example:
A a = new A ();
a.someMethodinClassA();
Show become:
#Component
public class SomeClass {
private final A a;
public SomeClass(A a) {
this.a = a;
}
public void foo() {
a.someMethodinClassA();
}
}
You should read some basics around spring dependency injection. The class that you have autowired with #Component is scanned via component scanning and its object is created by spring container for you.
that is the reason you should not create the object yourself using new keyword.
wherever in your new class you want to use your class A object you can autowire it as below:
#Component
public class TestC{
private A a; // this object will be injected by spring for you
}

Best practice: Spring Autowired, concrete class, and Builder

We have an interface:
public interface NotifyService {
public void send();
And a class that implements it
public class EmailNotifyService implements NotifyService {
private EmailBuilder _builder;
#Autowired
PersonRepository _personRepository;
... other Autowired Repositories ...
public EmailNotifyService(EmailBuilder builder) {
this._builder = builder;
}
public void send() {
// send mail using _builder.getRecipient().getEmailAddress(), etc.
}
We used to instantiate EmailNotifyService with a builder:
public class EmailBuilder {
private Person _recipient;
private EmailType _type;
private Event _event;
public EmailNotifyService build() {
return new EmailNotifyService(this);
}
public EmailBuilder recipient(Person recipient) {
this._recipient = recipient;
return this;
}
... and so on. But now, instead of using build() to create a new EmailNotifyService, we are trying to use Autowire with Spring instead. The problem is that everywhere else in our app, we are Autowiring interfaces, not classes. And from what I've read it's a good idea in general. In fact, I've tried rewriting the NotifyService to be an Abstract class, and then have EmailNotifyService just extend it. But Spring isn't Autowiring it correctly, it doesn't create a Proxy like it does for interfaces, and all of my Autowired fields are null.
So it would seem we're stuck with Autowiring the NotifyService interface. Fine. What I can't get my head around is - how can I get the data I used to assign with the builder -- the Person, EmailType and Event -- into a Spring Autowired interface?
I suppose I could change the interface definition to have a setPerson(), setEmailType(), etc., but apart from being really ugly, it defeats the purpose of using an interface in the first place. A different NotifyService (WebServiceNotifyService or RestNotifyService for example) night not have need for that info.
Is there any elegant, best-practice way to do this?
Thanks.
EDIT
I am using annotations, very little xml. And I am also using transaction management, which might explain why the abstract class isn't properly autowired? This is the only pertitnent info I have in xml:
<context:annotation-config />
<context:component-scan base-package="com.myco.myapp" />
<tx:annotation-driven transaction-manager="transactionManager"/>
What I mean when I say "autowiring isn't working correctly" is that when I try to autowire the abstract class, Spring doesn't seem to be creating a Proxy like it does for interfaces, and all the Autowired fields in my EmailNotifyService (PersonRepository, others ...) are null. When I use an interface, all the Autowired fields are wired correctly.
But my main problem is that I used to work explicitly with a concrete class, using a builder to create a new EmailNotifyService() directly, and pass it info -- Person, EmailType and Event. These are just normal beans. There are no setters/getters for them in EmailNotifyService but there are the EmailBuilder, which used to live inside EmailNotifyService.
But now I am using the NotifyService interface, which knows nothing about Person, EmailType or Event. But I need this info in order for EmailNotifyService to work.
So my question is, if I use Spring to Autowire my EmailNotifyService like this:
#Autowired
#Qualifier("email") // so Spring knows I want to use the EmailNotifyService implementation
NotifyService _notifyService
How can I set the Person, EmailType and Event data, since NotifyService knows nothing about them?
Currently we are using the mailer service within a web app but theoretically the mailer service should be able to work stand-alone. Regardless, I don't see how request scoped beans can help me here.
Robert what do you mean by not autowiring correctly? Are you getting any error?
Generally both interface and class auto-wiring works in Spring unless you have some autoproxy configured example #Transactional.
You do not need to have setPerson(), setEmailType(), etc. in your interface but have them autowired in the concrete class which requires them.
But seems Person is not a service but a bean which holds data and its specific to a request. If yours is a web application then look at request scope proxy to inject Person like bean.
So you are using transactions which is why class based injection is failing. Add proxy-target-class="true" to tx:annotation-driven.
Regarding your injection of Person and EmailType then you have to do that to the bean EmailNotifyService. In EmailNotifyService I do not see any Person or EmailType variables defined. Also read what I said about Person bean above.
Your design is not correct. You should not make EmailBuilder a bean and look to autowire to the EmailNotifyService. Instead in EmailNotifyService you should have a method send(EmailBuilder builder) where you pass the builder which you created somewhere dynamically.

Spring dynamic autowire services

I've started to build some kind of a CMS and I'm stuck over one idea.
The description is:
I have standard MVC Controller (Home) in which I'm downoading modules settings which will be set in this Controller.
The response is, that I have to implement module with name "HPModule".
So I'm trying to load this module by Class.forName("com.app.something.HPModule"); and then call method init();
My HPModule is:
public class HPModule
{
#Resource(name = "hpModuleService")
private HPModuleService hpModuleService;
public String init()
{
SomeObject someObject = hpModuleService.getArticle();
}
}
And I found that when I'm trying to do SomeObject someObject = hpModuleService.getArticle(); Spring is blind for #Resource when I'm calling class by Class.forName.
How to solve this issue?
The HPModule has to be a Spring Bean retrieved by means of DI or directly from Spring BeanFactory. You cannot expect Spring to autowire a class that is not instantiated by Spring, unless You use #Configurable and AspectJ to weave the class.
If HPModule already is a Spring Bean, than just #Autowire or #Inject it directly into the MVC controller that needs it.
If You don't know in compile time what modules You'll need, than inject ListableBeanFactory and use BeanFactoryUtils to get the modules You need in runtime by type or by name.

Spring MVC + Hibernate DAOs : unable to wire beans

I'm currently working on a Spring MVC project in which I integrated Hibernate. The pure Spring MVC part (DispatcherServlet + request mapping) works fine. Now, the problem I have to cope with is quite strange : I've read "Java Persistence with Hibernate" and I am trying to design my persistence layer in a similar way than explained in the book. That is, I've designed it in two parallel hierarchies : one for implementation classes and a second for the interfaces.
So, I have an abstract class named GenericDaoImpl, that implements the GenericDao interface. Then I have a concrete class named AdvertisementDaoImpl, that extends GenericDaoImpl and that implements the AdvertisementDao interface (which extends GenericDao).
Then, in a service bean (class marked with #Service), I'll have my dao class autowired.
Here's my problem :
autowiring a DAO class that implements an interface but does not extends my abstract GenericDaoImpl class : OK
autowiring my AdvertisementDaoImpl that implements the AdvertisementDao interface and extends my abstract GenericDaoImpl class : leads to bean initialization exception.
The abstract class I have at the top of my DAO hierarchy handles all the boilerplate code for common CRUD methods. So, I definitely want to keep it.
Does anyone have an explanation about that?
Here's an excerpt of code :
public abstract class GenericDaoImpl <T, ID extends Serializable> implements BeanPostProcessor, GenericDao<T, ID>{
#Autowired(required=true)
private SessionFactory sessionFactory;
private Session currentSession;
private Class<T> persistentClass;
...
}
#Repository
public class AdvertisementDaoImpl extends GenericDaoImpl<Advertisement, Long> implements AdvertisementDao {
...
public List<Advertisement> listAdvertisementByType(AdvertisementType advertisementType, Class<? extends Good> type) {
return null;
}
}
#Service
public class AdvertisementServiceImpl implements AdvertisementService{
#Autowired(required=false)
private AdvertisementDao advertisementDao;
public List<Advertisement> listAllAdvertisements() {
return null;
}
}
Here's the most relevant part of the stacktrace (at least, I guess it is):
nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: be.glimmo.service.AdvertisementService
be.glimmo.controller.HomeController.advertisementService; nested
exception is java.lang.IllegalArgumentException: Can not set
be.glimmo.service.AdvertisementService field
be.glimmo.controller.HomeController.advertisementService to
be.glimmo.dao.AdvertisementDaoImpl
And here's my Spring configuration (link to pastebin.com) :
I believe you should use proxy-target-class in your transaction management configuration:
<tx:annotation-driven transaction-manager="transactionManagerForHibernate"
proxy-target-class="true" />
The symptoms of the problem you describe match the ones mentioned in Spring Transaction Management (look for Table 10.2) and AOP proxying with Spring:
If the target object to be proxied implements at least one interface
then a JDK dynamic proxy will be used. All of the interfaces
implemented by the target type will be proxied. If the target object
does not implement any interfaces then a CGLIB proxy will be created.
So, when CGLIB is not there by default, you have all the methods coming from implemented interfaces but you will miss proxying of the methods that come from super classes in the hierarchy and that's why you get an exception on this.
After a few more tests, it turns out that the problem was caused by my abstract GenericDaoImpl class implementing BeanPostProcessor interface : for some reason, the methods from this interface were executed not only at this bean instantiation but at every bean intantiation.
Given that, within my BeanPostProcessor hook methods, I was retrieving generics parameterized types, when these methods were executed against classes that are not in my DAO hierarchy, they would end up yielding runtime Exceptions (more specifically, ClassCastException).
So, to solve this issue, I had my GenericDaoImpl class not implement BeanPostProcessor interface anymore and I moved the body of the hook method in the empty contructor.

Resources