How to use Spring Dependency Injection with class inheritance - java

I have a parent class called BaseService and I have other services that inherit from BaseService as they all need those methods to do their jobs. As always the methods of the superclass are available inside the subclass... However, when I use #Autowired DI to inject the subclass I am not able to use the methods defined by the parent class, I am only able to use what is defined separately in the subclass. How can I inject the subclass and have it properly instantiate the subclass such that the methods of the parent class are available to me?
Ex. Parent Class
#Service
public class BaseService{
public BooleanExpression combineBools(Predicate predicate, BooleanExpression bool){
BooleanExpression result = runupBool.and(predicate);
return result;
}
}
Ex. Child Class
#Service
public class EqServiceImpl extends BaseService implements EqService{
public EqServiceImpl(){
super();
}
#Override
public Iterable getAllData(Map<String, String> params, Predicate predicate) {
// Some Method Specific to Child Class
}
}
Ex. Controller
#RestController
public class EqController {
#Autowired
EqService eqService
...
}
If I wanted to access the method eqService.combineBools() inside the controller I am unable to. Why is this? How can I fix it?

As DarrenForsythe pointed out I am instantiating with EqService as the type so it would not have all of the methods of the BaseService since it does not extend that class, rather it is the EqServiceImpl that extends that class. Therefore I would need the type to be EqServiceImpl. Without making some other changes #Autowired is not the best choice for DI here.

Related

Error with Quarkus CDI, Injection of inherited class

