CDI - #Any and #Inject - spring

Trying to inject bean in a class which has field with #Any annotation. But getting error as -
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.enterprise.inject.Instance' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#javax.inject.Inject(), #javax.enterprise.inject.Any()}
#Named
#Singleton
public class ProcessorFactoryImpl implements ProcessorFactory {
#Inject #Any
private Instance<Processor> processorList;
}
Interface is
public interface Processor {
some method
}
And implementing class is :
#Named
#Singleton
#Default
public class ProcessorImpl implements Processor {
}
For now, I have only one implementation so did not create qualifiers.

You are mixing Spring DI and CDI which are not made to work together.
Choose one of them but not both.
If you choose CDI
#Named
#ApplicationScoped
public class ProcessorFactoryImpl implements ProcessorFactory
{
#Inject
private Processor processor;
}
and
#Dependent
#Default
public class ProcessorImpl implements Processor {
// etc ...
}
In this case, the processor attribute is not a List ! You should think about what you expect. If you want a List<Processor>, you will have to use a CDI Producer instead.
If you choose Spring DI
#Component
public class ProcessorFactoryImpl implements ProcessorFactory
{
#Inject // or #Autowired
private Processor processor;
}
and
#Scope("prototype")
public class ProcessorImpl implements Processor
{
// etc ...
}
Mixing Spring and CDI
As written in the comments below, Spring can use #Inject and #Named as theses annotations are part of JSR-330.
The trouble is that too much framework mixing and using #Inject on an Instance<T>field cannot be achieved like that with Spring as it is a CDI feature.
To use the same feature, use #Provider from Spring.
Example :
CDI
#Inject
private Instance<MyClass> lazyInstance;
usage :
MyClasse instance = lazyInstance.get();
Spring
#Inject // or #Autowired
private Provider<MyClass> lazyInstance;
usage (same as CDI):
MyClasse instance = lazyInstance.get();

Have you tried List instead of Instance?
#Autowired
private List<Processor> processorList;

Related

How to use unit of work in rest controller properly?

