| /** |
| * 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.cxf.common.util; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.annotation.ElementType; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.lang.annotation.Target; |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
| import java.util.Iterator; |
| |
| /** |
| * |
| */ |
| public class ReflectionInvokationHandler implements InvocationHandler { |
| private Object target; |
| |
| public ReflectionInvokationHandler(Object obj) { |
| target = obj; |
| } |
| |
| public Object getTarget() { |
| return target; |
| } |
| |
| /** {@inheritDoc}*/ |
| public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
| WrapReturn wr = method.getAnnotation(WrapReturn.class); |
| final Class<?> targetClass = target.getClass(); |
| final Class<?>[] parameterTypes = getParameterTypes(method, args); |
| try { |
| Method m; |
| try { |
| m = targetClass.getMethod(method.getName(), parameterTypes); |
| } catch (NoSuchMethodException nsme) { |
| |
| boolean[] optionals = new boolean[method.getParameterTypes().length]; |
| int i = 0; |
| int optionalNumber = 0; |
| for (final Annotation[] a : method.getParameterAnnotations()) { |
| optionals[i] = false; |
| for (final Annotation potential : a) { |
| if (Optional.class.equals(potential.annotationType())) { |
| optionals[i] = true; |
| optionalNumber++; |
| break; |
| } |
| } |
| i++; |
| } |
| |
| Class<?>[] newParams = new Class<?>[args.length - optionalNumber]; |
| Object[] newArgs = new Object[args.length - optionalNumber]; |
| int argI = 0; |
| for (int j = 0; j < parameterTypes.length; j++) { |
| if (optionals[j]) { |
| continue; |
| } |
| newArgs[argI] = args[j]; |
| newParams[argI] = parameterTypes[j]; |
| argI++; |
| } |
| m = targetClass.getMethod(method.getName(), newParams); |
| args = newArgs; |
| } |
| ReflectionUtil.setAccessible(m); |
| return wrapReturn(wr, m.invoke(target, args)); |
| } catch (InvocationTargetException e) { |
| throw e.getCause(); |
| } catch (NoSuchMethodException e) { |
| for (Method m2 : targetClass.getMethods()) { |
| if (m2.getName().equals(method.getName()) |
| && m2.getParameterTypes().length == method.getParameterTypes().length) { |
| boolean found = true; |
| for (int x = 0; x < m2.getParameterTypes().length; x++) { |
| if (args[x] != null |
| && !m2.getParameterTypes()[x].isInstance(args[x])) { |
| found = false; |
| } |
| } |
| if (found) { |
| ReflectionUtil.setAccessible(m2); |
| return wrapReturn(wr, m2.invoke(target, args)); |
| } |
| } |
| } |
| throw e; |
| } |
| } |
| private Class<?>[] getParameterTypes(Method method, Object[] args) { |
| Class<?>[] types = method.getParameterTypes(); |
| final Annotation[][] parAnnotations = method.getParameterAnnotations(); |
| for (int x = 0; x < types.length; x++) { |
| UnwrapParam p = getUnwrapParam(parAnnotations[x]); |
| if (p != null) { |
| String s = p.methodName(); |
| String tn = p.typeMethodName(); |
| try { |
| Method m = args[x].getClass().getMethod(s); |
| if ("#default".equals(tn)) { |
| types[x] = m.getReturnType(); |
| } else { |
| Method m2 = args[x].getClass().getMethod(tn); |
| types[x] = (Class<?>)ReflectionUtil.setAccessible(m2).invoke(args[x]); |
| } |
| args[x] = ReflectionUtil.setAccessible(m).invoke(args[x]); |
| } catch (Exception ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| } |
| return types; |
| } |
| |
| private UnwrapParam getUnwrapParam(Annotation[] annotations) { |
| for (Annotation a : annotations) { |
| if (a instanceof UnwrapParam) { |
| return (UnwrapParam)a; |
| } |
| } |
| return null; |
| } |
| |
| private static Object wrapReturn(WrapReturn wr, Object t) { |
| if (wr == null || t == null) { |
| return t; |
| } |
| if (wr.iterator()) { |
| return new WrapperIterator(wr.value(), (Iterator<?>)t); |
| } |
| return createProxyWrapper(t, wr.value()); |
| } |
| |
| public static <T> T createProxyWrapper(Object target, Class<T> inf) { |
| InvocationHandler h = new ReflectionInvokationHandler(target); |
| return inf.cast(Proxy.newProxyInstance(inf.getClassLoader(), new Class<?>[] {inf}, h)); |
| } |
| |
| @Target(ElementType.PARAMETER) |
| @Retention(RetentionPolicy.RUNTIME) |
| public @interface Optional { |
| } |
| |
| @Target(ElementType.METHOD) |
| @Retention(RetentionPolicy.RUNTIME) |
| public @interface WrapReturn { |
| Class<?> value(); |
| boolean iterator() default false; |
| } |
| |
| @Target(ElementType.PARAMETER) |
| @Retention(RetentionPolicy.RUNTIME) |
| public @interface UnwrapParam { |
| String methodName() default "getValue"; |
| String typeMethodName() default "#default"; |
| } |
| |
| private static class WrapperIterator implements Iterator<Object> { |
| Class<?> cls; |
| Iterator<?> internal; |
| WrapperIterator(Class<?> c, Iterator<?> it) { |
| internal = it; |
| cls = c; |
| } |
| public boolean hasNext() { |
| return internal.hasNext(); |
| } |
| public Object next() { |
| Object obj = internal.next(); |
| return createProxyWrapper(obj, cls); |
| } |
| |
| @Override |
| public void remove() { |
| internal.remove(); |
| } |
| } |
| } |