All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.deltaspike.core.util.Annotateds Maven / Gradle / Ivy

/*
 * 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.core.util;

import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.AnnotatedCallable;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.AnnotatedType;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 

* Utilities for working with {@link Annotated}s. *

*

*

* Includes utilities to check the equality of and create unique id's for * Annotated instances. *

*/ public final class Annotateds { private static final char SEPARATOR = ';'; private Annotateds() { // this is a utility class with statics only } /** * Does the first stage of comparing AnnoatedCallables, however it cannot * compare the method parameters */ private static class AnnotatedCallableComparator implements Comparator>, Serializable { public int compare(AnnotatedCallable arg0, AnnotatedCallable arg1) { // compare the names first int result = (arg0.getJavaMember().getName().compareTo(arg1.getJavaMember().getName())); if (result != 0) { return result; } result = arg0.getJavaMember().getDeclaringClass().getName().compareTo(arg1.getJavaMember() .getDeclaringClass().getName()); if (result != 0) { return result; } result = arg0.getParameters().size() - arg1.getParameters().size(); return result; } } private static class AnnotatedMethodComparator implements Comparator>, Serializable { private AnnotatedCallableComparator callableComparator = new AnnotatedCallableComparator(); public static Comparator> instance() { return new AnnotatedMethodComparator(); } public int compare(AnnotatedMethod arg0, AnnotatedMethod arg1) { int result = callableComparator.compare(arg0, arg1); if (result != 0) { return result; } for (int i = 0; i < arg0.getJavaMember().getParameterTypes().length; ++i) { Class p0 = arg0.getJavaMember().getParameterTypes()[i]; Class p1 = arg1.getJavaMember().getParameterTypes()[i]; result = p0.getName().compareTo(p1.getName()); if (result != 0) { return result; } } return 0; } } private static class AnnotatedConstructorComparator implements Comparator>, Serializable { private AnnotatedCallableComparator callableComparator = new AnnotatedCallableComparator(); public static Comparator> instance() { return new AnnotatedConstructorComparator(); } public int compare(AnnotatedConstructor arg0, AnnotatedConstructor arg1) { int result = callableComparator.compare(arg0, arg1); if (result != 0) { return result; } for (int i = 0; i < arg0.getJavaMember().getParameterTypes().length; ++i) { Class p0 = arg0.getJavaMember().getParameterTypes()[i]; Class p1 = arg1.getJavaMember().getParameterTypes()[i]; result = p0.getName().compareTo(p1.getName()); if (result != 0) { return result; } } return 0; } } private static class AnnotatedFieldComparator implements Comparator>, Serializable { public static Comparator> instance() { return new AnnotatedFieldComparator(); } public int compare(AnnotatedField arg0, AnnotatedField arg1) { if (arg0.getJavaMember().getName().equals(arg1.getJavaMember().getName())) { return arg0.getJavaMember().getDeclaringClass().getName().compareTo(arg1.getJavaMember() .getDeclaringClass().getName()); } return arg0.getJavaMember().getName().compareTo(arg1.getJavaMember().getName()); } } private static class AnnotationComparator implements Comparator, Serializable { public static final Comparator INSTANCE = new AnnotationComparator(); public int compare(Annotation arg0, Annotation arg1) { return arg0.annotationType().getName().compareTo(arg1.annotationType().getName()); } } private static class MethodComparator implements Comparator { public static final Comparator INSTANCE = new MethodComparator(); public int compare(Method arg0, Method arg1) { return arg0.getName().compareTo(arg1.getName()); } } /** * Generates a deterministic signature for an {@link AnnotatedType}. Two * AnnotatedTypes that have the same annotations and underlying * type will generate the same signature. *

* This can be used to create a unique bean id for a passivation capable bean * that is added directly through the SPI. * * @param annotatedType The type to generate a signature for * @return A string representation of the annotated type */ public static String createTypeId(AnnotatedType annotatedType) { return createTypeId(annotatedType.getJavaClass(), annotatedType.getAnnotations(), annotatedType.getMethods(), annotatedType.getFields(), annotatedType.getConstructors()); } /** * Generates a unique signature for a concrete class. Annotations are not * read directly from the class, but are read from the * annotations, methods, fields and * constructors arguments * * @param clazz The java class type * @param annotations Annotations present on the java class * @param methods The AnnotatedMethods to include in the signature * @param fields The AnnotatedFields to include in the signature * @param constructors The AnnotatedConstructors to include in the signature * @return A string representation of the type */ public static String createTypeId(Class clazz, Collection annotations, Collection> methods, Collection> fields, Collection> constructors) { StringBuilder builder = new StringBuilder(); builder.append(clazz.getName()); builder.append(createAnnotationCollectionId(annotations)); builder.append("{"); // now deal with the fields List> sortedFields = new ArrayList>(); sortedFields.addAll(fields); Collections.sort(sortedFields, AnnotatedFieldComparator.instance()); for (AnnotatedField field : sortedFields) { if (!field.getAnnotations().isEmpty()) { builder.append(createFieldId(field)); builder.append(SEPARATOR); } } // methods List> sortedMethods = new ArrayList>(); sortedMethods.addAll(methods); Collections.sort(sortedMethods, AnnotatedMethodComparator.instance()); for (AnnotatedMethod method : sortedMethods) { if (!method.getAnnotations().isEmpty() || hasMethodParameters(method)) { builder.append(createCallableId(method)); builder.append(SEPARATOR); } } // constructors List> sortedConstructors = new ArrayList>(); sortedConstructors.addAll(constructors); Collections.sort(sortedConstructors, AnnotatedConstructorComparator.instance()); for (AnnotatedConstructor constructor : sortedConstructors) { if (!constructor.getAnnotations().isEmpty() || hasMethodParameters(constructor)) { builder.append(createCallableId(constructor)); builder.append(SEPARATOR); } } builder.append("}"); return builder.toString(); } /** * Generates a deterministic signature for an {@link AnnotatedField}. Two * AnnotatedFields that have the same annotations and * underlying field will generate the same signature. */ public static String createFieldId(AnnotatedField field) { return createFieldId(field.getJavaMember(), field.getAnnotations()); } /** * Creates a deterministic signature for a {@link Field}. * * @param field The field to generate the signature for * @param annotations The annotations to include in the signature */ public static String createFieldId(Field field, Collection annotations) { StringBuilder builder = new StringBuilder(); builder.append(field.getDeclaringClass().getName()); builder.append('.'); builder.append(field.getName()); builder.append(createAnnotationCollectionId(annotations)); return builder.toString(); } /** * Generates a deterministic signature for an {@link AnnotatedCallable}. Two * AnnotatedCallables that have the same annotations and * underlying callable will generate the same signature. */ public static String createCallableId(AnnotatedCallable method) { StringBuilder builder = new StringBuilder(); builder.append(method.getJavaMember().getDeclaringClass().getName()); builder.append('.'); builder.append(method.getJavaMember().getName()); builder.append(createAnnotationCollectionId(method.getAnnotations())); builder.append(createParameterListId(method.getParameters())); return builder.toString(); } /** * Creates a deterministic signature for a {@link Method}. * * @param method The method to generate the signature for * @param annotations The annotations to include in the signature * @param parameters The {@link AnnotatedParameter}s to include in the * signature */ public static String createMethodId(Method method, Set annotations, List> parameters) { StringBuilder builder = new StringBuilder(); builder.append(method.getDeclaringClass().getName()); builder.append('.'); builder.append(method.getName()); builder.append(createAnnotationCollectionId(annotations)); builder.append(createParameterListId(parameters)); return builder.toString(); } /** * Creates a deterministic signature for a {@link Constructor}. * * @param constructor The constructor to generate the signature for * @param annotations The annotations to include in the signature * @param parameters The {@link AnnotatedParameter}s to include in the * signature */ public static String createConstructorId(Constructor constructor, Set annotations, List> parameters) { StringBuilder builder = new StringBuilder(); builder.append(constructor.getDeclaringClass().getName()); builder.append('.'); builder.append(constructor.getName()); builder.append(createAnnotationCollectionId(annotations)); builder.append(createParameterListId(parameters)); return builder.toString(); } /** * Generates a unique string representation of a list of * {@link AnnotatedParameter}s. */ public static String createParameterListId(List> parameters) { StringBuilder builder = new StringBuilder(); builder.append("("); for (int i = 0; i < parameters.size(); ++i) { AnnotatedParameter ap = parameters.get(i); builder.append(createParameterId(ap)); if (i + 1 != parameters.size()) { builder.append(','); } } builder.append(")"); return builder.toString(); } /** * Creates a string representation of an {@link AnnotatedParameter}. */ public static String createParameterId(AnnotatedParameter annotatedParameter) { return createParameterId(annotatedParameter.getBaseType(), annotatedParameter.getAnnotations()); } /** * Creates a string representation of a given type and set of annotations. */ public static String createParameterId(Type type, Set annotations) { StringBuilder builder = new StringBuilder(); if (type instanceof Class) { Class c = (Class) type; builder.append(c.getName()); } else { builder.append(type.toString()); } builder.append(createAnnotationCollectionId(annotations)); return builder.toString(); } /** *

* Compares {@link AnnotatedField}s for equality. *

*

* Two {@link AnnotatedField}s are considered equal if they have the same * underlying field and annotations. *

*/ public static boolean compareAnnotatedField(AnnotatedField f1, AnnotatedField f2) { if (!f1.getJavaMember().equals(f2.getJavaMember())) { return false; } return compareAnnotated(f1, f2); } /** *

* Compare {@link AnnotatedCallable}s for equality. *

*

*

* Two {@link AnnotatedCallable}s are considered equal if they have the same * underlying callable and annotations. *

*/ public static boolean compareAnnotatedCallable(AnnotatedCallable m1, AnnotatedCallable m2) { if (!m1.getJavaMember().equals(m2.getJavaMember())) { return false; } if (!compareAnnotated(m1, m2)) { return false; } return compareAnnotatedParameters(m1.getParameters(), m2.getParameters()); } /** *

* Compares two {@link AnnotatedType}s for equality. *

*

*

* Two {@link AnnotatedType}s are considered equal if they have the same * underlying type and annotations, and all members have the same * annotations. *

*/ public static boolean compareAnnotatedTypes(AnnotatedType t1, AnnotatedType t2) { if (!t1.getJavaClass().equals(t2.getJavaClass())) { return false; } if (!compareAnnotated(t1, t2)) { return false; } if (t1.getFields().size() != t2.getFields().size()) { return false; } Map> fields = new HashMap>(); for (AnnotatedField f : t2.getFields()) { fields.put(f.getJavaMember(), f); } for (AnnotatedField f : t1.getFields()) { if (fields.containsKey(f.getJavaMember())) { if (!compareAnnotatedField(f, fields.get(f.getJavaMember()))) { return false; } } else { return false; } } if (t1.getMethods().size() != t2.getMethods().size()) { return false; } Map> methods = new HashMap>(); for (AnnotatedMethod f : t2.getMethods()) { methods.put(f.getJavaMember(), f); } for (AnnotatedMethod f : t1.getMethods()) { if (methods.containsKey(f.getJavaMember())) { if (!compareAnnotatedCallable(f, methods.get(f.getJavaMember()))) { return false; } } else { return false; } } if (t1.getConstructors().size() != t2.getConstructors().size()) { return false; } Map, AnnotatedConstructor> constructors = new HashMap, AnnotatedConstructor>(); for (AnnotatedConstructor f : t2.getConstructors()) { constructors.put(f.getJavaMember(), f); } for (AnnotatedConstructor f : t1.getConstructors()) { if (constructors.containsKey(f.getJavaMember())) { if (!compareAnnotatedCallable(f, constructors.get(f.getJavaMember()))) { return false; } } else { return false; } } return true; } private static boolean hasMethodParameters(AnnotatedCallable callable) { for (AnnotatedParameter parameter : callable.getParameters()) { if (!parameter.getAnnotations().isEmpty()) { return true; } } return false; } private static String createAnnotationCollectionId(Collection annotations) { if (annotations.isEmpty()) { return ""; } StringBuilder builder = new StringBuilder(); builder.append('['); List annotationList = new ArrayList(annotations.size()); annotationList.addAll(annotations); Collections.sort(annotationList, AnnotationComparator.INSTANCE); for (Annotation a : annotationList) { builder.append('@'); builder.append(a.annotationType().getName()); builder.append('('); Method[] declaredMethods = a.annotationType().getDeclaredMethods(); List methods = new ArrayList(declaredMethods.length); methods.addAll(Arrays.asList(declaredMethods)); Collections.sort(methods, MethodComparator.INSTANCE); for (int i = 0; i < methods.size(); ++i) { Method method = methods.get(i); try { Object value = method.invoke(a); builder.append(method.getName()); builder.append('='); builder.append(value.toString()); } catch (NullPointerException e) { throw new RuntimeException("NullPointerException accessing annotation member, annotation:" + a.annotationType().getName() + " member: " + method.getName(), e); } catch (IllegalArgumentException e) { throw new RuntimeException("IllegalArgumentException accessing annotation member, annotation:" + a.annotationType().getName() + " member: " + method.getName(), e); } catch (IllegalAccessException e) { throw new RuntimeException("IllegalAccessException accessing annotation member, annotation:" + a.annotationType().getName() + " member: " + method.getName(), e); } catch (InvocationTargetException e) { throw new RuntimeException("InvocationTargetException accessing annotation member, annotation:" + a.annotationType().getName() + " member: " + method.getName(), e); } if (i + 1 != methods.size()) { builder.append(','); } } builder.append(')'); } builder.append(']'); return builder.toString(); } /** * Compares two annotated elements to see if they have the same annotations */ private static boolean compareAnnotated(Annotated a1, Annotated a2) { return a1.getAnnotations().equals(a2.getAnnotations()); } /** * Compares two annotated elements to see if they have the same annotations */ private static boolean compareAnnotatedParameters(List> p1, List> p2) { if (p1.size() != p2.size()) { return false; } for (int i = 0; i < p1.size(); ++i) { if (!compareAnnotated(p1.get(i), p2.get(i))) { return false; } } return true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy