I'm defining a Java EE bean as follows:
#LocalBean
#Stateless
public class GreetingBean {
private HelloBean helloBean;
#Inject
public void setHelloBean(HelloBean helloBean) {
this.helloBean = helloBean;
}
// ...
}
And:
#Named
public class HelloBean {
public HelloBean() { // ... }
public HelloBean(String hello) { // ... }
}
Now, how can I inject the GreetingBean into another class by also setting an HelloBean instance for it?
Supposing that I've two different constructors for the HelloBean class (the one with an argument, for instance a String, the other without [default]), how can I properly inject either?
If you have two different constructors, this is very different question from this that you are asking here. In this case the default constructor (without arguments) will be called when HelloBean gets instantiated.
To inject a bean instance using arguments you have to use a producer method which will instantiate HelloBean. More info can be found here and here.
Related
I've got a Factory class in Java with some methods which return some Java Bean. All of these Java Beans have some DAO object as fields which are injected with the annotation #EJB. However in every case these DAO are all Null, so I suppose I've a problem with EJB injection. I use WebLogic for deploy. Any suggestions to resolve the issue?
//Factory class
public class Factory extends AbstractFactory {
#Override
public InterfaceService getService() {
return new ClassBean();
}
}
//Bean class
#Stateless(mappedName = "ClassBean")
#LocalBean
public class ClassBean implements IBeanService {
#EJB(beanName = "ClassDAO")
private ClassDAO classDAO;
public List<String> getList() throws ExpectedModelException {
return classDAO.getStringList(); //this one throws NullPointerException
}
Never create Enterprise-Beans using new.
The creation, caching, deletion,... is done by the container.
You must declare ClassDao as #Stateless or #Singleton, ... and the container will create and find it, hopefully if the names are correct.
The Factory is not necessary.
I am trying to autowire a member in a class using the constructor.
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(ClassA objectA) {
myMember = objectA;
}
}
If I have multiple sources that create beans of ClassA, is it possible to have a duplicate constructor definition that instantiates based on the bean that was autowired into this class?
I want to do something like this:
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(#Qualifier ("qualifierA") ClassA objectA) {
myMember = objectA;
}
#Autowire
public MyClass(#Qualifier ("qualifierB") ClassA objectB) {
myMember = objectB;
}
}
I tried using #Qualifier this way, but it didn't work.
Is it possible to do what I'm trying to do, with Spring? How can I disambiguate based on the name (qualifierA) or (qualifierB), if the bean definition is like:
#Bean (name = "qualifierA")
public ClassA getQualifierA() {
...
}
#Bean (name = "qualifierB")
public ClassA getQualifierB() {
...
}
You can't have two constructors with the exact same signature in a single class in Java. Nor any other programming language I've ever encountered. You might use method-injection instead, with two methods (named differently, of course), mark them as #Autowired(required = false) and use the proper #Qualifier(...) to specify the instance you want to inject. You might want to handle the case when both instances are present in the spring context, so no unexpected things happen.
The short answer is: no, that is not possible. In Java you cannot have two constructors with exactly the same signature. And also, you can assign only one value to your "myMember".
However, what are you trying to accomplish here? It seems that in some occasions MyClass needs to use "objectA" and in other occasions, you need "objectB".
For these scenarios, you should not use autowiring (you can't), but simply use explicit wiring:
#Bean
MyClass myObject() {
return new MyClass(qualifierA());
}
I have a class which I want to be a bean
public class SomeBean{
public SomeBean(){
//default constructor
}
public SomeBean(String someStr){
//constructor with arguments.
}
}
In order to create manually CDI bean I do the following
Bean<?> bean = (Bean<?>) beanManager.resolve(beanManager.getBeans(SomeBean.class));
SomeBean someBean =(SomeBean) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
However the above method will create SomeBean instance wth default constructor. How can I create bean and pass String argument to construcot?
P.S. CDI - WELD
The standard way to define beans with given constructor arguments is via a producer method, e.g.
#Produces #ApplicationScoped #MyQualifier
public SomeBean myBean() {
return new SomeBean("foo");
}
Application code should not normally have to use the BeanManager, unless you want to create a CDI extension.
I want to externalize commonly used applicationlogic into a "utility class" called Helper. The applicationlogic needs other CDI beans to work.
Two possibilities:
a)
#SessionScoped
class ControllerWithCdiBean {
#Inject
Helper helper;
public void doIt() {
Object result = helpder.calculate();
}
}
#RequestScoped
class Helper{
#Inject
Service anyService;
public Object calculate() {
return anyService.calc();
}
}
b)
#SessionScoped
class ControllerWithStaticCallsViaDeltaspike {
public void doIt() {
Object result = Helpder.calculate();
}
}
class Helper{
private static Service anyService = BeanProvider.getContextualReference(Service.class);
public static Object calculate() {
return anyService.calc();
}
What about performance? Are there any notable differences? Both solutions are possible for me, is one solutions better than the other?
One disadvantage:
Helpder gets initialized for every Request.
Mark your Helper class as #ApplicationScoped. With this, you will have a single instance per application context.
Still, if it's just an utility class, it shouldn't be a managed bean at all. I would instead mark it as final, define a private constructor and mark all the methods as static. This is because since it's an utility class, it doesn't need to maintain any state.
Based on parameters passed to a method, I need to select from one of many Spring beans that are implementations of the same class, but configured with different parameters.
E.g. if user A invokes the method, I need to call dooFoo() on bean A, but if it's user B then I need to call the very same method, only on bean B.
Is there a 'Springier' way of doing this other than sticking all the beans in a map, and deriving a key from the parameters passed to my method?
We face that issue in our project, and we solve it through a Factory-Like class. The client class -the one that needed the bean at runtime- had an instance of the factory, that was injected through Spring:
#Component
public class ImTheClient{
#Autowired
private ImTheFactory factory;
public void doSomething(
Parameters parameters) throws Exception{
IWantThis theInstance = factory.getInstance(parameters);
}
}
So, the IWantThis instance depends on the runtime value of the parameters parameter. The Factory implementation goes like this:
#Component
public class ImTheFactoryImpl implements
ImTheFactory {
#Autowired
private IWantThisBadly anInstance;
#Autowired
private IAlsoWantThis anotherInstance;
#Override
public IWantThis getInstance(Parameters parameters) {
if (parameters.equals(Parameters.THIS)) {
return anInstance;
}
if (parameters.equals(Parameters.THAT)) {
return anotherInstance;
}
return null;
}
}
So, the factory instance holds reference to both of the posible values of the IWantThis class, being IWantThisBadly and IAlsoWantThis both implementations of IWantThis.
Seems like do you want a ServiceLocator using the application context as registry.
See ServiceLocatorFactoryBean support class for creating ServiceLocators mapping keys to bean names without coupling client code to Spring.
Other option is to use a naming convention or annotation based configuration.
for example, assuming that you annotate Services with #ExampleAnnotation("someId"), you can use something like the following Service Locator to retrieve them.
public class AnnotationServiceLocator implements ServiceLocator {
#Autowired
private ApplicationContext context;
private Map<String, Service> services;
public Service getService(String id) {
checkServices();
return services.get(id);
}
private void checkServices() {
if (services == null) {
services = new HashMap<String, Service>();
Map<String, Object> beans = context.getBeansWithAnnotation(ExampleAnnotation.class);
for (Object bean : beans.values()) {
ExampleAnnotation ann = bean.getClass().getAnnotation(ExampleAnnotation.class);
services.put(ann.value(), (Service) bean);
}
}
}
}
Sticking them in a map sounds fine. If it's a Spring-managed map (using util:map, or in Java config), that's better than creating it somewhere else, because then Spring owns all the object references and can manage their lifecycle properly.
If the beans (A, B) you are talking about are SessionScope its no problem at all, they will be selected correctly.
public class BusinessLogic {
private BaseClassOfBeanAandB bean;
public void methodCalledByUserAorB() {
bean.doFoo();
}
}