You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by rm...@apache.org on 2014/12/23 12:17:34 UTC

svn commit: r1647547 - in /openwebbeans/trunk/webbeans-impl/src: main/java/org/apache/webbeans/inject/ main/java/org/apache/webbeans/portable/ main/java/org/apache/webbeans/proxy/ test/java/org/apache/webbeans/test/decorators/constructor/ test/java/org...

Author: rmannibucau
Date: Tue Dec 23 11:17:34 2014
New Revision: 1647547

URL: http://svn.apache.org/r1647547
Log:
allowing cnstructor injection in decorators

Added:
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/decorators/constructor/
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/decorators/constructor/DecoratorConstructorInjectionTest.java
Modified:
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/inject/AbstractInjectable.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/portable/AbstractDecoratorInjectionTarget.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java
    openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java
    openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/interceptors/factory/SubclassProxyFactoryTest.java

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/inject/AbstractInjectable.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/inject/AbstractInjectable.java?rev=1647547&r1=1647546&r2=1647547&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/inject/AbstractInjectable.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/inject/AbstractInjectable.java Tue Dec 23 11:17:34 2014
@@ -53,7 +53,7 @@ import org.apache.webbeans.util.WebBeans
 public abstract class AbstractInjectable<T>
 {
 
-    private Producer<?> owner;
+    protected Producer<?> owner;
     
     protected final CreationalContextImpl<?> creationalContext;
     

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/portable/AbstractDecoratorInjectionTarget.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/portable/AbstractDecoratorInjectionTarget.java?rev=1647547&r1=1647546&r2=1647547&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/portable/AbstractDecoratorInjectionTarget.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/portable/AbstractDecoratorInjectionTarget.java Tue Dec 23 11:17:34 2014
@@ -19,6 +19,8 @@
 package org.apache.webbeans.portable;
 
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -26,8 +28,11 @@ import javax.enterprise.inject.spi.Annot
 import javax.enterprise.inject.spi.AnnotatedMethod;
 import javax.enterprise.inject.spi.AnnotatedType;
 import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
 
 import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.context.creational.CreationalContextImpl;
+import org.apache.webbeans.inject.InjectableConstructor;
 
 public class AbstractDecoratorInjectionTarget<T> extends InjectionTargetImpl<T>
 {
@@ -50,11 +55,76 @@ public class AbstractDecoratorInjectionT
             classLoader = Thread.currentThread().getContextClassLoader();
         }
 
-        proxySubClass = webBeansContext.getSubclassProxyFactory().createImplementedSubclass(classLoader, classToProxy);
+        proxySubClass = webBeansContext.getSubclassProxyFactory().createImplementedSubclass(classLoader, annotatedType);
 
-        //X TODO what about @Inject constructors?
-        Constructor<T> ct = webBeansContext.getWebBeansUtil().getNoArgConstructor(proxySubClass);
-        return new AnnotatedConstructorImpl<T>(webBeansContext, ct, annotatedType);
+        Constructor<T> ct = (Constructor<T>) webBeansContext.getSecurityService().doPrivilegedGetDeclaredConstructors(proxySubClass)[0];
+        Constructor<T> parentCtor;
+        try
+        {
+            parentCtor = classToProxy.getConstructor(ct.getParameterTypes());
+        }
+        catch (final NoSuchMethodException e)
+        {
+            throw new IllegalStateException(e);
+        }
+        return new SubClassAnnotatedConstructorImpl<T>(webBeansContext, parentCtor, ct, annotatedType);
+    }
+
+    @Override
+    protected SubClassAnnotatedConstructorImpl<T> getConstructor()
+    {
+        if (constructor == null)
+        {
+            constructor = createConstructor();
+        }
+        return (SubClassAnnotatedConstructorImpl<T>) constructor;
+    }
+
+    @Override
+    protected T newInstance(CreationalContextImpl<T> creationalContext)
+    {
+        return new AbstractDecoratorInjectableConstructor<T>(
+                getConstructor().parentConstructor, getConstructor().getJavaMember(), this, creationalContext).doInjection();
     }
 