public interface CourseRepo extends CrudRepository<Course, Long> {
}
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class UnitOfWork {
CourseRepo courses;
StudentRepository students;
StudyProgramRepository studyPrograms;
StudySchemeRepo studySchemes;
FeeStructureRepository feeStructures;
}
#RestController
public class TestController {
#Autowired
UnitOfWork uow;
#GetMapping("/addcr")
public String addCourse() {
Course cr = new Course();
cr.setTitle("DingDong course");
uow.getCourses().save(cr);
return "course Added..!!" ;
}
APPLICATION FAILED TO START
***************************
Description:
Field uow in com.srs.TestController required a bean of type 'com.srs.uow.UnitOfWork' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.srs.uow.UnitOfWork' in your configuration.
if i remove autowired and add a bean
#RestController
public class TestController {
#Bean
public UnitOfWork uow() {
return new UnitOfWork();
}
#GetMapping("/addcr")
public String addCourse() {
Course cr = new Course();
cr.setTitle("DingDong course");
uow().getCourses().save(cr);
return "course Added..!!" ;
}
java.lang.NullPointerException: Cannot invoke "com.srs.jpa.CourseRepo.save(Object)"
because the return value of "com.srs.uow.UnitOfWork.getCourses()" is null
i tried both autowired and in this case how can i use autowired or bean properly ?
Your class need to be annotated with #Component to be used with DI provider by #Autowired annotation
For the same reason each repository of your class need to be annotated with #Autowired
The Error Message gives the answer.
Field uow in com.srs.TestController required a bean of type 'com.srs.uow.UnitOfWork' that could not be found.
spring is searching for a bean from type UnitOfWork. You have to add this class to the application context from spring boot. To accomplish this you have to annotate the class UnitOfWork with #bean or #Data if you use lombok.
After this the spring application can find the Class UnitOfWork and auto wire it.
Since UnitOfWork (a somewhat misleading name in the JPA context) autowires data repositories, it has to be a Spring Bean itself.
The easiest and most common way is to annotate the class with one of the annotations #Service, #Component or #Bean, depending on the semantic of the class. There are also other ways, like the #Bean on method-level as you used.
To use the fully initialized bean you need to autowire it where you want to use it, not calling the create method. E.g. calling uow() as in your sample, bypasses the Spring Bean mechanism and creates a new instance, which hasn't been fully initialized (thus the NullPointerException).
Usually, the beans are autowired as fields, sometimes they are autowired in mehtod parameters (especially when working with #Bean on method-level in the same class).
E.g.
#Component
#Getter
#RequiredArgsConstructor
public class UnitOfWork {
private final CourseRepo courses;
private final StudentRepository students;
private final StudyProgramRepository studyPrograms;
private final StudySchemeRepo studySchemes;
private final FeeStructureRepository feeStructures;
}

spring boot 2.1.3 onward throws circular reference

public abstract class CommonBillService implements BillService {
#Autowired
#Qualifier("onlineProfitServiceImpl")
private ProfitService profitService;
....
}
#Service
public class OnlineProfitServiceImpl implements ProfitService {
#Autowired
#Qualifier("aBillServiceImpl")
private BillService aBillService;
}
#Service
public class ABillServiceImpl extends CommonBillService implements Move {
....//inject other services or dao here with #Autowired,
//there is no OnlineProfitService here explicitly, but its parent CommonBillService inject OnlineProfitService by autowired
}
this code works under spring boot 2.1.2, but failed with circular reference under 2.1.3:
Error creating bean with name 'aBillServiceImpl':
Bean with name 'aBillServiceImpl' has been injected into other beans [onlineProfitServiceImpl]
in its raw version as part of a circular reference, but has eventually been wrapped.
This means that said other beans do not use the final version of the bean.
but my code has no constructor injection, i just use #Autowired to inject, so it is not possible to throw circular reference, right?

Fail to autowire dependency in test

I'd like to write a Spring integration test to make sure that #Autowired correctly puts together my classes, but fail.
The test class
#RunWith(SpringRunner.class)
#DataJpaTest
#EntityScan(basePackageClasses = {ClassUnderTest.class, SomRepository.class, SomeEntity.class})
public class ClassUnderTestIT{
#Autowired private InterfaceUnderTest cut;
#Test public void autowires() {
assertThat(cut).isNotNull();
}
}
Should test that this #Service autowires
#Service
#Transactional
public class ClassUnderTest implements InterfaceUnderTest {
private final SomeRepository repository;
#Autowired
public DefaultWatchlistDataModifier(SomeRepository repository) {
this.repository = repository;
}
}
Paying special attention to the wired dependency
#Repository
#Transactional(readOnly = true)
#Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
public interface SomeRepository extends JpaRepository<SomeEntity, String> {
}
However, all I ever get is the exception
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'com.[...].InterfaceUnderTest' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Meanwhile, I have experimented with all kinds of additional annotations, such as #ComponentScan, #EnableJpaRepositories ... whatever I could dig up in the endless number of StackOverflow questions on the topic - all in vain.
Using [#DataJpaTest] will only bootstrap the JPA part of your Spring Boot application. As the unit of your test isn't part of that subset it will not be available in the application context.
Either construct it yourself and inject the dependencies or use a full blown #SpringBootTest instead.

Spring #Autowired annotaion

Spring #Autowired
I have a doubt on Spring #Autowired annotation.Please Help...
In Spring mvc ,when I tried #Autowired in this order
Controller--->Service--->Dao
ie,In Controller I autowired Service Class Object , In Service Class Autowire Dao Object.
This Injection chain works perfectly.
Similliarly In strutrs2+Spring ,I applied #Autowired Annotation in this way
Action--->Service-->Dao
This Injection chain also works fine.
If I call a funtion from outside this chain (eg:Custom Taglib class (from jsp)) to funtion in Service class Then in this Service class the Autowired dao object is null(ie,this call braks the chain).
My questions is
Is this #Autowired works in a Injection chain Only?
Beans that have #Autowired fields only have them set if they are sent through the Spring Bean Postprocessor -- that is, like you said, if you autowire them yourself. That is a big reason that constructor injection is much more preferred than field injection. Instead of doing
#Service
public class MyService {
#Autowired
private MyDao dao;
...
}
you should do
#Service
public class MyService {
private final MyDao dao;
#Autowired
public MyService(MyDao dao) {
this.dao = dao;
}
}
That way, when you're in a situation where you can't rely on a service to be post-processed (as in your case of using the jsp tag library), you can simply instantiate a new instance with a MyDao object and be on your merry way.

Could not autowire field when bean implements some interface with Spring

I am using Spring in my Java Application, all the #Autowired annotations working until now.
Simplified example would be:
#Component
public class MyBean implements MyInterface {
...
}
#Component
public class MyOtherBean {
#Autowired
private MyBean myBean;
...
}
Once I try to start the Application, I get:
java.lang.IllegalArgumentException: Can not set MyBean field MyOtherBean.myBean to $ProxyXX
The interface contains just two public simple methods and the class implements them.
Both classes are public and have public default constructor. (I even tried to instantiate them in tests.
Once I remove the implements section, everything works correctly.
What can be wrong with the implementation of the interface? What is $ProxyXX?
I suspect the issue is that Spring is injecting an AOP proxy which implements MyInterface - possibly for the purposes of transaction management or caching. Are any of MyBean's methods annotated #Transactional or annotated with any other annotation?
Ideally you'd probably want to reference MyBean by it's interface type - which should resolve the issue.
#Component
public class MyOtherBean {
#Autowired
private MyInterface myBean;
...
}
If you have more than one bean implementing MyInterface then you an always qualify your bean by name.
#Component
public class MyOtherBean {
#Autowired
#Qualifier("myBean")
private MyInterface myBean;
...
}
By default, Spring uses Java dynamic proxies to implement AOP when the bean implements an interface. The easiest and cleanest way to solve your problem is to make program on interfaces, and inject theinterface insted of the concrete class:
#Component
public class MyOtherBean {
#Autowired
private MyInterface myBean;
...
}
See http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/htmlsingle/#aop-proxying for how to force Spring to always use CGLib.

Resources