I have following class
public class TransactionalTest {
#javax.inject.Inject
EntityManager em;
#com.google.inject.persist.Transactional
public void insertSomeData() {
Preferences p0 = new Preferences();
p0.setTemplatename("pref 01");
em.persist(p0);
}
}
I am using javax.inject.Inject instead of com.google.inject.Inject.
What is the correct annotation for Transactional, thus I have no dependencies to Guice?
From my memories, you will have to write your own annotation.
However, if you're in a JavaEE system, youc an use EJB TransactionAttribute. There also exist some CDI extensiosn, like Seam Solder or Apache DeltaSpike that may in a distant future provide such code outside of JavaEE containers.
Related
I would like to know if there is some equivalent annotation on Quarkus for
#Bean(initMethod = "start", destroyMethod = "stop")
I am working with a third-party lib which has a class that is final, thus I cannot extends it to implement #PostConstruct and #PreDestroy.
The solution on Spring would be very simple, I would just need to initialize its bean with those two arguments on the annotation; However, I could not find something similar to that on Quarkus.
A solution from CDI, which apparently works in Quarkus (see Quarkus CDI Reference/Supported features), is to use producers and disposers. So, in a class:
#ApplicationScoped // might not be needed - TBD
public class ThirdPartyBeanManager {
#Produces #ApplicationScoped // use the appropriate scope
public ThirdPartyBean getThirdPartyBean() {
ThirdPartyBean thirdPartyBean = new ThirdPartyBean();
// ***HERE IS THE MANUAL #PostConstruct/initMethod CALL***
thirdPartyBean.start();
return thirdPartyBean;
}
// ***THIS IS THE EQUIVALENT OF #PreDestroy/destroyMethod***
public void dispose(#Disposes ThirdPartyBean thirdPartyBean) {
thirdPartyBean.stop();
}
}
There may be some details that need ironing out (e.g. the "manager" does not have to be a full CDI bean, nor does it need to keep a reference to the produced bean, I think), but this is the general concept.
Another idea that builds on this concept, would be to wrap the third party dependency in an API of your own. Your API/bean will be using the third party internally and will forward its own #PostConstruct/#PreDestroy calls to the third party. The disadvantage is more code; the advantage is that now your application is decoupled from the 3rd party, the most immediate consequence of that being you can now mock that dependency in tests.
I have a Spring AOP aspect used for logging, where a method can be included for logging by adding an annotation to it, like this:
#AspectLogging("do something")
public void doSomething() {
...
}
I've been using this on Spring beans and it's been working just fine. Now, I wanted to use it on a REST-service, but I ran into some problems. So, I have:
#Path("/path")
#Service
public class MyRestService {
#Inject
private Something something;
#GET
#AspectLogging("get some stuff")
public Response getSomeStuff() {
...
}
}
and this setup works just fine. The Rest-service that I'm trying to add the logging to now has an interface, and somehow that messes stuff up. As soon as I add the #AspectLogging annotation to one of the methods, no dependencies are injected in the bean, and also, the aspect is newer called!
I've tried adding an interface to the REST-service that works, and it gets the same error.
How can having an interface lead to this type of problems? The aspect-logger works on classes with interfaces elsewhere, seems it's only a problem when it's a REST-service..
Ref the below Spring documentation (para 2) -
To enable AspectJ annotation support in the Spring IoC container, you
only have to define an empty XML element aop:aspectj-autoproxy in your
bean configuration file. Then, Spring will automatically create
proxies for any of your beans that are matched by your AspectJ
aspects.
For cases in which interfaces are not available or not used in an
application’s design, it’s possible to create proxies by relying on
CGLIB. To enable CGLIB, you need to set the attribute
proxy-targetclass= true in aop:aspectj-autoproxy.
In case your class implements an interface, a JDK dynamic proxy will be used. However if your class does not implement any interfaces then a CGLIB proxy will be created. You can achieve this #EnableAspectJAutoProxy. Here is the sample
#Configuration
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public LoggingAspect logingAspect(){
return new LoggingAspect();
}
}
#Component
#Aspect
public class LoggingAspect {
...
...
}
In my opinion what you are actually trying to do is to add spring annotations to a class maintained by jersey. In the result you are receiving a proxy of proxy of proxy of somethng. I do not think so this is a good idea and this will work without any problems. I had a similar issue when I tried to implement bean based validation. For some reasons when there were #PahtParam and #Valid annotations in the same place validation annotations were not visible. My advice is to move your logging to a #Service layer instead of #Controller.
I am a big fan of Play, and I use it in almost any project of mine nowadays. As one of my projects got bigger, though, I decided to include a DI solution. After a brief consideration between Spring and Guice, I stopped on Guice and added the Guice module for Play (http://www.playframework.com/modules/guice-1.0/home).
The problem with it, seems to be the fact that injection works for static fields only. This means that I will have to do stuff like:
#InjectSupport
public class MyService {
#Inject
static MyBean myBean;
}
from (http://java.dzone.com/articles/dependency-injection-play)
which scares me a bit, especially when it comes to testing. I mean, it is true that most of the DI solutions always try to inject singletons, for instance Spring creates a single instance of every bean and injects it, which is kind of the same at the end, but still. Should I have these concerns?
You definitely can perform Guice injection with Play.
You should not use the old Guice module (version 1.0). The tutorial you referred to is also using the old Guice, and old Play (version 1.2!)
Please take a look of the new Guice module (version 3.0) & Play (version 2.1.1)
http://www.playframework.com/documentation/2.1.1/JavaInjection
When you inject to an instance variable, you need to create controller dynamically
In your route file:
GET / #controllers.Application.index()
In your Global.java, you need to override getControllerInstance:
#Override
public <A> A getControllerInstance(Class<A> controllerClass) throws Exception {
return INJECTOR.getInstance(controllerClass);
}
In Play 1, you can easily combine normal Guice singletons with statically injected controller fields, the trick is getting the annotation imports correct.
In your play controllers, jobs & test classes that need static injection use the JSR330 annotation versions:
import javax.inject.Inject;
public class Application extends Controller {
#Inject private static MyService myService;
....
}
and for other classes that need #InjectSupport use JSR330/module imports:
import play.modules.guice.InjectSupport;
import javax.inject.Inject;
#InjectSupport
public class AnotherClass {
#Inject private static MyService myService;
}
For the actual (non-static) services instantiated by Guice library, you need to use the Guice annotation versions (note the com.google.inject package):
import com.google.inject.Inject;
import com.google.inject.Singleton;
#Singleton
public class MyService {
#Inject private AnotherService anotherService; // note non-static injection
}
You'll also need an empty Module to kick things off:
import com.google.inject.AbstractModule;
public class MainModule extends AbstractModule {
#Override
protected void configure() {}
}
This should also work for Guice classes created in other ways apart from #Singleton, such as #Provides, although I haven't tried this yet.
I want to do something like this:
#Stateless
public class GreeterEjb {
private final Greeter greeter;
#Inject
public GreeterEjb(Greeter greeter) {
this.greeter = greeter;
}
public String greet() {
return greeter.greet();
}
}
I tried it with Glassfish 3.1.1 and JBoss 7.0.2 with mixed results. Under some circumstances it works, under other circumstances it doesn't.
See this thread in the Glassfisch forum if you are interested in the details.
The EJB 3.1 spec, section 4.9.2 Bean Classes says:
The class must have a public constructor that takes no parameters.
That sounds like constructor injection is not allowed for EJBs.
BUT the CDI spec says at the start of section 3 that Session Beans are supported by CDI. Section 3.2 then talks at length about CDI and EJBs but never mentions anything about constructor injection not working. Which makes me think that it should be allowed.
So, do the specs allow CDI constructor injection for EJBs or not?
Kris and Pete Muir have finally convinced me: The EJB must have a public no-arg constructor even if another constructor is used for injection. Weird to use two constructors at the same time, but it works. Thanks guys.
Successfully tested on Glassfish 3.1.1, JBoss 7.0.2 and TomEE 1.0.0-beta-2.
#Stateless
public class GreeterEjb {
private final Greeter greeter;
#Inject
public GreeterEjb(Greeter greeter) {
this.greeter = greeter;
}
// public no-arg constructor required for EJBs
// injection still works fine with the #Inject constructor
public GreeterEjb() {
this.greeter = null;
}
public String greet() {
return greeter.greet();
}
}
Constructor injection of EJBs is required in Java EE 6 ONLY IF CDI is enabled for the jar. If this not working in an appserver, file a bug.
Please also file an issue here - http://java.net/jira/browse/EJB_SPEC - to have the EJB language spec fixed (it's wrong).
This is tested in the CDITCK - https://github.com/jboss/cdi-tck/blob/master/impl/src/main/java/org/jboss/cdi/tck/tests/implementation/enterprise/definition/ExplicitConstructorSessionBean.java - but not for no-interface-views, so please raise an issue in https://issues.jboss.org/browse/CDITCK and we can add a test for your case.
I am new to Java EE 6 and CDI. I have read a couple of tutorials and the weld documentation. However something that should work from my understanding doesn't so I need help.
I have the following situation. I created a Java EE 6 Application with NetBeans 7.0.1 using the maven archetype supplied with the IDE and I deploy to GlassFish 3.1 also supplied by the IDE.
The beans.xml is located in the META-INF directory of my EJB jar.
I have created a class that works soley as a producer class for my EJB Artifacts (and EntityManager)
#Stateless
public class EjbArtifactProducer {
#PersistenceContext(unitName = "trackProfiler-PU")
private EntityManager em;
#EJB
private UserFacadeLocal userFacade;
#EJB
private AuthServiceLocal authService;
#EJB
private NewsEntryFacadeLocal newsEntryFacade;
#EJB
private RoleFacadeLocal roleFacade;
#EJB
private TrackCommentFacade trackCommentFacade;
#EJB
private TrackFacade trackFacade;
#EJB
private TrackTypeFacade trackTypeFacade;
#EJB
private WaypointFacadeLocal waypointFacade;
#Produces
public AuthServiceLocal getAuthService() {
return authService;
}
#Produces
public EntityManager getEm() {
return em;
}
#Produces
public NewsEntryFacadeLocal getNewsEntryFacade() {
return newsEntryFacade;
}
#Produces
public RoleFacadeLocal getRoleFacade() {
return roleFacade;
}
#Produces
public TrackCommentFacade getTrackCommentFacade() {
return trackCommentFacade;
}
#Produces
public TrackFacade getTrackFacade() {
return trackFacade;
}
#Produces
public TrackTypeFacade getTrackTypeFacade() {
return trackTypeFacade;
}
#Produces
public UserFacadeLocal getUserFacade() {
return userFacade;
}
#Produces
public WaypointFacadeLocal getWaypointFacade() {
return waypointFacade;
}
}
I tried to apply the #Produces annotation directly to the fields an on methods as shown above.
However the following does not inject anything in another EJB
#Inject
private NewsEntryFacadeLocal newsEntryFacade;
This is done in a stateless session ejb but when I try to access newsEntryFacade in any of my business methods a NullPointerException is thrown. So clearly no Injection is happening or my producers produce null references.
Am I missing something? Or should this work according to CDI/Weld?
Strangely it seems to work that way when I try to #Inject EJBs into the web application part (however i needed an extra producer class in my .war for this to work, is this as it should be?).
EDIT: The project works with an ant build (generated by NetBeans). Are there issues with the Maven archetype provided by NetBeans? It seems that with the Maven archetype there are some issues with CDI injection between the war and ejb modules. I found that if I had separate producers in the web and ejb module Glassfish generates a deployment error stating that there are two indistinguishable implementations of an interface. But when I remove the producer in the web module Weld complains that the EJB i want to inject into my beans in the web module cannot be resolved. Also with the Ant build EJBs can be #Injected without a producer while the maven build needs producer fields on a class. I can't explain how this could happen. After all the final deployment should be more or less equal, shouldn't it?
If you want to use #Inject then annotate it as #Named #ApplicationScoped, otherwise use #EJB when injecting your singleton.
Jordan Denison is correct. You're trying to #Inject and EJB, but you be using #EJB for EJBs. You're EJB class is probably annotated with #Stateless or something. #Inject should be used on session beans that annotated with #Named and some sort of scope.
Hard to tell whats going wrong but what definitely did not work for us is to use CDI between class loader boundaries. For example if your application is packaged as an ear file you would have your ejbs in an jar file and your webapp in your war file. In this case you can not use CDI to inject your ejbs in your web layer. The problem is that the jar and the war is loaded by different class loaders. Maybe newer CDI implementations behave different but at least JBoss 6 and Glassfish had this problem.
Try to put #Named into EjbArtifactProducer. Also, if the produces is this kind of simple, I think it's better to remove it too (else, you should do one more change).
you are mixing two different concepts... use CDI as backing beans for JSF. (CDI in Web Container) and use EJB and JPA in the Business Layer... the CDI layer can inject a EJB to call the specific business method.
in this case you have a clean separation on concerns.
BTW: you do not need any EJB interfaces at all! use only interfaces if you have a requirements to communicate from remote... (#Remote). with the #LocalBean annotation you can inject directly the EJB itself..
if you have e clean separation of layers each with his own concern i think you better find the reason for this NullPointerException.. and i think your NullPointerException does not exists any more after this...
Layering:
Web Browser --> JSF Facelet --> CDI Backing Bean --> EJB Service(s) --> EntityManager