+    public static class SubClassAnnotatedConstructorImpl<T> extends AnnotatedConstructorImpl<T>
+    {
+        private final Constructor<T> parentConstructor;
+
+        public SubClassAnnotatedConstructorImpl(final WebBeansContext webBeansContext,
+                                                final Constructor<T> parentConstructor,
+                                                final Constructor<T> javaMember,
+                                                final AnnotatedType<T> declaringType)
+        {
+            super(webBeansContext, javaMember, declaringType);
+            this.parentConstructor = parentConstructor;
+        }
+    }
+
+    public static class AbstractDecoratorInjectableConstructor<T> extends InjectableConstructor<T>
+    {
+        private final Constructor<T> parent;
+
+        public AbstractDecoratorInjectableConstructor(final Constructor<T> parentConstructor,
+                                                      final Constructor<T> cons, final InjectionTarget<T> owner,
+                                                      final CreationalContextImpl<T> creationalContext)
+        {
+            super(cons, owner, creationalContext);
+            this.parent = parentConstructor;
+        }
+
+        @Override
+        protected List<InjectionPoint> getInjectionPoints(Member member)
+        {
+            List<InjectionPoint> injectionPoints = new ArrayList<InjectionPoint>();
+            for (InjectionPoint injectionPoint : owner.getInjectionPoints())
+            {
+                if (injectionPoint.getMember().equals(parent)) // we don't compare to the runtime subclass constructor
+                {
+                    injectionPoints.add(injectionPoint);
+                }
+            }
+            return injectionPoints;
+        }
+    }
 }

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java?rev=1647547&r1=1647546&r2=1647547&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/AbstractProxyFactory.java Tue Dec 23 11:17:34 2014
@@ -18,6 +18,7 @@
  */
 package org.apache.webbeans.proxy;
 
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -105,7 +106,7 @@ public abstract class AbstractProxyFacto
      * @param classFileName
      * @throws ProxyGenerationException
      */
-    protected abstract void createConstructor(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName)
+    protected abstract void createConstructor(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName, Constructor<?> injectConstructor)
             throws ProxyGenerationException;
 
     /**
@@ -174,6 +175,12 @@ public abstract class AbstractProxyFacto
         return fixedClassName;
     }
 
+    protected <T> Class<T> createProxyClass(ClassLoader classLoader, String proxyClassName, Class<T> classToProxy,
+                                            Method[] interceptedMethods, Method[] nonInterceptedMethods)
+            throws ProxyGenerationException
+    {
+        return createProxyClass(classLoader, proxyClassName, classToProxy, interceptedMethods, nonInterceptedMethods, null);
+    }
 
     /**
      * @param classLoader to use for creating the class in
@@ -184,21 +191,21 @@ public abstract class AbstractProxyFacto
      * @return the proxy class
      */
      protected <T> Class<T> createProxyClass(ClassLoader classLoader, String proxyClassName, Class<T> classToProxy,
-                                                      Method[] interceptedMethods, Method[] nonInterceptedMethods)
+                                                      Method[] interceptedMethods, Method[] nonInterceptedMethods,
+                                                      Constructor<T> constructor)
             throws ProxyGenerationException
     {
         String proxyClassFileName = proxyClassName.replace('.', '/');
 
-        final byte[] proxyBytes = generateProxy(classLoader, classToProxy, proxyClassName, proxyClassFileName, interceptedMethods, nonInterceptedMethods);
-
-        Class<T> clazz = defineAndLoadClass(classLoader, proxyClassName, proxyBytes);
-
+        final byte[] proxyBytes = generateProxy(
+                classLoader, classToProxy, proxyClassName, proxyClassFileName,
+                interceptedMethods, nonInterceptedMethods, constructor);
 
-        return clazz;
+        return defineAndLoadClass(classLoader, proxyClassName, proxyBytes);
     }
 
     private byte[] generateProxy(ClassLoader classLoader, Class<?> classToProxy, String proxyClassName, String proxyClassFileName,
-                                 Method[] interceptedMethods, Method[] nonInterceptedMethods)
+                                 Method[] interceptedMethods, Method[] nonInterceptedMethods, Constructor<?> constructor)
             throws ProxyGenerationException
     {
         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
@@ -225,7 +232,7 @@ public abstract class AbstractProxyFacto
         cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
                 FIELD_BEAN_PASSIVATION_ID, Type.getDescriptor(String.class), null, null).visitEnd();
 
-        createConstructor(cw, proxyClassFileName, classToProxy, classFileName);
+        createConstructor(cw, proxyClassFileName, classToProxy, classFileName, constructor);
 
 
         if (nonInterceptedMethods != null)

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java?rev=1647547&r1=1647546&r2=1647547&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/InterceptorDecoratorProxyFactory.java Tue Dec 23 11:17:34 2014
@@ -259,7 +259,7 @@ public class InterceptorDecoratorProxyFa
      * @throws ProxyGenerationException
      */
     @Override
