CDI Injection failed on parent abstract class - ejb-3.0

is there a problem injecting a session scope named component in a parent abstract class?
Here's the setup:
I have an interface:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })
public #interface CurrentTeacher { }
Which I use to produce current student (in session scoped):
#Named
#SessionScoped
public class CurrentStudentBean implements Serializable {
#Produces
#Named("currentTeacher")
#currentTeacher
public Teacher getCurrentTeacher() {
//...
return currentTeacher;
}
}
The quite confusing part of how I injected it in order.
page.xhtml->UserBean.java
page.xhtml:
<p:commandButton action="userBean.deleteSubject()" value="delete" />
Contains an action to delete a subject.
#Named
#ConversationScoped
public class StudentBean.java extends BaseBean {
#Inject
StudentService studentService;
}
public abstract class BaseBean {
#Inject
#CurrentTeacher
private Teacher currentTeacher; //injection OK
public void deleteSubject() {
getService().deleteSubject();
//returns studentService from UserBean and calls BaseService.deleteSubject();
}
}
#Stateless
#LocalBean
public class StudentService extends BaseService {
}
public abstract class BaseService {
#Inject
#CurrentTeacher
private Teacher currentTeacher; //injection FAILED, currentTeacher always null
public void deleteSubject() {
if(currentTeacher != null) { //do something }
}
public Student getTeacher() {
return currentTeacher;
}
}

Related

How to autowire a method of a generic service

I have a Service class that has a generic type and a setController method that is based on the same generic type. the generic type of the servic object is only known at the time of declaration.
The problem is now when i define a ControllerImpl where the generic type is defined the #Autowired method of setController does not use that component.
Has somebody an idea how to fix it and keep the ServiceImpl generic. (it would work when i define the typ in ServiceImpl as well).
The following example show the problem i'm facing with:
#SpringBootTest
#ActiveProfiles("local")
public class AccessTest {
#Autowired
private ServiceA<BeanA> service;
#Test
void test(){
Assertions.assertNotNull(service.controller);
}
interface ValueGetter{
}
static class BeanA implements ValueGetter{
}
static class AbstractService<B extends ValueGetter>{
Controller<B> controller;
#Autowired
void setController(#Nullable Controller<B> controller){
this.controller = controller;
}
}
interface Controller<B extends ValueGetter>{
void doSomething(B value);
}
//not inner class
#Service
public class ServiceA<B extends AccessTest.ValueGetter> extends AccessTest.AbstractService<B> {
}
//not inner class
#Component
public class ControllerImpl implements AccessTest.Controller<AccessTest.BeanA> {
#Override
public void doSomething(final AccessTest.BeanA value) {
}
}
}

How can I autowire a specific implementation of an interface by its bean name in Spring

I have classes which implements MyInterface and their names are for example:
MyClassA, MyClassB etc.
How can I get the instance of the class by it's bean name? Something like:
context.getBean("myClassA")
context.getBean("myClassB")
Can I do it without configuring beans in the XML?
I want to use annotations
You can use qualifiers, e.g:
#Component
#Qualifier("classA")
public MyInterface ClassA {
return new ClassA();
}
#Component
#Qualifier("classB")
public MyInterface ClassB {
return new ClassB();
}
and use it like:
public class SomeClass {
#Autowired
#Qualifier("classA")
private MyInterface classA;
}
You have several options here. The easiest one would be using field names as a component name using #Autowire:
#Component("testClassA") // It is possible to omit explicit bean name declaration here since Spring will use a class name starting from lower case letter as a bean name by default. So just `#Component` should be sufficient here and below.
public TestClassA implements MyInterface {
}
#Component("testClassB")
public TestClassB implements MyInterface {
}
/*
* Note that field names are the same as the component names.
*/
#Component
public class TestClassWithDependencies {
#Autowired
private MyInterface testClassA;
#Autowired
private MyInterface testClassB;
}
Another option is to use qualifiers:
#Component
#Qualifier("testClassA")
public TestClassA implements MyInterface {
}
#Component
#Qualifier("testClassB")
public TestClassB implements MyInterface {
}
#Component
public class TestClassWithDependencies {
#Autowired
#Qualifier("testClassA")
private MyInterface testClassA;
#Autowired
#Qualifier("testClassB")
private MyInterface testClassB;
}
You could even create your own meta-annotations when you need to use the same qualifiers over and over again:
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
#Qualifier("testClassA")
public #interface TestClassACustomQualifier {
String value();
}
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
#Qualifier("testClassB")
public #interface TestClassBCustomQualifier {
String value();
}
#Component
public class TestClassWithDependencies {
#Autowired
#TestClassACustomQualifier
private MyInterface testClassA;
#Autowired
#TestClassBCustomQualifier
private MyInterface testClassB;
}
Much prettier, isn't it? One more option is to use #Resource from JSR-250 specification. As pointed out by #hovanessyan it's more JavaEE style of doing things, but still, I think it's a viable approach used on many projects:
#Component("testClassA")
public TestClassA implements MyInterface {
}
#Component("testClassB")
public TestClassB implements MyInterface {
}
#Component
public class TestClassWithDependencies {
#Resource(name="testClassA")
private MyInterface testClassA;
#Resource(name="testClassB")
private MyInterface testClassB;
}
More information you can get on https://www.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/, where discussed different approaches with tests added.
Hope this helps!
I think if above options don't suffice then factory implementation is one way to get instance on the fly -
#Component
public TestClassA implements MyInterface {
}
#Component
public TestClassB implements MyInterface {
}
define you factory this way -
public class MyInterfaceFactory extends AbstractFactoryBean<MyInterface> {
private String filter;
#Override
public Class<?> getObjectType() {
return MyInterface.class;
}
#Override
protected MyInterface createInstance() throws Exception {
MyInterface myInterface;
switch (filter)
{
case "1":
myInterface = new TestClassA();
break;
case "2":
myInterface = new TestClassB();
break;
default: throw new IllegalArgumentException("No such type.");
}
return myInterface;
}
}
and then your bean config -
#Configuration
public class FactoryBeanConfig {
#Bean(name = "myInterface")
public MyInterfaceFactory myInterfaceFactory() {
MyInterfaceFactory factory = new MyInterfaceFactory();
factory.setFilter("7070");
return factory;
}
}

