Return-Path: X-Original-To: apmail-openwebbeans-commits-archive@www.apache.org Delivered-To: apmail-openwebbeans-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 156A7EE7E for ; Wed, 13 Feb 2013 14:45:29 +0000 (UTC) Received: (qmail 4413 invoked by uid 500); 13 Feb 2013 14:45:29 -0000 Delivered-To: apmail-openwebbeans-commits-archive@openwebbeans.apache.org Received: (qmail 4310 invoked by uid 500); 13 Feb 2013 14:45:26 -0000 Mailing-List: contact commits-help@openwebbeans.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@openwebbeans.apache.org Delivered-To: mailing list commits@openwebbeans.apache.org Received: (qmail 4195 invoked by uid 99); 13 Feb 2013 14:45:24 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 13 Feb 2013 14:45:24 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 13 Feb 2013 14:45:14 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 077062388978; Wed, 13 Feb 2013 14:44:56 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1445630 - in /openwebbeans/trunk/webbeans-impl/src: main/java/org/apache/webbeans/proxy/ test/java/org/apache/webbeans/newtests/interceptors/factory/ Date: Wed, 13 Feb 2013 14:44:55 -0000 To: commits@openwebbeans.apache.org From: struberg@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130213144456.077062388978@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 + 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 implements Provider { 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; + } + + +}