Add Mycilla code to odlguice
[odlguice.git] / inject / inject-guice-extensions / injection / src / main / java / org / opendaylight / odlguice / inject / guice / extensions / injection / Reflect.java
diff --git a/inject/inject-guice-extensions/injection/src/main/java/org/opendaylight/odlguice/inject/guice/extensions/injection/Reflect.java b/inject/inject-guice-extensions/injection/src/main/java/org/opendaylight/odlguice/inject/guice/extensions/injection/Reflect.java
new file mode 100755 (executable)
index 0000000..cb8a3a6
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2010 Mycila (mathieu.carbou@gmail.com)
+ *
+ * Licensed 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.opendaylight.odlguice.inject.guice.extensions.injection;
+
+import static com.google.common.collect.Iterables.concat;
+import static com.google.common.collect.Iterables.transform;
+import static java.util.Arrays.asList;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import com.google.inject.internal.Annotations;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.gaul.modernizer_maven_annotations.SuppressModernizer;
+
+/**
+ * This code originated in https://github.com/mycila/guice and was forked into
+ * OpenDaylight.
+ * @author Mathieu Carbou (mathieu.carbou@gmail.com) date 2013-07-20
+ */
+@SuppressModernizer
+public final class Reflect {
+
+    private Reflect() {
+    }
+
+    private static final Function<Signature, Method> TO_METHOD = new Function<Signature, Method>() {
+        @Override
+        public Method apply(Signature from) {
+            return from.method;
+        }
+    };
+
+    private static final List<Signature> OBJECT_METHODS = Lists
+            .newArrayList(transform(asList(Object.class.getDeclaredMethods()), new Function<Method, Signature>() {
+                @Override
+                public Signature apply(Method from) {
+                    return new Signature(from);
+                }
+            }));
+
+    private static Key<?> buildKey(TypeLiteral<?> type, Annotation[] annotations) {
+        for (Annotation annotation : annotations) {
+            if (Annotations.isBindingAnnotation(annotation.annotationType())) {
+                return Key.get(type, annotation);
+            }
+        }
+        return Key.get(type);
+    }
+
+    private static final LoadingCache<AnnotatedElement, Set<Class<? extends Annotation>>> ANNOT_CACHE = CacheBuilder
+            .newBuilder().weakKeys().softValues()
+            .build(new CacheLoader<AnnotatedElement, Set<Class<? extends Annotation>>>() {
+                @Override
+                public Set<Class<? extends Annotation>> load(AnnotatedElement ex) throws Exception {
+                    Annotation[] annotations = ex.getDeclaredAnnotations();
+                    Set<Class<? extends Annotation>> annotationTypes = new HashSet<Class<? extends Annotation>>(
+                            annotations.length);
+                    for (Annotation annotation : annotations) {
+                        annotationTypes.add(annotation.annotationType());
+                    }
+                    return annotationTypes;
+                }
+            });
+
+    private static final LoadingCache<Class<?>, List<Signature>> METHODS = CacheBuilder.newBuilder().weakKeys()
+            .softValues().build(new CacheLoader<Class<?>, List<Signature>>() {
+                @Override
+                public List<Signature> load(Class<?> clazz) throws Exception {
+                    List<Signature> sup;
+                    Class<?> sc = clazz.getSuperclass();
+                    if (sc == null) {
+                        sup = Collections.emptyList();
+                    } else if (sc == Object.class) {
+                        sup = OBJECT_METHODS;
+                    } else {
+                        sup = METHODS.get(sc);
+                    }
+                    Method[] methods = clazz.isInterface() ? clazz.getMethods() : clazz.getDeclaredMethods();
+                    final List<Signature> thisMethods = new ArrayList<Signature>(methods.length);
+                    for (Method method : methods) {
+                        if (!(method.isSynthetic() || method.isBridge())) {
+                            thisMethods.add(new Signature(method));
+                        }
+                    }
+                    return Lists.newLinkedList(concat(thisMethods, Iterables.filter(sup, new Predicate<Signature>() {
+                        @Override
+                        public boolean apply(Signature input) {
+                            int pos = thisMethods.indexOf(input);
+                            if (pos == -1) {
+                                return true;
+                            }
+                            Signature override = thisMethods.get(pos);
+                            return !overrides(override.method, input.method);
+                        }
+                    })));
+                }
+            });
+
+    public static boolean isAnnotationPresent(AnnotatedElement annotatedElement,
+            Class<? extends Annotation> annotationType) {
+        try {
+            return ANNOT_CACHE.get(annotatedElement).contains(annotationType);
+        } catch (ExecutionException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
+
+    public static List<Key<?>> getParameterKeys(TypeLiteral<?> type, Method method) {
+        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+        List<TypeLiteral<?>> parameterTypes = type.getParameterTypes(method);
+        List<Key<?>> keys = new ArrayList<Key<?>>(parameterTypes.size());
+        for (int i = 0; i < parameterTypes.size(); i++) {
+            keys.add(buildKey(parameterTypes.get(i), parameterAnnotations[i]));
+        }
+        return keys;
+    }
+
+    public static Iterable<MethodInvoker> findAllAnnotatedInvokables(Class<?> type, Class<? extends Annotation> annot) {
+        return transform(findAllAnnotatedMethods(type, annot), new Function<Method, MethodInvoker>() {
+            @Override
+            public MethodInvoker apply(Method method) {
+                return MethodInvoker.on(method);
+            }
+        });
+    }
+
+    public static Iterable<Method> findAllAnnotatedMethods(Class<?> type, Class<? extends Annotation> annot) {
+        return Iterables.filter(findAllMethods(type), annotatedBy(annot));
+    }
+
+    public static Iterable<Method> findAllMethods(Class<?> type) {
+        try {
+            return transform(METHODS.get(type), TO_METHOD);
+        } catch (ExecutionException e) {
+            throw MycilaGuiceException.toRuntime(e);
+        }
+    }
+
+    public static Iterable<Field> findAllAnnotatedFields(Class<?> type, Class<? extends Annotation> annot) {
+        return Iterables.filter(findAllFields(type), annotatedBy(annot));
+    }
+
+    public static Iterable<Field> findAllFields(Class<?> type) {
+        return type == null || type == Object.class ? new LinkedList<Field>()
+                : concat(Lists.newArrayList(type.getDeclaredFields()), findAllFields(type.getSuperclass()));
+    }
+
+    public static Class<?> getTargetClass(Class<?> proxy) {
+        if (proxy.getName().contains("$$")) {
+            do {
+                proxy = proxy.getSuperclass();
+            } while (proxy.getName().contains("$$"));
+            return proxy;
+        }
+        return proxy;
+    }
+
+    public static Class<?> getTargetClass(Object instance) {
+        return getTargetClass(instance.getClass());
+    }
+
+    public static <T extends AnnotatedElement> Predicate<T> annotatedBy(
+            final Class<? extends Annotation> annotationType) {
+        return new Predicate<T>() {
+            @Override
+            public boolean apply(T element) {
+                return Reflect.isAnnotationPresent(element, annotationType);
+            }
+        };
+    }
+
+    public static Predicate<Method> withSignature(final String methodName, final Class<?>... classes) {
+        return new Predicate<Method>() {
+            @Override
+            public boolean apply(Method member) {
+                if (!member.getName().equals(methodName)) {
+                    return false;
+                }
+                Class<?>[] thisParams = member.getParameterTypes();
+                if (thisParams.length != classes.length) {
+                    return false;
+                }
+                int cls = 0;
+                for (Class<?> thisParam : thisParams) {
+                    if (thisParam != classes[cls++]) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        };
+    }
+
+    /**
+     * Returns true if a overrides b. Assumes signatures of a and b are the same and
+     * a's declaring class is a subclass of b's declaring class.
+     */
+    public static boolean overrides(Method methodA, Method methodB) {
+        // See JLS section 8.4.8.1
+        int modifiers = methodB.getModifiers();
+        if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
+            return true;
+        }
+        if (Modifier.isPrivate(modifiers)) {
+            return false;
+        }
+        // b must be package-private
+        return methodA.getDeclaringClass().getPackage().equals(methodB.getDeclaringClass().getPackage());
+    }
+
+    private static final class Signature {
+        public final Class[] parameterTypes;
+        private final int hash;
+        public final Method method;
+
+        Signature(Method method) {
+            this.method = method;
+            this.parameterTypes = method.getParameterTypes();
+            int methodHash = method.hashCode();
+            methodHash = methodHash * 31 + parameterTypes.length;
+            for (Class parameterType : parameterTypes) {
+                methodHash = methodHash * 31 + parameterType.hashCode();
+            }
+            this.hash = methodHash;
+        }
+
+        @Override
+        public int hashCode() {
+            return this.hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Signature)) {
+                return false;
+            }
+            Signature other = (Signature) obj;
+            if (!method.getName().equals(other.method.getName())) {
+                return false;
+            }
+            if (parameterTypes.length != other.parameterTypes.length) {
+                return false;
+            }
+            for (int i = 0; i < parameterTypes.length; i++) {
+                if (parameterTypes[i] != other.parameterTypes[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+}
\ No newline at end of file