Author: struberg
Date: Wed Feb 13 14:44:55 2013
New Revision: 1445630
URL: http://svn.apache.org/r1445630
Log:
OWB-344 add proxy support for protected methods
Added:
openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/ProtectedUsageBean.java
Modified:
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/test/java/org/apache/webbeans/newtests/interceptors/factory/NormalScopeProxyFactoryTest.java
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=1445630&r1=1445629&r2=1445630&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
Wed Feb 13 14:44:55 2013
@@ -619,4 +619,80 @@ public abstract class AbstractProxyFacto
});
}
+ /**
+ * Create an Object[] parameter which contains all the parameters of the
currently invoked method
+ * and store this array for use in the call stack.
+ * @param mv
+ * @param parameterTypes
+ */
+ protected void pushMethodParameterArray(MethodVisitor mv, Class<?>[]
parameterTypes)
+ {
+ // need to construct the array of objects passed in
+ // create the Object[]
+ createArrayDefinition(mv, parameterTypes.length, Object.class);
+
+ int index = 1;
+ // push parameters into array
+ for (int i = 0; i < parameterTypes.length; i++)
+ {
+ // keep copy of array on stack
+ mv.visitInsn(Opcodes.DUP);
+
+ final Class<?> parameterType = parameterTypes[i];
+
+ // push number onto stack
+ pushIntOntoStack(mv, i);
+
+ if (parameterType.isPrimitive())
+ {
+ String wrapperType = getWrapperType(parameterType);
+ mv.visitVarInsn(getVarInsn(parameterType), index);
+
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, wrapperType,
"valueOf",
+ "(" + Type.getDescriptor(parameterType) + ")L" +
wrapperType + ";");
+ mv.visitInsn(Opcodes.AASTORE);
+
+ if (Long.TYPE.equals(parameterType) ||
Double.TYPE.equals(parameterType))
+ {
+ index += 2;
+ }
+ else
+ {
+ index++;
+ }
+ }
+ else
+ {
+ mv.visitVarInsn(Opcodes.ALOAD, index);
+ mv.visitInsn(Opcodes.AASTORE);
+ index++;
+ }
+ }
+ }
+
+ /**
+ * pushes an array of the specified size to the method visitor. The
generated bytecode will leave
+ * the new array at the top of the stack.
+ *
+ * @param mv MethodVisitor to use
+ * @param size Size of the array to create
+ * @param type Type of array to create
+ * @throws ProxyGenerationException
+ */
+ protected void createArrayDefinition(final MethodVisitor mv, final int
size, final Class<?> type)
+ throws ProxyGenerationException
+ {
+ // create a new array of java.lang.class (2)
+
+ if (size < 0)
+ {
+ throw new ProxyGenerationException("Array size cannot be less than
zero");
+ }
+
+ pushIntOntoStack(mv, size);
+
+ mv.visitTypeInsn(Opcodes.ANEWARRAY,
type.getCanonicalName().replace('.', '/'));
+ }
+
+
}
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=1445630&r1=1445629&r2=1445630&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
Wed Feb 13 14:44:55 2013
@@ -437,6 +437,7 @@ public class InterceptorDecoratorProxyFa
final Label l4 = new Label();
mv.visitLabel(l4);
+
mv.visitVarInsn(Opcodes.ALOAD, 0);
// get the invocationHandler field from this class
@@ -451,47 +452,10 @@ public class InterceptorDecoratorProxyFa
// and now load the Method from the array
mv.visitInsn(Opcodes.AALOAD);
- // need to construct the array of objects passed in
- // create the Object[]
- createArrayDefinition(mv, parameterTypes.length, Object.class);
-
- int index = 1;
- // push parameters into array
- for (int i = 0; i < parameterTypes.length; i++)
- {
- // keep copy of array on stack
- mv.visitInsn(Opcodes.DUP);
-
- final Class<?> parameterType = parameterTypes[i];
-
- // push number onto stack
- pushIntOntoStack(mv, i);
-
- if (parameterType.isPrimitive())
- {
- String wrapperType = getWrapperType(parameterType);
- mv.visitVarInsn(getVarInsn(parameterType), index);
- mv.visitMethodInsn(Opcodes.INVOKESTATIC, wrapperType,
"valueOf",
- "(" + Type.getDescriptor(parameterType) + ")L" +
wrapperType + ";");
- mv.visitInsn(Opcodes.AASTORE);
+ // prepare the parameter array as Object[] and store it on the stack
+ pushMethodParameterArray(mv, parameterTypes);
- if (Long.TYPE.equals(parameterType) ||
Double.TYPE.equals(parameterType))
- {
- index += 2;
- }
- else
- {
- index++;
- }
- }
- else
- {
- mv.visitVarInsn(Opcodes.ALOAD, index);
- mv.visitInsn(Opcodes.AASTORE);
- index++;
- }
- }
// invoke the invocationHandler
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
Type.getInternalName(InterceptorHandler.class), "invoke",
@@ -570,29 +534,4 @@ public class InterceptorDecoratorProxyFa
}
- /**
- * pushes an array of the specified size to the method visitor. The
generated bytecode will leave
- * the new array at the top of the stack.
- *
- * @param mv MethodVisitor to use
- * @param size Size of the array to create
- * @param type Type of array to create
- * @throws ProxyGenerationException
- */
- private void createArrayDefinition(final MethodVisitor mv, final int size,
final Class<?> type)
- throws ProxyGenerationException
- {
- // create a new array of java.lang.class (2)
-
- if (size < 0)
- {
- throw new ProxyGenerationException("Array size cannot be less than
zero");
- }
-
- pushIntOntoStack(mv, size);
-
- mv.visitTypeInsn(Opcodes.ANEWARRAY,
type.getCanonicalName().replace('.', '/'));
- }
-
-
}
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=1445630&r1=1445629&r2=1445630&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
Wed Feb 13 14:44:55 2013
@@ -350,7 +350,16 @@ public class NormalScopeProxyFactory ext
Class<?> classToProxy, Method[]
interceptedMethods)
throws ProxyGenerationException
{
- //X TODO invoke protected methods via reflection
+ if (interceptedMethods == null)
+ {
+ return;
+ }
+
+ for (int i = 0; i < interceptedMethods.length; i++)
+ {
+ Method proxiedMethod = interceptedMethods[i];
+ generateDelegationMethod(cw, proxiedMethod, i, classToProxy,
proxyClassFileName);
+ }
}
@Override
@@ -413,5 +422,96 @@ public class NormalScopeProxyFactory ext
}
+ private void generateDelegationMethod(ClassWriter cw, Method method, int
methodIndex, Class<?> classToProxy, String proxyClassFileName)
+ {
+ final Class<?> returnType = method.getReturnType();
+ final Class<?>[] parameterTypes = method.getParameterTypes();
+ final int modifiers = method.getModifiers();
+
+ // push the method definition
+ int modifier = modifiers & (Opcodes.ACC_PUBLIC |
Opcodes.ACC_PROTECTED);
+
+ MethodVisitor mv = cw.visitMethod(modifier, method.getName(),
Type.getMethodDescriptor(method), null, null);
+ mv.visitCode();
+
+
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+
+ // add the Method from the static array as first parameter
+ mv.visitFieldInsn(Opcodes.GETSTATIC, proxyClassFileName,
FIELD_PROTECTED_METHODS, Type.getDescriptor(Method[].class));
+
+ // push the methodIndex of the current method
+ mv.visitIntInsn(Opcodes.BIPUSH, methodIndex);
+
+ // and now load the Method from the array
+ mv.visitInsn(Opcodes.AALOAD);
+
+
+ // now invoke the get() on the contextual instance Provider<T>
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitFieldInsn(Opcodes.GETFIELD, proxyClassFileName,
FIELD_INSTANCE_PROVIDER, Type.getDescriptor(Provider.class));
+
+ // invoke the get() method on the Provider
+ mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
Type.getInternalName(Provider.class), "get", "()Ljava/lang/Object;");
+
+
+ // prepare the parameter array as Object[] and store it on the stack
+ pushMethodParameterArray(mv, parameterTypes);
+
+
+ // this invokes NormalScopeProxyFactory.delegateProtectedMethod
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC,
Type.getInternalName(NormalScopeProxyFactory.class), "delegateProtectedMethod",
+
"(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
+
+ // cast the result
+ mv.visitTypeInsn(Opcodes.CHECKCAST, getCastType(returnType));
+
+ //X temporary
+ //X mv.visitInsn(Opcodes.ACONST_NULL);
+
+
+ if (returnType.isPrimitive() && (!Void.TYPE.equals(returnType)))
+ {
+ // get the primitive value
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
getWrapperType(returnType), getPrimitiveMethod(returnType),
+ "()" + Type.getDescriptor(returnType));
+ }
+
+ mv.visitInsn(getReturnInsn(returnType));
+
+ // finish this method
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+
+
+ /**
+ * This method get invoked via generated ASM code.
+ * It delegates to the underlying Method so we don't need to do
+ * all the reflection stuff in our generated bytecode.
+ *
+ * @see #generateDelegationMethod(org.apache.xbean.asm.ClassWriter,
java.lang.reflect.Method, int, Class, String)
+ */
+ @SuppressWarnings("unused")
+ public static Object delegateProtectedMethod(Method method, Object
instance, Object[] params)
+ {
+ try
+ {
+ if (!method.isAccessible())
+ {
+ method.setAccessible(true);
+ }
+ return method.invoke(instance, params);
+ }
+ catch (InvocationTargetException ite)
+ {
+ throw ExceptionUtil.throwAsRuntimeException(ite.getCause());
+ }
+ catch (Exception e)
+ {
+ throw ExceptionUtil.throwAsRuntimeException(e);
+ }
+ }
}
Modified:
openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/NormalScopeProxyFactoryTest.java
URL:
http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/NormalScopeProxyFactoryTest.java?rev=1445630&r1=1445629&r2=1445630&view=diff
==============================================================================
---
openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/NormalScopeProxyFactoryTest.java
(original)
+++
openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/NormalScopeProxyFactoryTest.java
Wed Feb 13 14:44:55 2013
@@ -78,6 +78,23 @@ public class NormalScopeProxyFactoryTest
}
+ /**
+ * Test if protected and package scope methods are proxied as well.
+ * @throws Exception
+ */
+ @Test
+ public void testProtectedMethod() throws Exception
+ {
+ startContainer(ProtectedUsageBean.class);
+
+ ProtectedUsageBean protectedUsage =
getInstance(ProtectedUsageBean.class);
+ Assert.assertNotNull(protectedUsage);
+
+ Assert.assertEquals(42, protectedUsage.getPackageMeaningOfLife());
+ Assert.assertEquals(42, protectedUsage.getProtectedMeaningOfLife());
+ Assert.assertEquals(Integer.valueOf(42),
protectedUsage.getProtectedIntegerMeaningOfLife());
+ }
+
public static class TestContextualInstanceProvider<T> implements
Provider<T>
{
private T instance;
Added:
openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/ProtectedUsageBean.java
URL:
http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/ProtectedUsageBean.java?rev=1445630&view=auto
==============================================================================
---
openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/ProtectedUsageBean.java
(added)
+++
openwebbeans/trunk/webbeans-impl/src/test/java/org/apache/webbeans/newtests/interceptors/factory/ProtectedUsageBean.java
Wed Feb 13 14:44:55 2013
@@ -0,0 +1,51 @@
+/*
+ * 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.newtests.interceptors.factory;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.RequestScoped;
+
+@RequestScoped
+public class ProtectedUsageBean
+{
+ private int meaningOfLife;
+
+ @PostConstruct
+ private void init()
+ {
+ meaningOfLife = 42;
+ }
+
+ protected int getProtectedMeaningOfLife()
+ {
+ return meaningOfLife;
+ }
+
+ protected Integer getProtectedIntegerMeaningOfLife()
+ {
+ return Integer.valueOf(meaningOfLife);
+ }
+
+ int getPackageMeaningOfLife()
+ {
+ return meaningOfLife;
+ }
+
+
+}