I am attempting to implement dependency injection in a class that is inherited from a base abstract class, and I get the following error: "javax.enterprise.inject.spi.DeploymentException: It's not possible to automatically add a synthetic no-args constructor to an unproxyable bean class. You need to manually add a non-private no-args constructor to com...ExampleIntegrationProvider in order to fulfill the requirements for normal scoped/intercepted/decorated beans."
From what I researched, it seems that this happens because classes that are annotated with normal scoped beans such as #ApplicationScoped for example, need a non-private constructor without arguments, so that CDI can create a proxy of that class when it is injected in lazy mode. I was a bit surprised to find out, as I've never had problems with code like this:
#ApplicationScoped
public class UserService {
private final UserRepository userRepository;
#Inject
public UserUseCase(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User findById(long id) { ... }
}
Even though Quarkus magically adds a synthetic no-args constructor, how could it overcome the final field UserRepository? There would be a problem with its initialization as it needs to receive a value, I imagine it might end up being passed a null value..
Anyway, going straight to my case, here's an example of my current situation, with 3 important base classes and 1 implementation for a "Example" partner:
PartnerIntegration.java
#MappedSuperclass
public abstract class PartnerIntegration {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
// other common fields ...
}
PartnerIntegrationRepository.java
public interface PartnerIntegrationRepository<I extends PartnerIntegration> extends PanacheRepository<I> {
// common methods ...
}
PartnerIntegrationProvider.java
public abstract class PartnerIntegrationProvider<I extends PartnerIntegration> {
protected final PartnerIntegrationRepository<I> partnerIntegrationRepository;
protected PartnerIntegrationProvider(PartnerIntegrationRepository<I> partnerIntegrationRepository) {
this.partnerIntegrationRepository = partnerIntegrationRepository;
}
// code ...
}
And finally the final implementation ExampleIntegrationProvider.java:
#ApplicationScoped
public class ExampleIntegrationProvider extends PartnerIntegrationProvider<ExampleIntegration> {
#Inject
public ExampleIntegrationProvider(ExampleIntegrationRepository exampleIntegrationRepository) {
super(exampleIntegrationRepository);
}
// code ...
}
The abstract class PartnerIntegrationProvider is not annotated with any scope as I did not consider it necessary since it only receives the PartnerIntegrationRepository interface and not a concrete repository. But ExampleIntegrationProvider receives a concrete repository that is implementing that interface, so I annotated it with #ApplicationScoped to be able to inject the concrete repository with #Inject. But this generated that error.
I tried creating a public constructor method that passes the null parameter to the parent class, and the error disappeared, but this ends up polluting my code, since I do not want to allow that class to be instantiated without receiving a repository, so I removed the #ApplicationScoped and #Inject annotations from ExampleIntegrationProvider and created that class to produce the instance that will be injected from it:
ExampleIntegrationProviderBean.java
#Dependent
public class ExampleIntegrationProviderBean {
private static ExampleIntegrationProvider INSTANCE;
private final ExampleIntegrationRepository exampleIntegrationRepository;
#Inject
public ExampleIntegrationProviderBean(ExampleIntegrationRepository exampleIntegrationRepository) {
this.exampleIntegrationRepository = exampleIntegrationRepository;
}
#Produces
public ExampleIntegrationProvider exampleIntegrationProvider() {
return INSTANCE == null ?
(INSTANCE = new ExampleIntegrationProvider(exampleIntegrationRepository)) : INSTANCE;
}
}
But the number of partners may grow quickly, I wouldn't like to have to create other classes like this one to produce the instances, and even if it was just one partner, it doesn't seem like a very elegant solution...
Does anyone have any ideas on how I can resolve this in a better way?

How to call method from a reference send to annotation in java

I have a Interface I and a Abstract Class A , I have My custom annotation MyAnnotation which should take parameter as subclass S of A, now while processing annotation I want to call method of concrete class S
public interface I{
void m1();
}
public abstract class A implements I {
public abstract void m1();
}
public #interface MyAnnotation {
public Class< ? extends A> ref();
public Class< ? super A> ref2();
}
public S extends A{
public void m1() {}
}
I am annotating method like
#MyAnnotation(ref= new XX() ) or #MyAnnotation(ref= XX.class )
#MyAnnotation(ref= new yy() ) or #MyAnnotation(ref= yy.class )
whichever works
//In spring aspect before processing I am getting method annotation and trying to call m1()
annotation.ref().m1() //Error
annotation.ref2().m1() //Error
You can't use new XX() in an annotation. Annotations parameters can use a very specific set of types:
primitive
String
Class
an Enum
another Annotation
an array of any of the above
See this answer.
So to accomplish what you're trying to accomplish, you'd have to use a class.
You would then have to use reflection to create an instance and invoke the method.
Class<?> clazz = annotation.ref();
I instance = (I) cls.getConstructor().newInstance();
instance.m1();
See this answer.
Your classes must all have no-argument constructors, else you'll only be able to instantiate some this way but not others (leading you to have to conditionally branch based on the class).
You can't do that simply like that. You need an instance of the class first.
If your A class is a Spring's bean, you can inject ApplicationContext and get the bean from there. Then you can call a method.
#Autowired
private ApplicationContext context;
void test(MyAnnotation annotation) {
A bean = context.getBean(annotation.ref());
bean.m1();
}

specify injections for child classes