Spring Bean Factory Configuration passing input parameter

I'm trying to create a BeanFactory called TaskBeanFactory that I can Autowire into another prototype class that's running on a thread. I want a different instance of a bean returned by the Factory based on a taskName that i want to pass into it but when i start the application i get a null pointer exception because the taskName is null. I had a look at this article but i'm confused about how I should configure the Factory and then pass in the taskName.
The Factory:
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.stereotype.Component;
#Data
#Component
#NoArgsConstructor
public class TaskBeanFactory extends AbstractFactoryBean<GenericTask>{
private TaskNameEnum taskName;
public TaskBeanFactory(TaskNameEnum taskName) {
setSingleton(false);
}
#Override
public Class<?> getObjectType() {
return GenericTask.class;
}
#Override
protected GenericTask createInstance() throws Exception {
switch (taskName) {
case FILE_OPERATION:
return new FileTask();
case DATA_OPERATION:
return new DataTask();
default:
return new GenericTask();
}
}
}
The classes used by the Factory:
#Data
public class GenericTask {
private String idTask;
public void executeTask(Work work) {};
}
#Component
#Scope(value="prototype")
public class FileTask extends GenericTask {
#Override
public void executeTask(Work work) {
//some processing
}
}
#Component
#Scope(value="prototype")
public class DataTask extends GenericTask {
#Override
public void executeTask(Work work) {
//some processing
}
}
and the thread that's calling the Factory:
#Slf4j
#Data
#Scope("prototype")
#Component
public class WorkerThread implements Runnable {
#Autowired
private TaskBeanFactory taskBeanFactory;
#Autowired
private DataService dataService;
#Override
public void run() {
//iterate a Map of taskIds from the dataService
taskBeanFactory.setTaskName(TaskNameEnum.valueOf(taskEntry.getKey()));
GenericTask genericTask = taskBeanFactory.getObject();
//expecting genericTask to be of Type FileTask if called with one Key
//or of Type DataTask if called with another
}
}
}

#Configurable not working on Subclass

Take the following general abstract class:
#Configurable
public abstract class TestEntityRoot {
public abstract String print();
}
And a subclass:
#Configurable
public class TestEntity extends TestEntityRoot{
private TestEntityService testEntityService;
#Autowired
public void setTestEntityService(TestEntityService testEntityService) {
this.testEntityService = testEntityService;
}
#Override
public String print() {
return testEntityService.print();
}
}
When call controller:
#RestController
public class TestEntityController {
#GetMapping(name = "/test")
public String print() {
TestEntity entity = new TestEntity();
return entity.print();
}
}
everything ok. But if call like this:
#RestController
public class TestEntityController {
#GetMapping(name = "/test")
public String print() {
TestEntityRoot entity = new TestEntity();
return entity.print();
}
}
i get null pointer. Is it possible that second example work?
In the second case you create manually the class rather than using spring's bean. Autowire the bean instead. See
#RestController
public class TestEntityController {
#Autowired
private TestEntity entity
#GetMapping(name = "/test")
public String print() {
return entity.print();
}
}

Why declare always Interfaces for DAO

Why we have always to declare first a interface to implement our DAO classes like this
Interface :
public interface IRegion<T extends Serializable> {
List<T> findAll();
}
DAO Class :
#Transactional
#Repository
public class RegionDAO implements IRegion < Region > {
#Autowired
private SessionFactory sessionFactory;
#Override
public List<Region> findAll() {
return sessionFactory.getCurrentSession().createQuery("from Region").list();
}
}
Controller :
#Controller
public class welcome {
#Autowired
private IRegion<Region> regionI;
....
}
But it works also when I keep just my DAO class and I remove the interface
#Repository
#Transactional
public class RegionDAO {
#Autowired
private SessionFactory sessionFactory;
public List<Region> findAll() {
return sessionFactory.getCurrentSession().createQuery("from Region").list();
}
}
Controller:
#Controller
public class welcome {
#Autowired
private RegionDAO regionDAO;
....
}
So why we have to add interfaces ?

Resources