| /* |
| * JBoss, Home of Professional Open Source |
| * Copyright 2008, Red Hat Middleware LLC, and individual contributors |
| * by the @authors tag. See the copyright.txt in the distribution for a |
| * full listing of individual contributors. |
| * |
| * 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.apache.uima.fit.legacy.converter; |
| |
| import java.io.Serializable; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.util.Arrays; |
| |
| /** |
| * <p> |
| * Supports inline instantiation of annotation type instances. |
| * </p> |
| * |
| * <p> |
| * An instance of an annotation type may be obtained by subclassing {@link AnnotationLiteral}. |
| * </p> |
| * |
| * <pre> |
| * public abstract class PayByQualifier extends AnnotationLiteral<PayBy> implements PayBy { |
| * } |
| * </pre> |
| * |
| * <pre> |
| * PayBy paybyCheque = new PayByQualifier() { |
| * public PaymentMethod value() { |
| * return CHEQUE; |
| * } |
| * }; |
| * </pre> |
| * |
| * @author Pete Muir |
| * @author Gavin King |
| * |
| * @param <T> |
| * the annotation type |
| * |
| * @see <a href="http://docs.oracle.com/javaee/6/api/javax/enterprise/inject/Instance.html#select(java.lang.annotation.Annotation...)">javax.enterprise.inject.Instance.select(Annotation...)</a> |
| * @see <a href="http://docs.oracle.com/javaee/6/api/javax/enterprise/event/Event.html#select(java.lang.annotation.Annotation...)">javax.enterprise.event.Event.select(Annotation...)</a> |
| * |
| */ |
| // 2013-01-20 rec |
| // - Included file in this module to remove depenendy on javax.enterprise cdi-api which induced |
| // additional unnecessary transitive dependencies |
| // - Changed to "default" visbility scope because it is only used in this package |
| // - Formatted source code according to UIMA code style |
| abstract class AnnotationLiteral<T extends Annotation> implements Annotation, Serializable { |
| |
| private transient Class<T> annotationType; |
| |
| private transient Method[] members; |
| |
| protected AnnotationLiteral() { |
| } |
| |
| private Method[] getMembers() { |
| if (members == null) { |
| members = annotationType().getDeclaredMethods(); |
| if (members.length > 0 && !annotationType().isAssignableFrom(this.getClass())) { |
| throw new RuntimeException(getClass() |
| + " does not implement the annotation type with members " |
| + annotationType().getName()); |
| } |
| } |
| return members; |
| } |
| |
| private static Class<?> getAnnotationLiteralSubclass(Class<?> clazz) { |
| Class<?> superclass = clazz.getSuperclass(); |
| if (superclass.equals(AnnotationLiteral.class)) { |
| return clazz; |
| } else if (superclass.equals(Object.class)) { |
| return null; |
| } else { |
| return (getAnnotationLiteralSubclass(superclass)); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static <T> Class<T> getTypeParameter(Class<?> annotationLiteralSuperclass) { |
| Type type = annotationLiteralSuperclass.getGenericSuperclass(); |
| if (type instanceof ParameterizedType) { |
| ParameterizedType parameterizedType = (ParameterizedType) type; |
| if (parameterizedType.getActualTypeArguments().length == 1) { |
| return (Class<T>) parameterizedType.getActualTypeArguments()[0]; |
| } |
| } |
| return null; |
| } |
| |
| public Class<? extends Annotation> annotationType() { |
| if (annotationType == null) { |
| Class<?> annotationLiteralSubclass = getAnnotationLiteralSubclass(this.getClass()); |
| if (annotationLiteralSubclass == null) { |
| throw new RuntimeException(getClass() + "is not a subclass of AnnotationLiteral"); |
| } |
| annotationType = getTypeParameter(annotationLiteralSubclass); |
| if (annotationType == null) { |
| throw new RuntimeException(getClass() |
| + " does not specify the type parameter T of AnnotationLiteral<T>"); |
| } |
| } |
| return annotationType; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder string = new StringBuilder(); |
| string.append('@').append(annotationType().getName()).append('('); |
| for (int i = 0; i < getMembers().length; i++) { |
| string.append(getMembers()[i].getName()).append('='); |
| Object value = invoke(getMembers()[i], this); |
| if (value instanceof boolean[]) { |
| appendInBraces(string, Arrays.toString((boolean[]) value)); |
| } else if (value instanceof byte[]) { |
| appendInBraces(string, Arrays.toString((byte[]) value)); |
| } else if (value instanceof short[]) { |
| appendInBraces(string, Arrays.toString((short[]) value)); |
| } else if (value instanceof int[]) { |
| appendInBraces(string, Arrays.toString((int[]) value)); |
| } else if (value instanceof long[]) { |
| appendInBraces(string, Arrays.toString((long[]) value)); |
| } else if (value instanceof float[]) { |
| appendInBraces(string, Arrays.toString((float[]) value)); |
| } else if (value instanceof double[]) { |
| appendInBraces(string, Arrays.toString((double[]) value)); |
| } else if (value instanceof char[]) { |
| appendInBraces(string, Arrays.toString((char[]) value)); |
| } else if (value instanceof String[]) { |
| String[] strings = (String[]) value; |
| String[] quoted = new String[strings.length]; |
| for (int j = 0; j < strings.length; j++) { |
| quoted[j] = "\"" + strings[j] + "\""; |
| } |
| appendInBraces(string, Arrays.toString(quoted)); |
| } else if (value instanceof Class<?>[]) { |
| Class<?>[] classes = (Class<?>[]) value; |
| String[] names = new String[classes.length]; |
| for (int j = 0; j < classes.length; j++) { |
| names[j] = classes[j].getName() + ".class"; |
| } |
| appendInBraces(string, Arrays.toString(names)); |
| } else if (value instanceof Object[]) { |
| appendInBraces(string, Arrays.toString((Object[]) value)); |
| } else if (value instanceof String) { |
| string.append('"').append(value).append('"'); |
| } else if (value instanceof Class<?>) { |
| string.append(((Class<?>) value).getName()).append(".class"); |
| } else { |
| string.append(value); |
| } |
| if (i < getMembers().length - 1) { |
| string.append(", "); |
| } |
| } |
| return string.append(')').toString(); |
| } |
| |
| private void appendInBraces(StringBuilder buf, String s) { |
| buf.append('{').append(s.substring(1, s.length() - 1)).append('}'); |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other instanceof Annotation) { |
| Annotation that = (Annotation) other; |
| if (this.annotationType().equals(that.annotationType())) { |
| for (Method member : getMembers()) { |
| Object thisValue = invoke(member, this); |
| Object thatValue = invoke(member, that); |
| if (thisValue instanceof byte[] && thatValue instanceof byte[]) { |
| if (!Arrays.equals((byte[]) thisValue, (byte[]) thatValue)) |
| return false; |
| } else if (thisValue instanceof short[] && thatValue instanceof short[]) { |
| if (!Arrays.equals((short[]) thisValue, (short[]) thatValue)) |
| return false; |
| } else if (thisValue instanceof int[] && thatValue instanceof int[]) { |
| if (!Arrays.equals((int[]) thisValue, (int[]) thatValue)) |
| return false; |
| } else if (thisValue instanceof long[] && thatValue instanceof long[]) { |
| if (!Arrays.equals((long[]) thisValue, (long[]) thatValue)) |
| return false; |
| } else if (thisValue instanceof float[] && thatValue instanceof float[]) { |
| if (!Arrays.equals((float[]) thisValue, (float[]) thatValue)) |
| return false; |
| } else if (thisValue instanceof double[] && thatValue instanceof double[]) { |
| if (!Arrays.equals((double[]) thisValue, (double[]) thatValue)) |
| return false; |
| } else if (thisValue instanceof char[] && thatValue instanceof char[]) { |
| if (!Arrays.equals((char[]) thisValue, (char[]) thatValue)) |
| return false; |
| } else if (thisValue instanceof boolean[] && thatValue instanceof boolean[]) { |
| if (!Arrays.equals((boolean[]) thisValue, (boolean[]) thatValue)) |
| return false; |
| } else if (thisValue instanceof Object[] && thatValue instanceof Object[]) { |
| if (!Arrays.equals((Object[]) thisValue, (Object[]) thatValue)) |
| return false; |
| } else { |
| if (!thisValue.equals(thatValue)) |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| int hashCode = 0; |
| for (Method member : getMembers()) { |
| int memberNameHashCode = 127 * member.getName().hashCode(); |
| Object value = invoke(member, this); |
| int memberValueHashCode; |
| if (value instanceof boolean[]) { |
| memberValueHashCode = Arrays.hashCode((boolean[]) value); |
| } else if (value instanceof short[]) { |
| memberValueHashCode = Arrays.hashCode((short[]) value); |
| } else if (value instanceof int[]) { |
| memberValueHashCode = Arrays.hashCode((int[]) value); |
| } else if (value instanceof long[]) { |
| memberValueHashCode = Arrays.hashCode((long[]) value); |
| } else if (value instanceof float[]) { |
| memberValueHashCode = Arrays.hashCode((float[]) value); |
| } else if (value instanceof double[]) { |
| memberValueHashCode = Arrays.hashCode((double[]) value); |
| } else if (value instanceof byte[]) { |
| memberValueHashCode = Arrays.hashCode((byte[]) value); |
| } else if (value instanceof char[]) { |
| memberValueHashCode = Arrays.hashCode((char[]) value); |
| } else if (value instanceof Object[]) { |
| memberValueHashCode = Arrays.hashCode((Object[]) value); |
| } else { |
| memberValueHashCode = value.hashCode(); |
| } |
| hashCode += memberNameHashCode ^ memberValueHashCode; |
| } |
| return hashCode; |
| } |
| |
| private static Object invoke(Method method, Object instance) { |
| try { |
| if (!method.isAccessible()) |
| method.setAccessible(true); |
| return method.invoke(instance); |
| } catch (IllegalArgumentException e) { |
| throw new RuntimeException("Error checking value of member method " + method.getName() |
| + " on " + method.getDeclaringClass(), e); |
| } catch (IllegalAccessException e) { |
| throw new RuntimeException("Error checking value of member method " + method.getName() |
| + " on " + method.getDeclaringClass(), e); |
| } catch (InvocationTargetException e) { |
| throw new RuntimeException("Error checking value of member method " + method.getName() |
| + " on " + method.getDeclaringClass(), e); |
| } |
| } |
| |
| } |