I've got an abstract class that has injectable field
public abstract class AbstractPopulator implements ITemplatePopulator {
#Inject
private ITemplatePopulator next;
I have multiple classes that inherit AbstractPopulator. They are simple in a sense
public class ImportsPopulator extends AbstractPopulator
public class FieldsPopulator extends AbstractPopulator
public class LeftHandSidePopulator extends AbstractPopulator
But I need for each of them to have their own injected next field. For example for leftHandSide I want righthandside and so on.
How to achieve that using google guice?
As a solution, I decided to do this.
In AbstractPopulator I added abstract method injectNext
protected abstract void injectNext(ITemplatePopulator next);
and removed #Inject annotation for the field next itself.
In each child class I implemented this method like this
#Override
#Inject
protected void injectNext(#Named("rightHandSidePopulator") ITemplatePopulator next) {
setNext(next);
}
where I specified via #Named the name of the next populator in the chain of responsibility.
The last one populator is special
#Override
#Inject(optional = true)
protected void injectNext(#Named("null") ITemplatePopulator next) {
setNext(next);
}
I set the optional parameter of Inject annotation to true because according to Guice documentation
Method and field injections may be optional, which causes Guice to silently
ignore them when the dependencies aren't available
So if no object with null name found it won't wire next.
In the module class, I bound classes
#Override
protected void configure() {
bind(ITemplatePopulator.class)
.annotatedWith(Names.named("packageNamePopulator")).to(PackageNamePopulator.class);
...
And guice used it like this where needed
Injector injector = Guice.createInjector(new PopulatorModule());
ITemplatePopulator first = injector.getInstance(PackageNamePopulator.class); // first in chain
It seems to be working ok, but I am not sure whether it is the best solution and annotation imports are
import com.google.inject.Inject;
import com.google.inject.name.Named;

Get access to methods in child interface when using Spring autowiring

I have an interface A:
public interface Parent {
method1()
}
And an interface B:
public interface Child extends Parent{
method2()
}
Of course there is a class that implements interface B:
public class implements B{
#Override
method1(){
}
#override
method2(){
}
}
Now in a concrete class X, I use Spring autowiring to inject the interface "Parent":
public class X{
#Autowired
Parent parentImpl;
someMethod(){
}
)
But when I use the instance parentImpl, I only get access to method1
How can I get access to method2 in this case?
Thanks.
If you inject the interface Parent, there's no way to access method2() because it is only known in interface Child and not in Parent.
But if you inject a variable of interface Child in class X, then method2() would be accessible.
It is not a problem of Spring or Autowiring but of interfaces and implementations.
Field parentImpl has type Parent, so you can invoke only Parent's methods.
If you want to be able to invoke Child's methods you should #Autowired Child interface
This is not really a Spring question but Java question.
If you know that your concrete class can be of the sub interface you can cast it:
((Child)impl).method2();
You should check that your impl class is of the sub interface
if (impl instance of Child) {
((Child)impl).method2();
}
However, I don't think it is a good practice, what are you trying to achieve?
If you ignore Spring and Autowiring, you will have the same problem.
public class X {
private Parent parentImpl; //this is declared as a Parent.
public void someMethod() {
//This will see parentImpl as type Parent
//because that is how it is declared in this class.
}
)
If you want to be able to see parentImpl as a Child type, then it should be declared as such.

Limit a collection of autowired components using Package

I am working on a project for parsing files that uses Chains of Responsibility of an abstract class called EntityMapper that are used for parsing. Currently we have 2 types of Files/Entities:
GrantEntity
BillEntity
All EntityMappers extend the abstract class:
public abstract class EntityMapper<T extends AbstractBaseEntity> implements Function<MapperExchange, T>
Soon we will have a DonationEntity that will represent a file that has some structural characteristics as grantEntity.
Instead of creating new classes of Type extends EntityMapper<DonationEntity> I wanted to ask if there is a way to filter an #AutoWired collection using package names or a regex.
Something like ?:
#Autowired
#ComponentScan("com.my.package.first,com.my.package.second")
private List<EntityMapper<GrantEntity>> entityMappers;
I unfortunately did not find an answer in the link below except to do it by hand and remove the elements from the collection:
How to filter a collection of beans using a collection of regex in Spring?
You can use #Qualifer annotation to indicate logically similar components. Then specify a matching #Qualifier to the injection target. For example
class DependencyToInject{
}
#Configuration
public class AppConfig{
#Bean
#Qualifier("main")
public DependencyToInject dependency1(){
//return instance
}
#Bean
#Qualifier("main")
public DependencyToInject dependency2(){
//return instance
}
#Bean
#Qualifier("sub")
public DependencyToInject dependency3(){
//return instance
}
}
#Component
public class DependentClass{
#Autowired
#Qualifier("main")
private List<DependencyToInject> mainList;
#Autowired
#Qualifier("sub")
private List<DependencyToInject> subList;
}

Categories

Resources