Return-Path: X-Original-To: apmail-deltaspike-commits-archive@www.apache.org Delivered-To: apmail-deltaspike-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 BC66217CE1 for ; Sat, 14 Mar 2015 12:57:56 +0000 (UTC) Received: (qmail 79348 invoked by uid 500); 14 Mar 2015 12:57:56 -0000 Delivered-To: apmail-deltaspike-commits-archive@deltaspike.apache.org Received: (qmail 79308 invoked by uid 500); 14 Mar 2015 12:57:56 -0000 Mailing-List: contact commits-help@deltaspike.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@deltaspike.apache.org Delivered-To: mailing list commits@deltaspike.apache.org Received: (qmail 79299 invoked by uid 99); 14 Mar 2015 12:57:56 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 14 Mar 2015 12:57:56 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 52DABE0833; Sat, 14 Mar 2015 12:57:56 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: tandraschko@apache.org To: commits@deltaspike.apache.org Message-Id: <4451461e33c9444fb0313b82421bff72@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: deltaspike git commit: DELTASPIKE-420 proceed the original method inside the interceptor chain Date: Sat, 14 Mar 2015 12:57:56 +0000 (UTC) Repository: deltaspike Updated Branches: refs/heads/master 2955ce346 -> 72c9c81f7 DELTASPIKE-420 proceed the original method inside the interceptor chain Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/72c9c81f Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/72c9c81f Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/72c9c81f Branch: refs/heads/master Commit: 72c9c81f7e38d777f171898db8aceb2264fa7b01 Parents: 2955ce3 Author: Thomas Andraschko Authored: Sat Mar 14 13:57:15 2015 +0100 Committer: Thomas Andraschko Committed: Sat Mar 14 13:57:47 2015 +0100 ---------------------------------------------------------------------- .../AbstractManualInvocationHandler.java | 103 +++ .../interception/ManualInvocationContext.java | 353 ++++---- .../interception/ManualInvocationHandler.java | 106 --- ...nualInvocationThrowableWrapperException.java | 27 + .../impl/proxy/AsmProxyClassGenerator.java | 817 +++++++++---------- .../proxy/CallSuperManualInvocationHandler.java | 41 + .../impl/proxy/PartialBeanProxyFactory.java | 16 +- .../proxy/RedirectManualInvocationHandler.java | 42 + .../uc004/ScopedPartialBeanTest.java | 8 +- .../core/api/partialbean/uc007/PartialBean.java | 2 +- 10 files changed, 824 insertions(+), 691 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/AbstractManualInvocationHandler.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/AbstractManualInvocationHandler.java b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/AbstractManualInvocationHandler.java new file mode 100644 index 0000000..8c9a5ce --- /dev/null +++ b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/AbstractManualInvocationHandler.java @@ -0,0 +1,103 @@ +/* + * 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.deltaspike.partialbean.impl.interception; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import javax.enterprise.inject.Typed; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.InterceptionType; +import javax.enterprise.inject.spi.Interceptor; +import javax.interceptor.InterceptorBinding; +import org.apache.deltaspike.core.api.provider.BeanManagerProvider; + +@Typed +public abstract class AbstractManualInvocationHandler implements InvocationHandler +{ + @Override + public Object invoke(Object proxy, Method method, Object[] parameters) throws Throwable + { + List> interceptors = resolveInterceptors(proxy, method); + if (interceptors != null && interceptors.size() > 0) + { + try + { + ManualInvocationContext invocationContext = + new ManualInvocationContext(this, interceptors, proxy, method, parameters, null); + + Object returnValue = invocationContext.proceed(); + + if (invocationContext.isProceedOriginal()) + { + return invocationContext.getProceedOriginalReturnValue(); + } + + return returnValue; + } + catch (ManualInvocationThrowableWrapperException e) + { + throw e.getCause(); + } + } + + return proceedOriginal(proxy, method, parameters); + } + + protected abstract Object proceedOriginal(Object proxy, Method method, Object[] parameters) throws Throwable; + + protected List> resolveInterceptors(Object instance, Method method) + { + Annotation[] interceptorBindings = extractInterceptorBindings(instance, method); + if (interceptorBindings.length > 0) + { + BeanManager beanManager = BeanManagerProvider.getInstance().getBeanManager(); + return beanManager.resolveInterceptors(InterceptionType.AROUND_INVOKE, interceptorBindings); + } + + return null; + } + + protected Annotation[] extractInterceptorBindings(Object instance, Method method) + { + ArrayList bindings = new ArrayList(); + + for (Annotation annotation : instance.getClass().getDeclaredAnnotations()) + { + if (annotation.annotationType().isAnnotationPresent(InterceptorBinding.class) + && !bindings.contains(annotation)) + { + bindings.add(annotation); + } + } + + for (Annotation annotation : method.getDeclaredAnnotations()) + { + if (annotation.annotationType().isAnnotationPresent(InterceptorBinding.class) + && !bindings.contains(annotation)) + { + bindings.add(annotation); + } + } + + return bindings.toArray(new Annotation[bindings.size()]); + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationContext.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationContext.java b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationContext.java index ede57cc..39cdc8f 100644 --- a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationContext.java +++ b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationContext.java @@ -1,166 +1,187 @@ -/* - * 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.deltaspike.partialbean.impl.interception; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.inject.Typed; -import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.InterceptionType; -import javax.enterprise.inject.spi.Interceptor; -import javax.interceptor.InvocationContext; -import org.apache.deltaspike.core.api.provider.BeanManagerProvider; - -@Typed -public class ManualInvocationContext implements InvocationContext -{ - protected List> interceptors; - protected int interceptorIndex; - protected T target; - protected Method method; - protected Object[] parameters; - protected Map contextData; - protected Object timer; - protected ManualInvocationHandler manualInvocationHandler; - - protected BeanManager beanManager; - - protected boolean proceedOriginal; - - public ManualInvocationContext(ManualInvocationHandler manualInvocationHandler, - List> interceptors, T target, Method method, Object[] parameters, Object timer) - { - this.manualInvocationHandler = manualInvocationHandler; - this.interceptors = interceptors; - this.target = target; - this.method = method; - this.parameters = parameters; - this.timer = timer; - - this.interceptorIndex = 0; - } - - @Override - public Object getTarget() - { - return target; - } - - @Override - public Method getMethod() - { - return method; - } - - @Override - public Object[] getParameters() - { - return parameters; - } - - @Override - public void setParameters(Object[] os) - { - parameters = os; - } - - @Override - public Map getContextData() - { - if (contextData == null) - { - contextData = new HashMap(); - } - return contextData; - } - - @Override - public Object proceed() throws Exception - { - if (proceedOriginal) - { - return null; - } - - if (interceptors.size() > interceptorIndex) - { - Interceptor interceptor = null; - CreationalContext creationalContext = null; - H interceptorInstance = null; - - try - { - // lazy init beanManager - if (beanManager == null) - { - beanManager = BeanManagerProvider.getInstance().getBeanManager(); - } - - interceptor = interceptors.get(interceptorIndex++); - creationalContext = beanManager.createCreationalContext(interceptor); - interceptorInstance = interceptor.create(creationalContext); - - return interceptor.intercept(InterceptionType.AROUND_INVOKE, interceptorInstance, this); - } - finally - { - if (creationalContext != null) - { - if (interceptorInstance != null && interceptor != null) - { - interceptor.destroy(interceptorInstance, creationalContext); - } - - creationalContext.release(); - } - } - } - - - // workaround for OWB 1.1 - // interceptor#intercept always return null. Therefore we must remember here, - // that our interceptor chain is finished and #proceedOriginal should be called outside - proceedOriginal = true; - - // all interceptors handled without return a value - return manualInvocationHandler.proceedOriginal(target, method, parameters); - } - - @Override - public Object getTimer() - { - return timer; - } - - // @Override - // CDI 1.1 compatibility - public Constructor getConstructor() - { - return null; - } - - public boolean isProceedOriginal() - { - return proceedOriginal; - } -} +/* + * 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.deltaspike.partialbean.impl.interception; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.Typed; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.InterceptionType; +import javax.enterprise.inject.spi.Interceptor; +import javax.interceptor.InvocationContext; +import org.apache.deltaspike.core.api.provider.BeanManagerProvider; + +@Typed +public class ManualInvocationContext implements InvocationContext +{ + protected List> interceptors; + protected int interceptorIndex; + protected T target; + protected Method method; + protected Object[] parameters; + protected Map contextData; + protected Object timer; + protected AbstractManualInvocationHandler manualInvocationHandler; + + protected BeanManager beanManager; + + protected boolean proceedOriginal; + protected Object proceedOriginalReturnValue; + + public ManualInvocationContext(AbstractManualInvocationHandler manualInvocationHandler, + List> interceptors, T target, Method method, Object[] parameters, Object timer) + { + this.manualInvocationHandler = manualInvocationHandler; + this.interceptors = interceptors; + this.target = target; + this.method = method; + this.parameters = parameters; + this.timer = timer; + + this.interceptorIndex = 0; + } + + @Override + public Object getTarget() + { + return target; + } + + @Override + public Method getMethod() + { + return method; + } + + @Override + public Object[] getParameters() + { + return parameters; + } + + @Override + public void setParameters(Object[] os) + { + parameters = os; + } + + @Override + public Map getContextData() + { + if (contextData == null) + { + contextData = new HashMap(); + } + return contextData; + } + + @Override + public Object proceed() throws Exception + { + if (proceedOriginal) + { + return null; + } + + if (interceptors.size() > interceptorIndex) + { + Interceptor interceptor = null; + CreationalContext creationalContext = null; + H interceptorInstance = null; + + try + { + // lazy init beanManager + if (beanManager == null) + { + beanManager = BeanManagerProvider.getInstance().getBeanManager(); + } + + interceptor = interceptors.get(interceptorIndex++); + creationalContext = beanManager.createCreationalContext(interceptor); + interceptorInstance = interceptor.create(creationalContext); + + return interceptor.intercept(InterceptionType.AROUND_INVOKE, interceptorInstance, this); + } + finally + { + if (creationalContext != null) + { + if (interceptorInstance != null && interceptor != null) + { + interceptor.destroy(interceptorInstance, creationalContext); + } + + creationalContext.release(); + } + } + } + + + // workaround for OWB 1.1, otherwise we could just return the proceedOriginalReturnValue value in this method + try + { + proceedOriginal = true; + proceedOriginalReturnValue = manualInvocationHandler.proceedOriginal(target, method, parameters); + } + catch (Exception e) + { + throw e; + } + catch (Throwable e) + { + // wrap the Throwable here as interceptors declared only "throws Exception" + throw new ManualInvocationThrowableWrapperException(e); + } + + return null; + } + + @Override + public Object getTimer() + { + return timer; + } + + // @Override + // CDI 1.1 compatibility + public Constructor getConstructor() + { + return null; + } + + public boolean isProceedOriginal() + { + return proceedOriginal; + } + + public Object getProceedOriginalReturnValue() + { + return proceedOriginalReturnValue; + } + + public void setProceedOriginalReturnValue(Object proceedOriginalReturnValue) + { + this.proceedOriginalReturnValue = proceedOriginalReturnValue; + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationHandler.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationHandler.java b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationHandler.java deleted file mode 100644 index b882bba..0000000 --- a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationHandler.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.deltaspike.partialbean.impl.interception; - -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import javax.enterprise.inject.Typed; -import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.InterceptionType; -import javax.enterprise.inject.spi.Interceptor; -import javax.interceptor.InterceptorBinding; -import org.apache.deltaspike.core.api.provider.BeanManagerProvider; - -@Typed -public class ManualInvocationHandler implements InvocationHandler -{ - public static final Object PROCEED_ORIGINAL = new Object(); - - private static final ManualInvocationHandler INSTANCE = new ManualInvocationHandler(); - - public static Object staticInvoke(T proxy, Method method, Object[] parameters) throws Throwable - { - return INSTANCE.invoke(proxy, method, parameters); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] parameters) throws Throwable - { - List> interceptors = resolveInterceptors(proxy, method); - if (interceptors != null && interceptors.size() > 0) - { - ManualInvocationContext invocationContext = - new ManualInvocationContext(this, interceptors, proxy, method, parameters, null); - Object returnValue = invocationContext.proceed(); - if (invocationContext.isProceedOriginal()) - { - return proceedOriginal(proxy, method, parameters); - } - return returnValue; - } - - return proceedOriginal(proxy, method, parameters); - } - - protected Object proceedOriginal(Object proxy, Method method, Object[] parameters) throws Exception - { - return PROCEED_ORIGINAL; - } - - protected List> resolveInterceptors(Object instance, Method method) - { - Annotation[] interceptorBindings = extractInterceptorBindings(instance, method); - if (interceptorBindings.length > 0) - { - BeanManager beanManager = BeanManagerProvider.getInstance().getBeanManager(); - return beanManager.resolveInterceptors(InterceptionType.AROUND_INVOKE, - interceptorBindings); - } - - return null; - } - - protected Annotation[] extractInterceptorBindings(Object instance, Method method) - { - ArrayList bindings = new ArrayList(); - - for (Annotation annotation : instance.getClass().getDeclaredAnnotations()) - { - if (annotation.annotationType().isAnnotationPresent(InterceptorBinding.class) - && !bindings.contains(annotation)) - { - bindings.add(annotation); - } - } - - for (Annotation annotation : method.getDeclaredAnnotations()) - { - if (annotation.annotationType().isAnnotationPresent(InterceptorBinding.class) - && !bindings.contains(annotation)) - { - bindings.add(annotation); - } - } - - return bindings.toArray(new Annotation[bindings.size()]); - } -} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationThrowableWrapperException.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationThrowableWrapperException.java b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationThrowableWrapperException.java new file mode 100644 index 0000000..23edf17 --- /dev/null +++ b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/interception/ManualInvocationThrowableWrapperException.java @@ -0,0 +1,27 @@ +/* + * 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.deltaspike.partialbean.impl.interception; + +public class ManualInvocationThrowableWrapperException extends Exception +{ + public ManualInvocationThrowableWrapperException(Throwable e) + { + super(e); + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/AsmProxyClassGenerator.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/AsmProxyClassGenerator.java b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/AsmProxyClassGenerator.java index eb6de01..b877e01 100644 --- a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/AsmProxyClassGenerator.java +++ b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/AsmProxyClassGenerator.java @@ -1,414 +1,403 @@ -/* - * 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.deltaspike.partialbean.impl.proxy; - -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.UndeclaredThrowableException; -import java.util.Arrays; -import javax.enterprise.inject.Typed; -import org.apache.deltaspike.partialbean.impl.interception.ManualInvocationHandler; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.GeneratorAdapter; -import org.objectweb.asm.commons.Method; - -@Typed -public abstract class AsmProxyClassGenerator -{ - private static final String FIELDNAME_HANDLER = "__handler"; - - private static final Type TYPE_CLASS = Type.getType(Class.class); - private static final Type TYPE_OBJECT = Type.getType(Object.class); - - private AsmProxyClassGenerator() - { - // prevent instantiation - } - - public static Class generateProxyClass(ClassLoader classLoader, - Class targetClass, - Class invocationHandlerClass, - String suffix, - java.lang.reflect.Method[] redirectMethods, - java.lang.reflect.Method[] interceptionMethods) - { - String proxyName = targetClass.getCanonicalName() + suffix; - String classFileName = proxyName.replace('.', '/'); - - byte[] proxyBytes = generateProxyClassBytes(targetClass, invocationHandlerClass, - classFileName, redirectMethods, interceptionMethods); - - Class proxyClass = (Class) loadClass(classLoader, proxyName, proxyBytes); - - return proxyClass; - } - - private static byte[] generateProxyClassBytes(Class targetClass, - Class invocationHandlerClass, - String proxyName, - java.lang.reflect.Method[] redirectMethods, - java.lang.reflect.Method[] interceptionMethods) - { - Class superClass = targetClass; - String[] interfaces = new String[] { }; - - if (targetClass.isInterface()) - { - superClass = Object.class; - interfaces = new String[] { Type.getInternalName(targetClass) }; - } - - // add PartialBeanProxy as interface - interfaces = Arrays.copyOf(interfaces, interfaces.length + 1); - interfaces[interfaces.length - 1] = Type.getInternalName(PartialBeanProxy.class); - - Type superType = Type.getType(superClass); - Type proxyType = Type.getObjectType(proxyName); - Type invocationHandlerType = Type.getType(invocationHandlerClass); - - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); - cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, proxyType.getInternalName(), null, - superType.getInternalName(), interfaces); - - // copy annotations - for (Annotation annotation : targetClass.getDeclaredAnnotations()) - { - cw.visitAnnotation(Type.getDescriptor(annotation.annotationType()), true).visitEnd(); - } - - defineInvocationHandlerField(cw, invocationHandlerType); - defineConstructor(cw, proxyType, superType); - definePartialBeanProxyMethods(cw, proxyType, invocationHandlerType); - - for (java.lang.reflect.Method method : redirectMethods) - { - defineMethod(cw, method, proxyType, invocationHandlerType, superType, true); - } - - for (java.lang.reflect.Method method : interceptionMethods) - { - defineMethod(cw, method, proxyType, invocationHandlerType, superType, false); - } - - return cw.toByteArray(); - } - - private static void defineInvocationHandlerField(ClassWriter cw, Type invocationHandlerType) - { - // generates - // private MyPartialBeanInvocationHandler __handler; - cw.visitField(Opcodes.ACC_PRIVATE, FIELDNAME_HANDLER, invocationHandlerType.getDescriptor(), null, null) - .visitEnd(); - } - - private static void defineConstructor(ClassWriter cw, Type proxyType, Type superType) - { - GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, - new Method("", Type.VOID_TYPE, new Type[]{ }), - null, - null, - cw); - - mg.visitCode(); - - // invoke super constructor - mg.loadThis(); - mg.invokeConstructor(superType, Method.getMethod("void ()")); - mg.returnValue(); - mg.endMethod(); - - mg.visitEnd(); - } - - private static void definePartialBeanProxyMethods(ClassWriter cw, Type proxyType, Type invocationHandlerType) - { - try - { - // implement #setRedirectInvocationHandler - Method asmMethod = Method.getMethod( - PartialBeanProxy.class.getDeclaredMethod("setRedirectInvocationHandler", - InvocationHandler.class)); - GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, asmMethod, null, null, cw); - - mg.visitCode(); - - mg.loadThis(); - mg.loadArg(0); - mg.checkCast(invocationHandlerType); - mg.putField(proxyType, FIELDNAME_HANDLER, invocationHandlerType); - mg.returnValue(); - - mg.visitMaxs(2, 1); - mg.visitEnd(); - - - // implement #getRedirectInvocationHandler - asmMethod = Method.getMethod(PartialBeanProxy.class.getDeclaredMethod("getRedirectInvocationHandler")); - mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, asmMethod, null, null, cw); - - mg.visitCode(); - - mg.loadThis(); - mg.getField(proxyType, FIELDNAME_HANDLER, invocationHandlerType); - mg.returnValue(); - - mg.visitMaxs(2, 1); - mg.visitEnd(); - } - catch (NoSuchMethodException e) - { - throw new IllegalStateException("Unable to implement " + PartialBeanProxy.class.getName(), e); - } - } - - private static void defineMethod(ClassWriter cw, java.lang.reflect.Method method, Type proxyType, - Type invocationHandlerType, Type superType, boolean callInvocationHandler) - { - Type methodType = Type.getType(method); - Type[] exceptionTypes = getTypes(method.getExceptionTypes()); - - // push the method definition - int modifiers = (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED) & method.getModifiers(); - Method asmMethod = Method.getMethod(method); - GeneratorAdapter mg = new GeneratorAdapter(modifiers, asmMethod, null, exceptionTypes, cw); - - // copy annotations - for (Annotation annotation : method.getDeclaredAnnotations()) - { - mg.visitAnnotation(Type.getDescriptor(annotation.annotationType()), true).visitEnd(); - } - - mg.visitCode(); - - Label tryBlockStart = mg.mark(); - - mg.loadThis(); - loadCurrentMethod(mg, method, methodType); - loadArguments(mg, method, methodType); - - // invoke our ProxyInvocationHandler and store it in a local variable - int manualInvocationHandlerReturnValue = mg.newLocal(TYPE_OBJECT); - mg.invokeStatic(Type.getType(ManualInvocationHandler.class), - Method.getMethod("Object staticInvoke(Object, java.lang.reflect.Method, Object[])")); - mg.storeLocal(manualInvocationHandlerReturnValue); - - // check if ManualInvocationHandler returned the PROCEED_ORIGINAL object - // if true, we switch to our special logic, otherwise return the returned value - Label proceedOriginalStart = new Label(); - mg.getStatic(Type.getType(ManualInvocationHandler.class), "PROCEED_ORIGINAL", TYPE_OBJECT); - mg.loadLocal(manualInvocationHandlerReturnValue); - mg.ifCmp(TYPE_OBJECT, GeneratorAdapter.EQ, proceedOriginalStart); - - // cast the result - mg.loadLocal(manualInvocationHandlerReturnValue); - mg.unbox(methodType.getReturnType()); - - Label tryBlockEnd = mg.mark(); - - // push return - mg.returnValue(); - - mg.mark(proceedOriginalStart); - if (callInvocationHandler) - { - // call stored InvocationHandler - mg.loadThis(); - mg.getField(proxyType, FIELDNAME_HANDLER, invocationHandlerType); - mg.loadThis(); - loadCurrentMethod(mg, method, methodType); - loadArguments(mg, method, methodType); - mg.invokeVirtual(invocationHandlerType, - Method.getMethod("Object invoke(Object, java.lang.reflect.Method, Object[])")); - mg.unbox(methodType.getReturnType()); - mg.returnValue(); - } - else - { - // call super method - mg.loadThis(); - mg.loadArgs(); - mg.visitMethodInsn(Opcodes.INVOKESPECIAL, - superType.getInternalName(), - method.getName(), - Type.getMethodDescriptor(method), - false); - mg.returnValue(); - } - - - - boolean throwableCatched = false; - - // catch declared exceptions - if (exceptionTypes.length > 0) - { - Label rethrow = mg.mark(); - mg.visitVarInsn(Opcodes.ASTORE, 1); - mg.visitVarInsn(Opcodes.ALOAD, 1); - mg.throwException(); - - // catch declared exceptions and rethrow it... - for (Type exceptionType : exceptionTypes) - { - if (exceptionType.getClassName().equals(Throwable.class.getName())) - { - throwableCatched = true; - } - mg.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrow, exceptionType.getInternalName()); - } - } - - if (!throwableCatched) - { - // catch Throwable and wrap it with a UndeclaredThrowableException - Type uteType = Type.getType(UndeclaredThrowableException.class); - Label wrapAndRethrow = mg.mark(); - - mg.visitVarInsn(Opcodes.ASTORE, 1); - mg.newInstance(uteType); - mg.dup(); - mg.visitVarInsn(Opcodes.ALOAD, 1); - mg.invokeConstructor(uteType, - Method.getMethod("void (java.lang.Throwable)")); - mg.throwException(); - - mg.visitTryCatchBlock(tryBlockStart, tryBlockEnd, wrapAndRethrow, Type.getInternalName(Throwable.class)); - } - - // finish the method - mg.endMethod(); - mg.visitMaxs(10, 10); - mg.visitEnd(); - } - - /** - * Generates: - *
-     * Method method =
-     *      method.getDeclaringClass().getMethod("methodName", new Class[] { args... });
-     * 
- * @param mg - * @param method - * @param methodType - */ - private static void loadCurrentMethod(GeneratorAdapter mg, java.lang.reflect.Method method, Type methodType) - { - mg.push(Type.getType(method.getDeclaringClass())); - mg.push(method.getName()); - - // create the Class[] - mg.push(methodType.getArgumentTypes().length); - mg.newArray(TYPE_CLASS); - - // push parameters into array - for (int i = 0; i < methodType.getArgumentTypes().length; i++) - { - // keep copy of array on stack - mg.dup(); - - // push index onto stack - mg.push(i); - mg.push(methodType.getArgumentTypes()[i]); - mg.arrayStore(TYPE_CLASS); - } - - // invoke getMethod() with the method name and the array of types - mg.invokeVirtual(TYPE_CLASS, Method.getMethod("java.lang.reflect.Method getDeclaredMethod(String, Class[])")); - } - - /** - * Defines a new Object[] and push all method argmuments into the array. - * - * @param mg - * @param method - * @param methodType - */ - private static void loadArguments(GeneratorAdapter mg, java.lang.reflect.Method method, Type methodType) - { - // create the Object[] - mg.push(methodType.getArgumentTypes().length); - mg.newArray(TYPE_OBJECT); - - // push parameters into array - for (int i = 0; i < methodType.getArgumentTypes().length; i++) - { - // keep copy of array on stack - mg.dup(); - - // push index onto stack - mg.push(i); - - mg.loadArg(i); - mg.valueOf(methodType.getArgumentTypes()[i]); - mg.arrayStore(TYPE_OBJECT); - } - } - - private static Type[] getTypes(Class... src) - { - Type[] result = new Type[src.length]; - for (int i = 0; i < result.length; i++) - { - result[i] = Type.getType(src[i]); - } - return result; - } - - /** - * Adapted from http://asm.ow2.org/doc/faq.html#Q5 - * - * @param b - * - * @return Class - */ - private static Class loadClass(ClassLoader loader, String className, byte[] b) - { - // override classDefine (as it is protected) and define the class. - try - { - java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod( - "defineClass", String.class, byte[].class, int.class, int.class); - - // protected method invocation - boolean accessible = method.isAccessible(); - if (!accessible) - { - method.setAccessible(true); - } - try - { - return (Class) method.invoke(loader, className, b, Integer.valueOf(0), Integer.valueOf(b.length)); - } - finally - { - if (!accessible) - { - method.setAccessible(false); - } - } - } - catch (Exception e) - { - throw e instanceof RuntimeException ? ((RuntimeException) e) : new RuntimeException(e); - } - } -} +/* + * 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.deltaspike.partialbean.impl.proxy; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Arrays; +import javax.enterprise.inject.Typed; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.GeneratorAdapter; +import org.objectweb.asm.commons.Method; + +@Typed +public abstract class AsmProxyClassGenerator +{ + private static final String FIELDNAME_HANDLER = "__handler"; + + private static final Type TYPE_CLASS = Type.getType(Class.class); + private static final Type TYPE_OBJECT = Type.getType(Object.class); + + private AsmProxyClassGenerator() + { + // prevent instantiation + } + + public static Class generateProxyClass(ClassLoader classLoader, + Class targetClass, + Class invocationHandlerClass, + String suffix, + String superAccessorMethodSuffix, + java.lang.reflect.Method[] redirectMethods, + java.lang.reflect.Method[] interceptionMethods) + { + String proxyName = targetClass.getCanonicalName() + suffix; + String classFileName = proxyName.replace('.', '/'); + + byte[] proxyBytes = generateProxyClassBytes(targetClass, invocationHandlerClass, + classFileName, superAccessorMethodSuffix, redirectMethods, interceptionMethods); + + Class proxyClass = (Class) loadClass(classLoader, proxyName, proxyBytes); + + return proxyClass; + } + + private static byte[] generateProxyClassBytes(Class targetClass, + Class invocationHandlerClass, + String proxyName, + String superAccessorMethodSuffix, + java.lang.reflect.Method[] redirectMethods, + java.lang.reflect.Method[] interceptionMethods) + { + Class superClass = targetClass; + String[] interfaces = new String[] { }; + + if (targetClass.isInterface()) + { + superClass = Object.class; + interfaces = new String[] { Type.getInternalName(targetClass) }; + } + + // add PartialBeanProxy as interface + interfaces = Arrays.copyOf(interfaces, interfaces.length + 1); + interfaces[interfaces.length - 1] = Type.getInternalName(PartialBeanProxy.class); + + Type superType = Type.getType(superClass); + Type proxyType = Type.getObjectType(proxyName); + Type invocationHandlerType = Type.getType(invocationHandlerClass); + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, proxyType.getInternalName(), null, + superType.getInternalName(), interfaces); + + // copy annotations + for (Annotation annotation : targetClass.getDeclaredAnnotations()) + { + cw.visitAnnotation(Type.getDescriptor(annotation.annotationType()), true).visitEnd(); + } + + defineInvocationHandlerField(cw, invocationHandlerType); + defineConstructor(cw, proxyType, superType); + definePartialBeanProxyMethods(cw, proxyType, invocationHandlerType); + + for (java.lang.reflect.Method method : redirectMethods) + { + defineMethod(cw, method, RedirectManualInvocationHandler.class); + } + + for (java.lang.reflect.Method method : interceptionMethods) + { + defineSuperAccessorMethod(cw, method, superType, superAccessorMethodSuffix); + defineMethod(cw, method, CallSuperManualInvocationHandler.class); + } + + return cw.toByteArray(); + } + + private static void defineInvocationHandlerField(ClassWriter cw, Type invocationHandlerType) + { + // generates + // private MyPartialBeanInvocationHandler __handler; + cw.visitField(Opcodes.ACC_PRIVATE, FIELDNAME_HANDLER, invocationHandlerType.getDescriptor(), null, null) + .visitEnd(); + } + + private static void defineConstructor(ClassWriter cw, Type proxyType, Type superType) + { + GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, + new Method("", Type.VOID_TYPE, new Type[]{ }), + null, + null, + cw); + + mg.visitCode(); + + // invoke super constructor + mg.loadThis(); + mg.invokeConstructor(superType, Method.getMethod("void ()")); + mg.returnValue(); + mg.endMethod(); + + mg.visitEnd(); + } + + private static void definePartialBeanProxyMethods(ClassWriter cw, Type proxyType, Type invocationHandlerType) + { + try + { + // implement #setRedirectInvocationHandler + Method asmMethod = Method.getMethod(PartialBeanProxy.class.getDeclaredMethod( + "setRedirectInvocationHandler", InvocationHandler.class)); + GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, asmMethod, null, null, cw); + + mg.visitCode(); + + mg.loadThis(); + mg.loadArg(0); + mg.checkCast(invocationHandlerType); + mg.putField(proxyType, FIELDNAME_HANDLER, invocationHandlerType); + mg.returnValue(); + + mg.visitMaxs(2, 1); + mg.visitEnd(); + + + // implement #getRedirectInvocationHandler + asmMethod = Method.getMethod(PartialBeanProxy.class.getDeclaredMethod("getRedirectInvocationHandler")); + mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, asmMethod, null, null, cw); + + mg.visitCode(); + + mg.loadThis(); + mg.getField(proxyType, FIELDNAME_HANDLER, invocationHandlerType); + mg.returnValue(); + + mg.visitMaxs(2, 1); + mg.visitEnd(); + } + catch (NoSuchMethodException e) + { + throw new IllegalStateException("Unable to implement " + PartialBeanProxy.class.getName(), e); + } + } + + private static void defineSuperAccessorMethod(ClassWriter cw, java.lang.reflect.Method method, Type superType, + String superAccessorMethodSuffix) + { + Method originalAsmMethod = Method.getMethod(method); + Method newAsmMethod = new Method(method.getName() + superAccessorMethodSuffix, + originalAsmMethod.getReturnType(), + originalAsmMethod.getArgumentTypes()); + GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, newAsmMethod, null, null, cw); + + mg.visitCode(); + + // call super method + mg.loadThis(); + mg.loadArgs(); + mg.visitMethodInsn(Opcodes.INVOKESPECIAL, + superType.getInternalName(), + method.getName(), + Type.getMethodDescriptor(method), + false); + mg.returnValue(); + + // finish the method + mg.endMethod(); + mg.visitMaxs(10, 10); + mg.visitEnd(); + } + + private static void defineMethod(ClassWriter cw, java.lang.reflect.Method method, + Class manualInvocationHandlerClass) + { + Type methodType = Type.getType(method); + Type[] exceptionTypes = getTypes(method.getExceptionTypes()); + + // push the method definition + int modifiers = (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED) & method.getModifiers(); + Method asmMethod = Method.getMethod(method); + GeneratorAdapter mg = new GeneratorAdapter(modifiers, asmMethod, null, exceptionTypes, cw); + + // copy annotations + for (Annotation annotation : method.getDeclaredAnnotations()) + { + mg.visitAnnotation(Type.getDescriptor(annotation.annotationType()), true).visitEnd(); + } + + mg.visitCode(); + + Label tryBlockStart = mg.mark(); + + mg.loadThis(); + loadCurrentMethod(mg, method, methodType); + loadArguments(mg, method, methodType); + + // invoke our ProxyInvocationHandler + mg.invokeStatic(Type.getType(manualInvocationHandlerClass), + Method.getMethod("Object staticInvoke(Object, java.lang.reflect.Method, Object[])")); + + // cast the result + mg.unbox(methodType.getReturnType()); + + // push return + mg.returnValue(); + + // build try catch + Label tryBlockEnd = mg.mark(); + boolean throwableCatched = false; + + // catch declared exceptions + if (exceptionTypes.length > 0) + { + Label rethrow = mg.mark(); + mg.visitVarInsn(Opcodes.ASTORE, 1); + mg.visitVarInsn(Opcodes.ALOAD, 1); + mg.throwException(); + + // catch declared exceptions and rethrow it... + for (Type exceptionType : exceptionTypes) + { + if (exceptionType.getClassName().equals(Throwable.class.getName())) + { + throwableCatched = true; + } + mg.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrow, exceptionType.getInternalName()); + } + } + + if (!throwableCatched) + { + // catch Throwable and wrap it with a UndeclaredThrowableException + Type uteType = Type.getType(UndeclaredThrowableException.class); + Label wrapAndRethrow = mg.mark(); + + mg.visitVarInsn(Opcodes.ASTORE, 1); + mg.newInstance(uteType); + mg.dup(); + mg.visitVarInsn(Opcodes.ALOAD, 1); + mg.invokeConstructor(uteType, + Method.getMethod("void (java.lang.Throwable)")); + mg.throwException(); + + mg.visitTryCatchBlock(tryBlockStart, tryBlockEnd, wrapAndRethrow, Type.getInternalName(Throwable.class)); + } + + // finish the method + mg.endMethod(); + mg.visitMaxs(10, 10); + mg.visitEnd(); + } + + /** + * Generates: + *
+     * Method method =
+     *      method.getDeclaringClass().getMethod("methodName", new Class[] { args... });
+     * 
+ * @param mg + * @param method + * @param methodType + */ + private static void loadCurrentMethod(GeneratorAdapter mg, java.lang.reflect.Method method, Type methodType) + { + mg.push(Type.getType(method.getDeclaringClass())); + mg.push(method.getName()); + + // create the Class[] + mg.push(methodType.getArgumentTypes().length); + mg.newArray(TYPE_CLASS); + + // push parameters into array + for (int i = 0; i < methodType.getArgumentTypes().length; i++) + { + // keep copy of array on stack + mg.dup(); + + // push index onto stack + mg.push(i); + mg.push(methodType.getArgumentTypes()[i]); + mg.arrayStore(TYPE_CLASS); + } + + // invoke getMethod() with the method name and the array of types + mg.invokeVirtual(TYPE_CLASS, Method.getMethod("java.lang.reflect.Method getDeclaredMethod(String, Class[])")); + } + + /** + * Defines a new Object[] and push all method argmuments into the array. + * + * @param mg + * @param method + * @param methodType + */ + private static void loadArguments(GeneratorAdapter mg, java.lang.reflect.Method method, Type methodType) + { + // create the Object[] + mg.push(methodType.getArgumentTypes().length); + mg.newArray(TYPE_OBJECT); + + // push parameters into array + for (int i = 0; i < methodType.getArgumentTypes().length; i++) + { + // keep copy of array on stack + mg.dup(); + + // push index onto stack + mg.push(i); + + mg.loadArg(i); + mg.valueOf(methodType.getArgumentTypes()[i]); + mg.arrayStore(TYPE_OBJECT); + } + } + + private static Type[] getTypes(Class... src) + { + Type[] result = new Type[src.length]; + for (int i = 0; i < result.length; i++) + { + result[i] = Type.getType(src[i]); + } + return result; + } + + /** + * Adapted from http://asm.ow2.org/doc/faq.html#Q5 + * + * @param b + * + * @return Class + */ + private static Class loadClass(ClassLoader loader, String className, byte[] b) + { + // override classDefine (as it is protected) and define the class. + try + { + java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod( + "defineClass", String.class, byte[].class, int.class, int.class); + + // protected method invocation + boolean accessible = method.isAccessible(); + if (!accessible) + { + method.setAccessible(true); + } + try + { + return (Class) method.invoke(loader, className, b, Integer.valueOf(0), Integer.valueOf(b.length)); + } + finally + { + if (!accessible) + { + method.setAccessible(false); + } + } + } + catch (Exception e) + { + throw e instanceof RuntimeException ? ((RuntimeException) e) : new RuntimeException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/CallSuperManualInvocationHandler.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/CallSuperManualInvocationHandler.java b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/CallSuperManualInvocationHandler.java new file mode 100644 index 0000000..86791d7 --- /dev/null +++ b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/CallSuperManualInvocationHandler.java @@ -0,0 +1,41 @@ +/* + * 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.deltaspike.partialbean.impl.proxy; + +import java.lang.reflect.Method; +import javax.enterprise.inject.Typed; +import org.apache.deltaspike.partialbean.impl.interception.AbstractManualInvocationHandler; + +@Typed +public class CallSuperManualInvocationHandler extends AbstractManualInvocationHandler +{ + private static final CallSuperManualInvocationHandler INSTANCE = new CallSuperManualInvocationHandler(); + + public static Object staticInvoke(Object proxy, Method method, Object[] parameters) throws Throwable + { + return INSTANCE.invoke(proxy, method, parameters); + } + + @Override + protected Object proceedOriginal(Object proxy, Method method, Object[] parameters) throws Throwable + { + Method superAccessorMethod = PartialBeanProxyFactory.getSuperAccessorMethod(proxy, method); + return superAccessorMethod.invoke(proxy, parameters); + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/PartialBeanProxyFactory.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/PartialBeanProxyFactory.java b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/PartialBeanProxyFactory.java index f19eeca..e965145 100644 --- a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/PartialBeanProxyFactory.java +++ b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/PartialBeanProxyFactory.java @@ -32,6 +32,7 @@ import org.apache.deltaspike.core.util.ClassUtils; public abstract class PartialBeanProxyFactory { private static final String CLASSNAME_SUFFIX = "$$DSPartialBeanProxy"; + private static final String SUPER_ACCESSOR_METHOD_SUFFIX = "$super"; private PartialBeanProxyFactory() { @@ -64,6 +65,7 @@ public abstract class PartialBeanProxyFactory targetClass, invocationHandlerClass, CLASSNAME_SUFFIX, + SUPER_ACCESSOR_METHOD_SUFFIX, redirectMethods.toArray(new Method[redirectMethods.size()]), interceptionMethods.toArray(new Method[interceptionMethods.size()])); } @@ -76,6 +78,18 @@ public abstract class PartialBeanProxyFactory return clazz.getCanonicalName() + CLASSNAME_SUFFIX; } + private static String constructSuperAccessorMethodName(Method method) + { + return method.getName() + SUPER_ACCESSOR_METHOD_SUFFIX; + } + + public static Method getSuperAccessorMethod(Object proxy, Method method) throws NoSuchMethodException + { + return proxy.getClass().getMethod( + constructSuperAccessorMethodName(method), + method.getParameterTypes()); + } + /** * Checks if the given class is DS proxy class. * @@ -215,4 +229,4 @@ public abstract class PartialBeanProxyFactory && a.getReturnType().equals(b.getReturnType()) && Arrays.equals(a.getParameterTypes(), b.getParameterTypes()); } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/RedirectManualInvocationHandler.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/RedirectManualInvocationHandler.java b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/RedirectManualInvocationHandler.java new file mode 100644 index 0000000..c8b553b --- /dev/null +++ b/deltaspike/modules/partial-bean/impl/src/main/java/org/apache/deltaspike/partialbean/impl/proxy/RedirectManualInvocationHandler.java @@ -0,0 +1,42 @@ +/* + * 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.deltaspike.partialbean.impl.proxy; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import javax.enterprise.inject.Typed; +import org.apache.deltaspike.partialbean.impl.interception.AbstractManualInvocationHandler; + +@Typed +public class RedirectManualInvocationHandler extends AbstractManualInvocationHandler +{ + private static final RedirectManualInvocationHandler INSTANCE = new RedirectManualInvocationHandler(); + + public static Object staticInvoke(Object proxy, Method method, Object[] parameters) throws Throwable + { + return INSTANCE.invoke(proxy, method, parameters); + } + + @Override + protected Object proceedOriginal(Object proxy, Method method, Object[] parameters) throws Throwable + { + InvocationHandler redirectInvocationHandler = ((PartialBeanProxy) proxy).getRedirectInvocationHandler(); + return redirectInvocationHandler.invoke(proxy, method, parameters); + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc004/ScopedPartialBeanTest.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc004/ScopedPartialBeanTest.java b/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc004/ScopedPartialBeanTest.java index 193878c..6286f66 100644 --- a/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc004/ScopedPartialBeanTest.java +++ b/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc004/ScopedPartialBeanTest.java @@ -56,14 +56,16 @@ public class ScopedPartialBeanTest @Test public void testPartialBeanWithApplicationScope() throws Exception { - String result = BeanProvider.getContextualReference(ApplicationScopedPartialBean.class).getResult(); + ApplicationScopedPartialBean bean = BeanProvider.getContextualReference(ApplicationScopedPartialBean.class); + + String result = bean.getResult(); Assert.assertEquals("partial-test-false", result); - int count = BeanProvider.getContextualReference(ApplicationScopedPartialBean.class).getManualResult(); + int count = bean.getManualResult(); Assert.assertEquals(0, count); - count = BeanProvider.getContextualReference(ApplicationScopedPartialBean.class).getManualResult(); + count = bean.getManualResult(); Assert.assertEquals(1, count); } http://git-wip-us.apache.org/repos/asf/deltaspike/blob/72c9c81f/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc007/PartialBean.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc007/PartialBean.java b/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc007/PartialBean.java index b6a563b..8708683 100644 --- a/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc007/PartialBean.java +++ b/deltaspike/modules/partial-bean/impl/src/test/java/org/apache/deltaspike/test/core/api/partialbean/uc007/PartialBean.java @@ -33,6 +33,6 @@ public abstract class PartialBean @CustomInterceptor public void doSomething() { - + String a = "test"; } } \ No newline at end of file