-    protected void createConstructor(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName)
+    protected void createConstructor(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName, Constructor<?> ignored)
             throws ProxyGenerationException
     {
         Constructor superDefaultCt;

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java?rev=1647547&r1=1647546&r2=1647547&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/NormalScopeProxyFactory.java Tue Dec 23 11:17:34 2014
@@ -304,7 +304,8 @@ public class NormalScopeProxyFactory ext
 
 
     @Override
-    protected void createConstructor(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName) throws ProxyGenerationException
+    protected void createConstructor(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName, Constructor<?> ignored)
+            throws ProxyGenerationException
     {
         try
         {

Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java?rev=1647547&r1=1647546&r2=1647547&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/proxy/SubclassProxyFactory.java Tue Dec 23 11:17:34 2014
@@ -31,6 +31,10 @@ import org.apache.xbean.asm5.MethodVisit
 import org.apache.xbean.asm5.Opcodes;
 import org.apache.xbean.asm5.Type;
 
+import javax.enterprise.inject.spi.AnnotatedConstructor;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.inject.Inject;
+
 /**
  * This factory creates subclasses for abstract classes.
  * This is being used for Abstract Decorators.
@@ -50,8 +54,9 @@ public class SubclassProxyFactory extend
     }
 
 
-    public <T> Class<T> createImplementedSubclass(ClassLoader classLoader, Class<T> classToProxy)
+    public <T> Class<T> createImplementedSubclass(ClassLoader classLoader, AnnotatedType<T> annotatedType)
     {
+        Class<T> classToProxy = annotatedType.getJavaClass();
         if (!Modifier.isAbstract(classToProxy.getModifiers()))
         {
             throw new WebBeansConfigurationException("Only abstract classes should get subclassed, not " + classToProxy);
@@ -64,7 +69,7 @@ public class SubclassProxyFactory extend
             return proxyClass;
         }
 
-        proxyClass = createSubClass(classLoader, classToProxy);
+        proxyClass = createSubClass(classLoader, annotatedType);
 
         return proxyClass;
     }
@@ -91,13 +96,14 @@ public class SubclassProxyFactory extend
 
     /**
      * @param classLoader to use for creating the class in
-     * @param classToProxy the class for which a subclass will get generated
+     * @param annotatedType the annotatedType for which a subclass will get generated
      * @param <T>
      * @return the proxy class
      */
-    public synchronized <T> Class<T> createSubClass(ClassLoader classLoader, Class<T> classToProxy)
+    public synchronized <T> Class<T> createSubClass(ClassLoader classLoader, AnnotatedType<T> annotatedType)
             throws ProxyGenerationException
     {
+        Class<T> classToProxy = annotatedType.getJavaClass();
         Class<T> clazz = tryToLoadClass(classLoader, classToProxy);
         if (clazz != null)
         {
@@ -109,19 +115,31 @@ public class SubclassProxyFactory extend
         List<Method> methods = ClassUtil.getNonPrivateMethods(classToProxy, true);
         Method[] businessMethods = methods.toArray(new Method[methods.size()]);
 
-        clazz = createProxyClass(classLoader, proxyClassName, classToProxy, businessMethods, new Method[0]);
+        Constructor<T> cons = null;
+        for (AnnotatedConstructor<T> c : annotatedType.getConstructors())
+        {
+            if (c.isAnnotationPresent(Inject.class))
+            {
+                cons = c.getJavaMember();
+                break;
+            }
+        }
+
+        clazz = createProxyClass(classLoader, proxyClassName, classToProxy, businessMethods, new Method[0], cons);
 
         return clazz;
     }
 
 
     @Override
-    protected void createConstructor(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName) throws ProxyGenerationException
+    protected void createConstructor(ClassWriter cw, String proxyClassFileName, Class<?> classToProxy, String classFileName, Constructor<?> constructor)
+            throws ProxyGenerationException
     {
         try
         {
             Constructor superDefaultCt;
             String parentClassFileName;
+            String[] exceptions = null;
             if (classToProxy.isInterface())
             {
                 parentClassFileName = Type.getInternalName(Object.class);
@@ -130,13 +148,34 @@ public class SubclassProxyFactory extend
             else
             {
                 parentClassFileName = classFileName;
-                superDefaultCt = classToProxy.getConstructor(null);
+                if (constructor == null)
+                {
+                    superDefaultCt = classToProxy.getConstructor(null);
+                }
+                else
+                {
+                    superDefaultCt = constructor;
+
+                    Class<?>[] exceptionTypes = constructor.getExceptionTypes();
+                    exceptions = exceptionTypes.length == 0 ? null : new String[exceptionTypes.length];
+                    for (int i = 0; i < exceptionTypes.length; i++)
+                    {
+                        exceptions[i] = Type.getDescriptor(exceptionTypes[i]);
+                    }
+                }
             }
 
             final String descriptor = Type.getConstructorDescriptor(superDefaultCt);
-            final MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", descriptor, null, null);
+            final MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", descriptor, null, exceptions);
             mv.visitCode();
             mv.visitVarInsn(Opcodes.ALOAD, 0);
+            if (constructor != null)
+            {
+                for (int i = 1; i <= constructor.getParameterTypes().length; i++)
+                {
+                    mv.visitVarInsn(Opcodes.ALOAD, i);
+                }
+            }
             mv.visitMethodInsn(Opcodes.INVOKESPECIAL, parentClassFileName, "<init>", descriptor, false);
 
             mv.visitInsn(Opcodes.RETURN);

Added: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/decorators/constructor/DecoratorConstructorInjectionTest.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/decorators/constructor/DecoratorConstructorInjectionTest.java?rev=1647547&view=auto
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/decorators/constructor/DecoratorConstructorInjectionTest.java (added)
+++ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/decorators/constructor/DecoratorConstructorInjectionTest.java Tue Dec 23 11:17:34 2014
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.webbeans.test.decorators.constructor;
+
+import junit.framework.Assert;
+import org.apache.webbeans.test.AbstractUnitTest;
+import org.junit.Test;
+
+import javax.annotation.Priority;
+import javax.decorator.Decorator;
+import javax.decorator.Delegate;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+
+public class DecoratorConstructorInjectionTest extends AbstractUnitTest
+{
+    @Test
+    public void run()
+    {
+        startContainer(Foo.class, Dec.class, FooImpl.class, ABeanJustToEnsureInjectionsWork.class);
+        Assert.assertTrue(getInstance(Foo.class).dec());
+    }
+
+    public static interface Foo
+    {
+        boolean dec();
+        boolean normal();
+    }
+
+    public static class FooImpl implements Foo
+    {
+        public boolean dec()
+        {
+            return false;
+        }
+
+        @Override
+        public boolean normal()
+        {
+            return true;
+        }
+    }
+
+    @Decorator
+    @Priority(1)
+    public static abstract class Dec implements Foo
+    {
+        private final Foo del;
+        private final Integer number;
+        private final ABeanJustToEnsureInjectionsWork injection;
+
+        @Inject
+        public Dec(@Delegate @Any Foo delegate, ABeanJustToEnsureInjectionsWork injection, Integer integer) throws IllegalArgumentException
+        {
+            this.del = delegate;
+            this.number = integer;
+            this.injection = injection;
+        }
+
+        @Override
+        public boolean dec()
+        {
+            return del != null && !Foo.class.cast(del).dec() && Foo.class.cast(del).normal()
+                    && number == 1 && injection != null;
+        }
+    }
+
+    public static class ABeanJustToEnsureInjectionsWork
+    {
+        @Produces
+        public Integer aWrapper = 1;
+    }
+}

Modified: openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/interceptors/factory/SubclassProxyFactoryTest.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/interceptors/factory/SubclassProxyFactoryTest.java?rev=1647547&r1=1647546&r2=1647547&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/interceptors/factory/SubclassProxyFactoryTest.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/test/interceptors/factory/SubclassProxyFactoryTest.java Tue Dec 23 11:17:34 2014
@@ -35,7 +35,8 @@ public class SubclassProxyFactoryTest ex
         startContainer();
 
         Class<? extends MyAbstractTestDecorator> subClass
-                = getWebBeansContext().getSubclassProxyFactory().createSubClass(this.getClass().getClassLoader(), MyAbstractTestDecorator.class);
+                = getWebBeansContext().getSubclassProxyFactory().createSubClass(
+                this.getClass().getClassLoader(), getBeanManager().createAnnotatedType(MyAbstractTestDecorator.class));
         Assert.assertNotNull(subClass);
 
         MyAbstractTestDecorator instance = subClass.newInstance();