I want to add a dependency to an EJB. How do I do this using Spring? The dependent object is a general service object. Based on code below I want to wire myDependency without having to use 'new'.
The EJB runs in weblogic.
#Stateless(mappedName = "MyBean")
public class MyBean implements MyBeanRemote, MyBeanLocal {
#EJB(name = "MyOtherBean")
private MyOtherBean myOtherBean;
private MyDependency myDependency;
...
}
This is well described in the Spring documentation:
For EJB 3 Session Beans and Message-Driven Beans, Spring provides a
convenient interceptor that resolves Spring 2.5's #Autowired
annotation in the EJB component class:
org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.
This interceptor can be applied through an #Interceptors annotation in
the EJB component class, or through an interceptor-binding XML element
in the EJB deployment descriptor.
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class MyFacadeEJB implements MyFacadeLocal {
// automatically injected with a matching Spring bean
#Autowired
private MyComponent myComp;
// for business method, delegate to POJO service impl.
public String myFacadeMethod(...) {
return myComp.myMethod(...);
}
...
}
Stateless EJBs and Spring beans, however, offer more or less the same possibilities. Mixing them together seems like unnecessary complexity.
Related
I have several service like that:
#Singleton
public SimpleService {
...
}
I have Managed Bean #ViewScoped which should create some complex objects. These objects should execute business-logic. I need to pass these services to this object.
Example of Managed Bean:
#ManagedBean
#ViewScoped
public class ExampleBean {
#Inject
private SimpleService simpleService;
...
public void customLogic() {
// in this method I should create complex object which should have services and some data.
// current implementation
ComplexObject object = new ComplexObject(SimpleService simpleService, ...)
}
}
Services are injected to Managed Bean by #Inject annotation. For creating these objects - I'm using the constructor and pass these services as params. The question is: can I have better solution than passing services in constructor?
You can:
Inject by method:
private MyService myService;
#Inject
public void setMyService(MyService ms) {
this.myService = ms;
}
Inject by field:
#Inject
private MyService myService;
Fetch reference through CDI (not recommended, except in advanced usecases):
...
MyService myService = CDI.current().select(MyService.class).get();
...
Fetch reference through BeanManager (not recommended, except in advanced usecases or CDI 1.0):
...
BeanManager beanManager = CDI.getBeanManager(); // you can fetch a BeanManager reference by several other methods, I use CDI for simplicity here
MyService myService = beanManager.getReference(MyService.class);
...
If your #Singleton annotation is javax.ejb.Singleton and not javax.inject.Singleton, then your bean is actually a EJB and you can also use any mechanism that allows you to access EJB, such as #Resource annotations, or through the JNDI context.
Personally I tend to inject by method as I find it the most flexible option most of the time. In my opinion it is also the most "portable" to other frameworks (e.g: Spring)
Remember that when you use either the CDI.current() or the BeanManager methods to fetch #Dependent beans, you are responsible to manually destroy the fetched bean when you are done with it, so that you do not fall into this CDI-related memory leak. When using CDI.current() it is as easy as saving the Instance reference and invoking it afterwards:
...
Instance<MyService> msInstance = CDI.current().select(MyService.class);
MyService myService = msInstance.get();
...
msInstance.destroy(myService);
...
The BeanManager method is too low-level and should only be used in CDI 1.0 environments (back when the CDI class did not exist yet). You can read the linked StackOverflow question for more details.
What you are doing is perfectly fine. You are using the ManagedBean as a bridge to inject the services and then passing the injected variables to a ComplexObject that need the services.
The only restriction that should be considered is, could the ComplexObject class be a ManagedBean itself? That way you could inject everything directly on it, but if it is not possible, you may use the bean for that.
I prefer the inject by field option mentioned because I think it is a little more readable.
I'm trying to look up my stateless bean using the annotation class #EJB, but fails. I'm using WildFly 10 as EE container. The stateless bean interface looks as follows:
#Local
public interface T1Service {
String sayHi();
}
The implementation class:
#Stateless
public class T1ServiceImpl implements T1Service {
#Override
public String sayHi() {
return "Hi!";
}
}
In my controller I want to inject the service:
#EJB(lookup = "javaee/T1ServiceImpl")
private T1Service t1Service;
Make the call:
t1Service.sayHi();
But it fails with a NullPointerException (t1Service is null).
What am I missing?
Note, the JNDI bindings are:
java:global/javaee/T1ServiceImpl!p1.T1Service
java:app/javaee/T1ServiceImpl!p1.T1Service
java:module/T1ServiceImpl!p1.T1Service
java:jboss/exported/javaee/T1ServiceImpl!p1.T1Service
java:global/javaee/T1ServiceImpl
java:app/javaee/T1ServiceImpl
java:module/T1ServiceImpl
The controller where you want to inject the T1Service is also a #Stateless Bean? If it is runnning in the same application you can omit the definition of property lookup.
I would also suggest to use CDI (#Inject) in case that you are using Java EE 6/7/8. (see here for more information)
I understand that a managed bean works like a controller, because your only task is "link" the View Layer with Model.
To use a bean as a managed bean I must declare #ManagedBeanannotation, doing that I can communicate JSF with bean directly.
If I want to inject some component (from Spring) in this managedBean I have two possibles ways:
Choose the property in ManagedBean (like "BasicDAO dao") and declare #ManagedProperty(#{"basicDAO"}) above the property. Doing it, i'm injecting the bean "basicDAO" from Spring in ManagedBean.
Declared #Controller in ManagedBean Class, then i'll have #ManagedBean and #Controller annotations, all together. And in property "BasicDAO dao" i must use #Autowired from Spring.
Is my understanding correct?
#ManagedBean vs #Controller
First of all, you should choose one framework to manage your beans. You should choose either JSF or Spring (or CDI) to manage your beans. Whilst the following works, it is fundamentally wrong:
#ManagedBean // JSF-managed.
#Controller // Spring-managed.
public class BadBean {}
You end up with two completely separate instances of the very same managed bean class, one managed by JSF and another one managed by Spring. It's not directly clear which one would actually be used in EL when you reference it as #{someBean}. If you have the SpringBeanFacesELResolver registered in faces-config.xml, then it would be the Spring-managed one, not the JSF-managed one. If you don't have that, then it would be the JSF-managed one.
Also, when you declare a JSF managed bean specific scope, such as #RequestScoped, #ViewScoped, #SessionScoped or #ApplicationScoped from javax.faces.* package, it will only be recognized and used by #ManagedBean. It won't be understood by #Controller as it expects its own #Scope annotation. This defaults to singleton (application scope) when absent.
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
#Controller // Spring-managed (without own scope, so actually becomes a singleton).
public class BadBean {}
When you reference the above bean via #{someBean}, it would return the Spring-managed application scoped bean, not the JSF-managed view scoped bean.
#ManagedProperty vs #Autowired
The JSF-specific #ManagedProperty works only in JSF-managed beans, i.e. when you're using #ManagedBean. The Spring-specific #Autowired works only in Spring-managed beans, i.e. when you're using #Controller. Below approaches are less or more equivalent and cannot be mixed:
#ManagedBean // JSF-managed.
#RequestScoped // JSF-managed scope.
public class GoodBean {
#ManagedProperty("#{springBeanName}")
private SpringBeanClass springBeanName; // Setter required.
}
#Component // Spring-managed.
#Scope("request") // Spring-managed scope.
public class GoodBean {
#Autowired
private SpringBeanClass springBeanName; // No setter required.
}
Do note that when you have the SpringBeanFacesELResolver registered in faces-config.xml as per the javadoc,
<application>
...
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
and thus you can reference Spring managed beans in EL via #{springBeanName}, then you can just reference them in #ManagedProperty too, as it basically sets the evaluated result of the given EL expression. The other way round, injecting a JSF managed bean via #Autowired, is in no way supported. You can however use #Autowired in a JSF managed bean when you extend your bean from SpringBeanAutowiringSupport. This will automatically register the JSF managed bean instance in Spring autowirable context during constructor invocation, which means that everything #Autowired will be available in #PostConstruct and later.
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
public class GoodBean extends SpringBeanAutowiringSupport implements Serializable {
#Autowired
private SpringBeanClass springBeanName; // No setter required.
#PostConstruct
private void init() {
// springBeanName is now available.
}
}
Or when your architecture doesn't allow extending beans from a different base class, then you can always manually register the JSF managed bean instance in Spring autowirable context as below. See also How to integrate JSF 2 and Spring 3 (or Spring 4) nicely for the trick.
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
public class GoodBean implements Serializable {
#Autowired
private SpringBeanClass springBeanName; // No setter required.
#PostConstruct
private void init() {
FacesContextUtils
.getRequiredWebApplicationContext(FacesContext.getCurrentInstance())
.getAutowireCapableBeanFactory().autowireBean(this);
// springBeanName is now available.
}
}
#XxxScoped vs #Scope
Spring's #Scope has limited support for JSF scopes. There's no equivalent for JSF's #ViewScoped. You'd basically either homegrow your own scopes, or stick to manually registering the JSF managed bean instance in Spring autowirable context as shown above.
And, from the other side on, Spring WebFlow was taken over in JSF 2.2 via new #FlowScoped annotation. So if you happen to be on JSF 2.2 already, then you don't necessarily need to use Spring WebFlow if you solely want the flow scope.
CDI - trying to unify it all
Since Java EE 6, CDI is offered as standard alternative to Spring DI. It has respectively #Named and #Inject annotations for this and also its own set of scopes. I'm not sure how it interacts with Spring as I don't use Spring, but #Inject works inside a #ManagedBean, and #ManagedProperty inside a #ManagedBean can reference a #Named bean. On the other hand, #ManagedProperty doesn't work inside a #Named bean.
The purpose of CDI is to unify all different bean management frameworks into only one specification/inteface. Spring could have been a full CDI implementation, but they choosed to only partially implement it (only JSR-330 javax.inject.* is supported, but JSR-299 javax.enterprise.context.* not). See also Will Spring support CDI? and this tutorial.
JSF will be moving to CDI for bean management and deprecate #ManagedBean and friends in a future version.
#Named // CDI-managed.
#ViewScoped // CDI-managed scope.
public class BetterBean implements Serializable {
#Inject
private SpringBeanClass springBeanName; // No setter required.
#PostConstruct
private void init() {
// springBeanName is now available.
}
}
See also:
When is it necessary or convenient to use Spring or EJB3 or all of them together?
JSF Service Layer
Backing beans (#ManagedBean) or CDI Beans (#Named)?
Using JSF as view technology of Spring MVC
How to install and use CDI on Tomcat?
There is another way to use Spring-managed beans in JSF-managed beans by simply extending your JSF bean from SpringBeanAutowiringSupport and Spring will handle the dependency injection.
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
public class GoodBean extends SpringBeanAutowiringSupport {
#Autowired
private SpringBeanClass springBeanName; // No setter required.
// springBeanName is now available.
}
The easy way to do this is via XML. I used #Component in already made jsf managed bean but #Autowired did not work because managed bean was already there in faces-config.xml. If it is mandatory to keep that managed bean definition along with its managed property in the xml file then it is suggested to add the spring bean as another managed property inside the managed bean tag. Here the spring bean is there defined in spring-config.xml(can be autowired somewhere alternately). please refer
https://stackoverflow.com/a/19904591/5620851
edited by me. I suggest to either implement it altogether through annotation #Managed and #Component or via xml for both.
You can autowire individual beans without #Autowired by leveraging getBean of the current WebApplication context.
Please refer to #BalusC's answer for more details. This is just a slight modification over his example:
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
public class GoodBean implements Serializable {
// #Autowired // No Autowired required
private SpringBeanClass springBeanName; // No setter required.
#PostConstruct
private void init() {
WebApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
this.springBeanName = ctx.getBean(SpringBeanClass.class);
// springBeanName is now available.
}
}
I have a testcase which makes use of OpenEjb's #LocalClient annotation (embedded container) and injects EJBs using the #EJB annotation:
#LocalClient
public class MyTestCase {
#EJB
private BoxDao boxDao;
...
}
BoxDao is a remote EJB interface. Now, for testing, I need to access some internal state of BoxDao's implementation BoxDaoBean, which is a stateful session bean. I created a protected method in BoxDaoBean, which exposes the needed internal state, but I found not yet a way to access it in my test case, since the injected BoxDao is a remote interface proxy (an cannot be cast to BoxDaoBean).
Is there a way to access the stateful session bean behind the remote interface BoxDao in the test case? Would not matter if solution is OpenEjb specific.
Update: We can't use EJB 3.1 specific solutions unfortunately, as we have several EJB 3.0 projects running. Using Proxy.getInvocationHandler(boxDao), I can get access to the OpenEjb container, via StatefulEjbObjectHandler. Is it possible to access the stateful bean this way?
You could try having BoxDaoBean also expose an #LocalBean interface. A single EJB can expose a near unlimited number of views from #WebService, #Local, #Remote, JAX-RS and more.
Just update your bean like so:
#Stateful
#LocalBean
public class BoxDaoBean implements BoxDao {
//...
}
Then add another field to your test:
#LocalClient
public class MyTestCase {
#EJB
private BoxDao boxDao;
#EJB
private BoxDaoBean boxDaoBean;
...
}
I'm trying to replace my CDI/EJB annotations with Spring ones. But I'm struggeling how to do it right.
This is what I have in CDI/EJB:
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
class Service {
#Inject
EntityManager em;
}
#Named
#RequestScoped
class Facade {
#Inject
Service service;
}
Now I would do the following:
#Stateless
#Transactional
#Repository
class Service {
#Inject
EntityManager em;
}
What about the stateless? What is the aquivalent in spring?
Obvious I cannot just remove this annotation, bc then I'm getting these exception:
javax.el.PropertyNotFoundException: /input.xhtml #15,30 registerButtonAction="#{facade.createNew()}": The class 'Facade$Proxy$_$$_WeldClientProxy' does not have the property ...
Further:
#Named
#Service
class Facade {
#Autowired
Service service;
}
Do I have to simply replace all #Inject annotations with #Autowired?
Is there something in Spring that takes care of EL naming, so that I can remove the #Named?
Do I have to annotate my JPA entities too?
Stateless and Stateful Beans are EJB concepts, but Spring offers similar services through Service Beans. Put the #Service annotation in your Business Logic classes, and if you want your beans to be "Stateless" or "Stateful" just configure your bean scope (like Request or Session).
Spring also has a built-in transaction management API, so your Transaction annotations may need to be changed.
Finally, Spring is compatible with many persistence frameworks including JPA. IF you want to keep JPA it is OK, and feel free to change it for another technology if you desire (maybe Hibernate, or MyBatis)
The stateless and stateful concepts are EJB; Spring doesn't have such a notion. Spring uses POJOs, without any support for stateful beans. You're on your own there.
Spring uses javax.annotation.Resource annotation; I'd prefer that to #Autowired.
Spring supports #Inject and #Named directly. No need to use #Autowired and #Component (Spring's equivalents) if you don't want to. No need to bring in #Resource either.
// This is a singleton by default, which is OK since you previously
// had it marked as stateless
#Named
#Transactional(propagation=Propagation.REQUIRES_NEW)
class Service {
#PersistenceContext // Use JPA's usual annotation
EntityManager em;
}
// You may not still need this, but if you do ...
#Named
#Scope("request")
class Facade {
#Inject
Service service;
}