Hi all,
I've got a Wicket WebPage which is injected an EJB to retrieve the data to display in a grid. I've tried injecting the EJB with @Inject and with @EJB and both seem to work (at least for retrieving data), but a nasty error raises when using @EJB (please find the stack trace below).
My question is, which is the difference between injecting an EJB with @EJB and with @Inject? Do you lose any EJB facilities when using @Inject? Maybe I'm missing something / doing something wrong?
Thanks in advance,
J.
--------
logged error:
[#|2009-11-26T17:37:36.770+0100|INFO|glassfishv3.0|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=26;_ThreadName=http-thread-pool-8080-(1);|ERROR - Objects - Error serializing object class controllers.QuoteBrowse [object=[Page class = controllers.QuoteBrowse, id = 0, version = 0]]org.apache.wicket.util.io.SerializableChecker$WicketNotSerializableException: Unable to serialize class: services.__EJB31_Generated__QuoteService__Intf____Bean__
Field hierarchy is:
0 [class=controllers.QuoteBrowse, path=0]
private services.QuoteService controllers.QuoteBrowse.quoteService [class=services.__EJB31_Generated__QuoteService__Intf____Bean__] <----- field that is not serializable
at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:346)
at org.apache.wicket.util.io.SerializableChecker.checkFields(SerializableChecker.java:615)
at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:538)
at org.apache.wicket.util.io.SerializableChecker.writeObjectOverride(SerializableChecker.java:684)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:322)
at org.apache.wicket.util.io.IObjectStreamFactory$DefaultObjectStreamFactory$2.writeObjectOverride(IObjectStreamFactory.java:129)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:322)
at org.apache.wicket.util.lang.Objects.objectToByteArray(Objects.java:1120)
at org.apache.wicket.protocol.http.pagestore.AbstractPageStore.serializePage(AbstractPageStore.java:203)
at org.apache.wicket.protocol.http.pagestore.DiskPageStore.storePage(DiskPageStore.java:840)
at org.apache.wicket.protocol.http.SecondLevelCacheSessionStore$SecondLevelCachePageMap.put(SecondLevelCacheSessionStore.java:332)
at org.apache.wicket.Session.requestDetached(Session.java:1404)
at org.apache.wicket.RequestCycle.detach(RequestCycle.java:1176)
at org.jboss.weld.wicket.WeldRequestCycle.detach(WeldRequestCycle.java:155)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1454)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:545)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:468)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:301)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:332)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:233)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:168)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.io.NotSerializableException: services.__EJB31_Generated__QuoteService__Intf____Bean__
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at org.apache.wicket.util.io.IObjectStreamFactory$DefaultObjectStreamFactory$2.writeObjectOverride(IObjectStreamFactory.java:121)
... 37 more
|#]
------------
The WebPage class is controllers.QuoteBrowse and the EJB is services.QuoteService.
That error is very strange, since EJB local references should always be serializable. Bug in glassfish, perhaps?
Basically, @Inject is always better, since:
I recommend against the use of @EJB except for declaring references to remote EJBs.
Learn more about Weld...
I wonder whether weld just as Seam 2.x still doesn't support the injection of the remote EJBs.
Introduction of chapter 3 in the 299 spec:
If a man speaks in the forest and there is no woman around to hear him, is he still wrong?
It's interesting that the spec mentioned the resources in chapter 3 while the weld doc didn't mention the resources in the chapter 2 ending with the last producer fields.
This is the feature defined in the spec. Is it available with Weld at the same time?
If it is supported in Weld at the same time, which is better for using to inject remote beans. I'm just confused by gavin's words . Does it mean @EJB better with remote EJBs?
Use @EJB to define a resource. Then inject it into your beans using @Inject.
Learn more about Weld...
For a remote EJB, we can't declare metadata like qualifiers, @Alternative, etc, on the bean class, since the client simply isn't going to have access to that metadata. Furthermore, some additional metadata must be specified that we don't need for the local case (global JNDI name of whatever). So all that stuff needs to go somewhere else: namely the @Produces declaration.
Does that make sense?
Learn more about Weld...
OK Gavin, thanks for helping.
Rgds, J.
Thanks for replying. I understand now.
B/c I am stupid, I like platform and fmwks that cater to the KISS principle.
This is not happening here.
IMHO, it seems somewhat strange that we must decide b/n using @Inject and @EJB in EE 6 apps.
Ok, so there seems to be a technical limitation in the case of remote EJBs. But it would have been nice if the EGs somehow eliminated @EJB completely (except for backwards-compatibility for EE 5 apps).
Unfortunately, now it's somewhat confusing and/or you must keep track of yet another rule/detail so you know when to use which annotation.... bah humbug!
I'm learning Objective-C, it's about time I learned an OO language other than Java!
Arbi, if you spent more time on the learning and understanding bit, and less time on the criticizing stuff you don't properly understand bit, you would not be so stupid.
Four posts ago, I gave you a very simple piece of advice, so that you don't need to anything. I wrote:
Other people seem to have understood what I wrote. If you don't understand, why not ask for further explanation, instead of shooting your mouth off?
@EJB is completely eliminated for local EJBs (except for backward compatibility). There are lots and lots of examples in the CDI spec and Weld documentation of using @Inject to inject local EJBs. And lots of times where I've explained that we strongly recommend the use of @Inject instead of @EJB to inject local EJBs. How could you possibly have missed that? Because you were too busy posting questions and brain-dead criticism instead of actually reading what is already out there?
And if we tried to eliminate @EJB for remote EJBs, then we would need to introduce some new annotation, let's call it @ArbisSpecialEJB in order to tell the container where to go to obtain the reference to the remote EJB. And, of course, @ArbisSpecialEJB would need basically the same members that @EJB already has. Hey, I've got an idea! Why don't we just eliminate @ArbisSpecialEJB and use @EJB for that instead! After all, @EJB already exists and has a shorter name.
It's confusing to some people, apparently.
Learn more about Weld...
Jesus, in my very first reply in this thread, I wrote:
I don't know how I could possibly have been more explicit.
Learn more about Weld...
The problem is that injecting EJBs in Wicket pages is now broken in my app. This is how I used to declare the service (EJB) class before the changes and how it was injected (this worked):
==
@Stateless
public class QuoteService { ...
--
public class QuoteBrowse extends WebPage {
@Inject private QuoteService quoteService;
...
==
And this is how the code looks now for the EJB (the code to inject it hasn't changed):
==
@Stateless
public class QuoteService implements BrowseableService { ...
==
So now I'm getting the following error in GlassFish v3 b73 during deployment:
==
[#|2009-12-02T13:53:00.315+0100|SEVERE|glassfishv3.0|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=24;_ThreadName=http-thread-pool-4848-(2);|Exception while loading the app
org.glassfish.deployment.common.DeploymentException: Injection point has unstatisfied dependencies. Injection point: field controllers.QuoteBrowse.quoteService; Qualifiers: [@javax.enterprise.inject.Default()]
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:169)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:88)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:239)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:339)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:183)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:272)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:305)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:320)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1176)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$900(CommandRunnerImpl.java:83)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1235)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1224)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:365)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:204)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:166)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:100)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:245)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:168)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:619)
Caused by: org.jboss.weld.DeploymentException: Injection point has unstatisfied dependencies. Injection point: field controllers.QuoteBrowse.quoteService; Qualifiers: [@javax.enterprise.inject.Default()]
at org.jboss.weld.Validator.validateInjectionPoint(Validator.java:232)
at org.jboss.weld.Validator.validateBean(Validator.java:80)
at org.jboss.weld.Validator.validateRIBean(Validator.java:100)
at org.jboss.weld.Validator.validateBeans(Validator.java:282)
at org.jboss.weld.Validator.validateDeployment(Validator.java:268)
at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:389)
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:166)
... 30 more
|#]
==
But it works if I inject the service in a BrowseableService (the interface) type instead of a QuoteService (@Inject private BrowseableService quoteService;).
On the other hand, the Weld Reference PDF sates:
"A bean type is a user-defined class or interface; a type that is client-visible. If the bean is an EJB session bean, the bean type is the @Local interface or bean-class local view."
So the new code should work because the QuoteService is still a "bean-class local view", right? I'm a bit confused, should the EJB implement a @Local interface for this to work? Any help would be appreciated.
BTW, sorry for these lengthy posts.
Rgds, J.
It seems more or less related to WELD-305, but I'm not sure that my patch will help you if you don't have a local interface.
In most projects I've worked on, remote EJBs have not been required. So a remote EJB would be an EJB living in an EJB container in a different JVM/process than your app's EJB container.
Ok, so in the atypical cases when a remote EJB is required, you'd do something like this:
and then inject in your component using this:
so the idea being every time you need to inject an instance of this remote EJB, you use @Inject, rather than @EJB. Is this correct? So basically the @EJB is only used once per remote EJB (in the producer definition).
I'm learning Objective-C, it's about time I learned an OO language other than Java!
dammit. unfortunately, I have a penchant for complaining, no matter what, no matter where, no matter I'm wrong or right. editing is required for all forums! make it a damn priority.
...............
There is a typo above.
I meant to type:
btw, congrats on the EE6 final ballot vote!
I'm learning Objective-C, it's about time I learned an OO language other than Java!
As usual most of your points are very valid. congrats. But I don't want a special EJB annotation. All I want is to use one annotation, call it anything you like, @InjectFoo or @Inject, for all object injections in EE6 apps. Your solution using the producer pattern is a workaround to the remote EJB limitation which requires usage of @EJB. So the EE6 developer must use both @EJB and @Inject to inject a remote EJB object. I'd rather use simply and only @Inject.
Now if that's not possible for remote EJB instances, I can live with that, but using only @Inject obviously seems ideal to me, whether I read the entire spec or not...
I'm learning Objective-C, it's about time I learned an OO language other than Java!
ok, here are a couple examples to consider.
http://docs.jboss.org/weld/reference/1.0.0/en-US/html_single/#translator
public class TextTranslator implements Serializable { private SentenceParser sentenceParser; @EJB private Translator translator; @Inject public TextTranslator(SentenceParser sentenceParser) { this.sentenceParser = sentenceParser; } public String translate(String text) { StringBuilder sb = new StringBuilder(); for (String sentence: sentenceParser.parse(text)) { sb.append(translator.translate(sentence)).append(". "); } return sb.toString().trim(); } }not the usage of @EJB for the POJO above...
@Stateful @RequestScoped @Named("translator") public class TranslatorControllerBean implements TranslatorController { @Inject private TextTranslator translator; private String inputText; private String translatedText; public void translate() { translatedText = translator.translate(inputText); } public String getText() { return inputText; } public void setText(String text) { this.inputText = text; } public String getTranslatedText() { return translatedText; } @Remove public void remove() {} }not the usage of @Inject for the SFSB above...
so in a POJO, must you use @EJB to inject a SLSB local business interface or can you use @Inject as well?
I'm learning Objective-C, it's about time I learned an OO language other than Java!
Here we go.
Right. It's called @Inject. It's the only annotation you use to do injection in CDI. CDI does not use @EJB for injection. It uses it for bean definition. (I'm repeating myself here.)
Huh? It's not a workaround. It's how you tell CDI where the hell this remote EJB is.
Not correct. You use @EJB to tell CDI where this remote object is, and @Inject to inject it. I've now said this about 4 times.
And I would rather have magical powers to guess what other people are thinking. But I don't.
How the hell, in your proposal, is CDI going to know, when it encounters the following injection point,
where to go to look for the PaymentProcessorBean that exists in a totally different application, on a totally different machine? It uses its magical powers to guess what Arbi was thinking and magically comes up with the global JNDI name of an EJB deployed in a completely different application in a completely different container?
It's not possible. Live with it.
Learn more about Weld...
No. As I've said 5 times now. That example is showing the use of old code written to Java EE 5 APIs, that already uses @EJB. I don't recommend that approach for new code.
Arbi, this is the end of this thread. I've now told you the same thing 5 times, and you're deliberately trying not to understand me. I don't appreciate that kind of timewasting behavior. I will delete any future posts on this topic.
Learn more about Weld...
No, in this case, QuoteService will not be recognized as a bean class local view. I'm a little upset about this, since I argued strongly that it should be, but the rest of the group disagreed with me, according to reasoning that I don't think was very sound.
From the EJB 3.1 spec:
So you need to add an ugly @LocalBean annotation. Sorry. I hate it too. :-(
Learn more about Weld...
This was unfair, and I shouldn't have said it.
You'll just need to trust me that there really is no simpler way.
Learn more about Weld...
Thanks again for replying, Gavin, at least that's a solution :)
Regards,
J.
Behold! the Angel of the Lord has spoken!
I'm learning Objective-C, it's about time I learned an OO language other than Java!
Gavin,
There's a typo in that example:
@EJB does not have an element named ejbLink.