diff --git a/src/main/java/org/jboss/ejb/client/EJBProxyInformation.java b/src/main/java/org/jboss/ejb/client/EJBProxyInformation.java index dfa299e9c..ac05bf46c 100644 --- a/src/main/java/org/jboss/ejb/client/EJBProxyInformation.java +++ b/src/main/java/org/jboss/ejb/client/EJBProxyInformation.java @@ -18,19 +18,21 @@ package org.jboss.ejb.client; -import static java.security.AccessController.doPrivileged; - +import java.lang.reflect.Array; import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; +import java.lang.reflect.UndeclaredThrowableException; import java.security.PrivilegedAction; import java.util.Collection; import java.util.HashMap; import java.util.IdentityHashMap; +import java.util.Map; import java.util.concurrent.Future; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.Deflater; import javax.ejb.EJBHome; @@ -43,6 +45,8 @@ import org.jboss.ejb.client.annotation.CompressionHint; import org.jboss.ejb.client.annotation.Idempotent; +import static java.security.AccessController.doPrivileged; + /** * Cached information about an EJB proxy. * @@ -96,7 +100,21 @@ private

EJBProxyInformation

doCompute(final Class

type) { final boolean classIdempotent = ENABLE_SCANNING && type.getAnnotation(Idempotent.class) != null; final boolean classAsync = ENABLE_SCANNING && type.getAnnotation(ClientAsynchronous.class) != null; - for (Method method : type.getMethods()) { + + final Class proxyClass = Proxy.getProxyClass(type.getClassLoader(), type).asSubclass(type); + final Constructor constructor; + try { + constructor = proxyClass.getConstructor(JUST_INV_HANDLER); + } catch (NoSuchMethodException e) { + throw new NoSuchMethodError("No valid constructor found on proxy class"); + } + + + final ProxyClassMethodResolver

resolver = new ProxyClassMethodResolver<>(proxyClass, constructor); + + for (Method m : type.getMethods()) { + final Method method = resolver.resolve(m); + final boolean alwaysAsync = method.getReturnType() == Future.class; final boolean idempotent = classIdempotent || ENABLE_SCANNING && method.getAnnotation(Idempotent.class) != null; final boolean clientAsync = alwaysAsync || classAsync || ENABLE_SCANNING && method.getAnnotation(ClientAsynchronous.class) != null; @@ -137,9 +155,11 @@ private

EJBProxyInformation

doCompute(final Class

type) { fallbackMap.put(method, proxyMethodInfo); methodLocatorMap.put(methodLocator, proxyMethodInfo); } - for (Method method : Object.class.getMethods()) { - final String methodName = method.getName(); + for (Method m : Object.class.getMethods()) { + final String methodName = m.getName(); if (!"hashCode".equals(methodName) && !"toString".equals(methodName) && !"equals".equals(methodName)) continue; + + final Method method = resolver.resolve(m); final boolean alwaysAsync = false; final boolean idempotent = classIdempotent; final boolean clientAsync = alwaysAsync || classAsync; @@ -167,13 +187,6 @@ private

EJBProxyInformation

doCompute(final Class

type) { fallbackMap.put(method, proxyMethodInfo); methodLocatorMap.put(methodLocator, proxyMethodInfo); } - final Class proxyClass = Proxy.getProxyClass(type.getClassLoader(), type).asSubclass(type); - final Constructor constructor; - try { - constructor = proxyClass.getConstructor(JUST_INV_HANDLER); - } catch (NoSuchMethodException e) { - throw new NoSuchMethodError("No valid constructor found on proxy class"); - } return new EJBProxyInformation<>(proxyClass, constructor, methodInfoMap, fallbackMap, methodLocatorMap, classCompressionLevel, classIdempotent, classAsync, classInterceptors); } @@ -320,6 +333,59 @@ Collection getMethods() { return methodInfoMap.values(); } + static final class ProxyClassMethodResolver

implements InvocationHandler { + + private static final Object[] NO_PARAM = new Object[0]; + private static final Map, Object> DEFAULT_VALUES = Stream + .of(boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class) + .collect(Collectors.toMap(clazz -> (Class) clazz, clazz -> Array.get(Array.newInstance(clazz, 1), 0))); + + + private P proxyInstance; + private Method resolvedProxyMethod; + + public ProxyClassMethodResolver(Class proxyClass, Constructor constructor) { + try { + proxyInstance = constructor.newInstance(this); + } catch (InstantiationException e) { + throw new InstantiationError(e.getMessage()); + } catch (IllegalAccessException e) { + throw new IllegalAccessError(e.getMessage()); + } catch (InvocationTargetException e) { + throw new UndeclaredThrowableException(e.getCause()); + } + } + + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + resolvedProxyMethod = method; + return DEFAULT_VALUES.get(method.getReturnType()); + } + + public Method resolve(Method method) { + Object[] parameters = NO_PARAM; + if(method.getParameterCount() > 0) { + final Class[] parameterTypes = method.getParameterTypes(); + parameters = new Object[parameterTypes.length]; + + for(int i = 0; i < parameters.length; ++i) { + parameters[i] = DEFAULT_VALUES.get(parameterTypes[i]); + } + } + + try { + resolvedProxyMethod = null; + method.invoke(proxyInstance, parameters); + return resolvedProxyMethod; + } catch (IllegalAccessException e) { + throw new IllegalAccessError(e.getMessage()); + } catch (InvocationTargetException e) { + throw new UndeclaredThrowableException(e.getCause()); + } + } + } + static final class ProxyMethodInfo { enum CompressionHint { @@ -405,4 +471,4 @@ boolean isSynchronous() { return returnType != void.class && returnType != Future.class; } } -} +} \ No newline at end of file