6 Replies Latest reply on Jun 20, 2010 10:13 PM by wuhaixing.wuhaixing.gmail.com

    Injection of a proxied interface

    agori

      I am trying to write an extension where a particular annotated interface is implemented at startup (using CGLIB) generating a proxy class.
      Then user should be allowed to inject this implementation:


      @Inject MyInterface bean;



      The problem is that WELD can't resolve the dependency, and I don't know why.
      The extension is this:


      Enhancer e = new Enhancer();
      e.setInterfaces(new Class[]{javaClass}); //it is MyInterface
      e.setCallback(...);
      final Class proxyClass = e.create().getClass();
                
      AnnotatedTypeBuilder builder = AnnotatedTypeBuilder.newInstance(proxyClass).readAnnotationsFromUnderlyingType();
      BeanBuilder beanBuilder = new BeanBuilder(builder.create(), bm);
      beanBuilder.setBeanLifecycle(...);
      beanBuilder.defineBeanFromAnnotatedType();
      beanBuilder.setScope(Default.class);
      
      Bean bean = beanBuilder.create();
      
      additionalBeans.add(bean);
      



      As you can see I am using weld exception to build the Bean object. The Bean is then added on AfterBeanDiscovery event.
      What is wrong with my idea/code?


      The exception is:


      Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408 Injection point has unsatisfied dependencies.  Injection point:  field org.lambico.cdi.LambicoTest.dao;  Qualifiers:  [@javax.enterprise.inject.Default()]
           at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:276)
           at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:122)
           at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:141)
           at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:331)
           at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:317)
           at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:399)
           at org.jboss.arquillian.weld.WeldSEContainer.deploy(WeldSEContainer.java:113)
           at org.jboss.arquillian.impl.handler.ContainerDeployer.callback(ContainerDeployer.java:62)
           at org.jboss.arquillian.impl.handler.ContainerDeployer.callback(ContainerDeployer.java:50)
           at org.jboss.arquillian.impl.event.MapEventManager.fire(MapEventManager.java:63)
           ... 14 more
      



        • 1. Re: Injection of a proxied interface
          wuhaixing.wuhaixing.gmail.com

          I implemented something similiar with @Produce and override type extesion,reference GenericDAO in the forum.
          I think the document told us there is a typesafe resolution  and what is considered is a bean .

          • 2. Re: Injection of a proxied interface
            alin.heyoulin.qq.com

            I gues you should veto your original MyInterface or extension from ProcessAnnotatedType so you have only one MyInterface bean define.

            • 3. Re: Injection of a proxied interface
              swd847

              beanBuilder.setScope(Default.class);
              



              should probably be:


              beanBuilder.getQualifiers.add(new AnnotationLiteral<Default>(){});
              

              • 4. Re: Injection of a proxied interface
                agori

                Ok I was able to implement this in WELD. For completeness I report the code here so that you can comment it and tell me where I can improve the WELD and CGLIB part.
                I see there is another implementation in this forum of a generic dao in WELD, but following a different approach with producer and interceptor. Maybe this extension is a little cleaner because doesn't force the user to configure an interceptor and doesn't need to write an empty producer.


                Dao.java (the annotation)


                @Documented
                @Target({ ElementType.TYPE })
                @Retention(RetentionPolicy.RUNTIME)
                @Inherited
                public @interface Dao {
                     
                     Class<?> value();
                 
                }
                
                



                GenericDao interface


                public interface GenericDao<T, PK extends Serializable> {
                     
                     T load(PK id);
                
                }
                
                



                Generic dao implementation


                public class GenericDaoImpl<T, PK extends Serializable> implements GenericDao<T, PK> {
                     
                    private Class<T> type;
                
                     public T load(PK id) {
                          System.out.println("load object of type " + getType().getName() + " from id " + id);
                          try {
                               return getType().newInstance();
                          } catch (Exception e) {
                               throw new RuntimeException(e);
                          }
                     }
                
                     public void setType(Class<T> type) {
                          this.type = type;
                     }
                
                     public Class<T> getType() {
                          return type;
                     };
                
                }
                
                



                CDI Extension.java:



                public class MyExtension implements Extension {
                     
                     private final Collection<Bean<?>> additionalBeans = new ArrayList<Bean<?>>();
                
                     public <X> void processAnnotatedType(
                               @Observes final ProcessAnnotatedType<X> pat, final BeanManager bm) {
                
                          final AnnotatedType<X> at = pat.getAnnotatedType();
                
                          if (!at.isAnnotationPresent(Dao.class)) {
                               return;
                          }
                          
                          
                          final Class<X> javaClass = at.getJavaClass();
                          
                          final Enhancer e = new Enhancer();
                          e.setSuperclass(GenericDaoImpl.class);
                          e.setInterfaces(new Class[]{javaClass});
                          e.setCallback(new MethodInterceptor() {
                               
                               @Override
                               public Object intercept(Object target, Method method, Object[] args,
                                         MethodProxy proxy) throws Throwable {
                                    if (method.getName().equals("setType")) {
                                         return proxy.invokeSuper(target, args);
                                    }
                                    GenericDaoImpl genericDaoImpl = (GenericDaoImpl) target;
                                    genericDaoImpl.setType(at.getAnnotation(Dao.class).value());
                                    return proxy.invokeSuper(target, args);
                               }
                          });
                          
                          final Class proxyClass = e.create().getClass();
                          
                          AnnotatedTypeBuilder builder = AnnotatedTypeBuilder.newInstance(proxyClass)
                                    .readAnnotationsFromUnderlyingType();
                                    
                          BeanBuilder beanBuilder = new BeanBuilder(builder.create(), bm);
                          beanBuilder.defineBeanFromAnnotatedType();
                          beanBuilder.setBeanLifecycle(new BeanLifecycleImpl() {
                
                               @Override
                               public Object create(BeanImpl bean, CreationalContext creationalContext) {
                                     Object instance = e.create();
                                     bean.getInjectionTarget().inject(instance, creationalContext);
                                     bean.getInjectionTarget().postConstruct(instance);
                                     return instance;
                               }
                
                          });
                
                          beanBuilder.getQualifiers().add(new AnnotationLiteral<Default>(){});
                          Bean bean = beanBuilder.create();
                          
                          additionalBeans.add(bean);
                     }
                
                
                     void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) {
                          for (Bean<?> bean : additionalBeans) {
                               abd.addBean(bean);
                          }
                     }
                     
                
                
                }
                



                Arquillian test:


                @RunWith(Arquillian.class)
                public class LambicoTest {
                
                     @Deployment
                     public static Archive<?> createTestArchive() {
                          Archive<?> archive = ShrinkWrap.create("test.jar", JavaArchive.class)
                        .addPackages(true, LambicoTest.class.getPackage())
                        .addManifestResource("META-INF/beans.xml")
                        .addServiceProvider(Extension.class,  LambicoExtension.class);
                     
                          return archive;
                     }
                
                     @Inject MyDao dao;
                
                     @Test
                     public void test() {
                          User user = dao.load(2L);
                          System.out.println(user);
                     }
                
                }
                




                • 5. Re: Injection of a proxied interface
                  wuhaixing.wuhaixing.gmail.com

                  Another approach no interceptor to config,and producer is responsiable to create proxy class as you do in the extension.

                  • 6. Re: Injection of a proxied interface
                    wuhaixing.wuhaixing.gmail.com

                    Does InjectionTarget more suit this work?