1 2 Previous Next 17 Replies Latest reply on Jan 26, 2010 5:30 PM by Pete Muir

    Injecting an EJB from a jar into a jax-rs class in a war

    David Beaumont Newbie

      Hi All,


      I am trying a very simple experiment to get started with Weld on glassfish v3 and have got stuck pretty quickly. I have an ear with an ejb-jar and a war. The ejb-jar contains an ejb:


      @Stateless
      @LocalBean
      @Named
      public class IdentifierService {
      
           @PersistenceContext(unitName="mud")
           EntityManager entityManager;
      
           @EJB
           OrgService orgService;
      
           public Collection<Identifier> getIdentifiers() {
                Query q = entityManager.createNamedQuery("identifiers.all");
                return q.getResultList();
           }
      
      }



      And the war contains a simple jax-rs class:


      @Path("/")
      public class RootResource {
      
           @Inject
           IdentifierService identifierService;
      
           @GET
              @Produces("application/xml")
           public Collection<Identifier> getXml() {
                return identifierService.getIdentifiers();
           }
      
      }



      The war also contains a facelets page:


      <?xml version='1.0' encoding='UTF-8' ?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml"
            xmlns:h="http://java.sun.com/jsf/html"
             xmlns:ui="http://java.sun.com/jsf/facelets">
          <h:head>
              <title>Facelet Title</title>
          </h:head>
          <h:body>
              <h1>Identifiers</h1>
                <p>Service bean: #{identifierService}</p>
                <ul>
                     <ui:repeat value="#{identifierService.identifiers}" var="ident">
                          <li>#{ident.name}</li>
                     </ui:repeat>
                </ul>
          </h:body>
      </html>
      



      The war has a beans.xml in WEB-INF and the ejb-jar has the same in META-INF. The facelets page works as desired - hibernate runs the query and the results are shown in the web browser.


      The problem:


      When accessing the JAX-RS resource, injection doesn't happen, so there is a null pointer exception at return identifierService.getIdentifiers();


      Does CDI not work with JAX-RS?
      Previously I had made the JAX-RS classes also ejbs by using @Stateless @LocalBean, then injecting with @EJB - that worked fine.


      Dave


        • 1. Re: Injecting an EJB from a jar into a jax-rs class in a war
          David Beaumont Newbie

          Some things I have tried:


          ---Deploying as a War---


          I made the ejb-jar the library of a war containing the facelet and jax-rs. There was no change in the outcome - the facelet worked but jax-rs didn't.


          ---Making the JAX-RS class available to EL---


          by adding @Named to the jax-rs class it could be accessed via EL, and then injection mysteriously works if accessed by the facelet (e.g. with #{rootResource.xml})


          However, it still didn't work when accessing the resource 'natively'.

          • 2. Re: Injecting an EJB from a jar into a jax-rs class in a war
            Nicklas Karlsson Master

            Strange. Can you inject the RootResource into something else? Just curious about the visibility. I don't think the JAX-RS annotations should matter.

            • 3. Re: Injecting an EJB from a jar into a jax-rs class in a war
              David Beaumont Newbie

              Hi Nik, thank you for your reply.


              I think our last messages crossed - 'injecting' into a facelet (if that is the right language) does work, it's just accessing the jax-rs resource directly that doesn't.


              I've just tried adding another layer of indirection. I've added a third class which injects the jax-rs class:


              @Named
              public class TertiaryResource {
              
                   @Inject
                   RootResource rootResource;
              
                   public Collection<Identifier> getIdents() {
                        return rootResource.getXml();
                   }
              }
              



              And another facelet to test it:


              <?xml version='1.0' encoding='UTF-8' ?>
              <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
              <html xmlns="http://www.w3.org/1999/xhtml"
                    xmlns:h="http://java.sun.com/jsf/html"
                     xmlns:ui="http://java.sun.com/jsf/facelets">
                  <h:head>
                      <title>Facelet Title</title>
                  </h:head>
                  <h:body>
                      <h1>Identifiers</h1>
                        <p>Service bean: #{tertiaryResource}</p>
                        #{tertiaryResource.idents}
                  </h:body>
              </html>
              



              So now the flow is:


              Request to facelet -> tertiary resource -> root resource -> identifier service.
              



              This works, but doesn't do anything useful.


              This doesn't work:


              Request to JAX-RS root resource -> identifier service
              



              It seems weld doesn't manage jax-rs classes unless they are accessed in a specific way. Do I need to add some sort of filter or interceptor to web.xml to have this work?


              Thanks.

              • 4. Re: Injecting an EJB from a jar into a jax-rs class in a war
                Nicklas Karlsson Master

                Hmm. I must stand down on this issue with a dunno, I haven't done anything with CDI and JAX-RS. There is of course the chance that the server creates a new instance of the class all by itself (which will of course have no injections). I'm sure there will be helpers and patterns for optimal usage but until then: can you access BeanManager from JNDI and get hold of the stuff yourself?

                • 5. Re: Injecting an EJB from a jar into a jax-rs class in a war
                  he youlin Novice

                  yep,it is probably IdentifierService has created by jax-rs servlet not by injected.

                  • 6. Re: Injecting an EJB from a jar into a jax-rs class in a war
                    David Beaumont Newbie

                    Ok, changing the jax-rs class to look as below and not use CDI at all does work, but it's not the elegance I was hoping for. CDI works for all classes, except where it doesn't?


                    @Path("/")
                    public class RootResource {
                    
                         public RootResource() throws NamingException {
                              identifierService = (IdentifierService) (new InitialContext()).lookup("java:global/WebApplication1/IdentifierService");
                         }
                    
                         //@Inject
                         IdentifierService identifierService;
                    
                         @GET
                            @Produces("application/xml")
                         public Collection<Identifier> getXml() {
                              return identifierService.getIdentifiers();
                         }
                    
                    }
                    

                    • 7. Re: Injecting an EJB from a jar into a jax-rs class in a war
                      Nicklas Karlsson Master

                      It works in those lifecycles where it's specified to work. If you do a new Foo(), you won't get CDI in there either.


                      Using BeanManager might still be worth a shot. While there are a few more steps for resolving stuff, you get injections from that point in (if the thing you resolve has other CDI injections)

                      • 8. Re: Injecting an EJB from a jar into a jax-rs class in a war
                        he youlin Novice
                        
                        you can try
                        @Path("/")
                        public class RootResource {
                        
                             public RootResource() throws NamingException {
                                       BeanManager beanManager=(BeanManager)new InitialContext().lookup("java:comp/BeanManager");
                        Bean<IdentifierService> identifierServiceBean= (Bean<IdentifierService>)beanManager.getBeans(Conversation.class).iterator().next();
                                           identifierService= (IdentifierService)beanManager.getReference(identifierServiceBean, IdentifierService.class, beanManager.createCreationalContext(identifierServiceBean)); 
                             }
                        
                             //@Inject
                             IdentifierService identifierService;
                        
                             @GET
                                @Produces("application/xml")
                             public Collection<Identifier> getXml() {
                                  return identifierService.getIdentifiers();
                             }
                        
                        }
                           
                         
                        
                        


                        • 9. Re: Injecting an EJB from a jar into a jax-rs class in a war
                          Nicklas Karlsson Master

                          ITYM getBeans(IdentifierService.class...) and not getBeans(Conversation.class...)?

                          • 10. Re: Injecting an EJB from a jar into a jax-rs class in a war
                            he youlin Novice

                            
                            :) Soory,my code copy and paste and then edit.
                            
                            you can try
                            @Path("/")
                            public class RootResource {
                            
                                 public RootResource() throws NamingException {
                                           BeanManager beanManager=(BeanManager)new InitialContext().lookup("java:comp/BeanManager");
                            Bean<IdentifierService> identifierServiceBean= (Bean<IdentifierService>)beanManager.getBeans(IdentifierService.class).iterator().next();
                                               identifierService= (IdentifierService)beanManager.getReference(identifierServiceBean, IdentifierService.class, beanManager.createCreationalContext(identifierServiceBean)); 
                                 }
                            
                                 //@Inject
                                 IdentifierService identifierService;
                            
                                 @GET
                                    //@Produces("application/xml")
                                 public Collection<Identifier> getXml() {
                                      return identifierService.getIdentifiers();
                                 }
                            
                            }
                            


                            • 11. Re: Injecting an EJB from a jar into a jax-rs class in a war
                              David Beaumont Newbie

                              Thanks guys, that looks useful for injecting things which aren't EJBs.


                              For my particular case with a stateless EJB, because there isn't going to be a CDI context coming from the JAX-RS request anyway, I might as well just use the simpler EJB lookup?


                              Supposing I want access to a session scoped bean (Identity is a good candidate), is there someway I could tell the bean manager the users' session (from the jsessionid) and get back a bean relating to that user?


                              Does he youlin's code magically do that? Let me know if I'm not making sense!


                              Thanks!
                              Dave

                              • 12. Re: Injecting an EJB from a jar into a jax-rs class in a war
                                he youlin Novice

                                I think you'd better wrappe EJBs into weld beans and use BeanManager to get the weld beans or you can wait for weld-jax-rs inetgration module.

                                • 13. Re: Injecting an EJB from a jar into a jax-rs class in a war
                                  Nicklas Karlsson Master

                                  I guess you would also need (in any case) to activate the contexts with calls to methods in org.jboss.weld.servlet.ServletLifeCycle...

                                  • 14. Re: Injecting an EJB from a jar into a jax-rs class in a war
                                    Gavin King Master

                                    IMO the original code example should work, according to section 6.2 of the JAX-RS specification. Try asking in the glassfish forums, or posting a bug against glassfish.

                                    1 2 Previous Next