| /* |
| * 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 javax.enterprise.util; |
| |
| import java.io.Serializable; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.AccessibleObject; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.Arrays; |
| |
| /** |
| * Annotation literal utility. |
| * |
| * @param <T> wrapped annotation class |
| * @version $Rev$ $Date$ |
| */ |
| @SuppressWarnings("unchecked") |
| public abstract class AnnotationLiteral<T extends Annotation> implements Annotation, Serializable |
| { |
| private static final long serialVersionUID = -1885320698638161810L; |
| |
| private Class<T> annotationType; |
| |
| private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; |
| |
| protected AnnotationLiteral() |
| { |
| this.annotationType = getAnnotationType(getClass()); |
| |
| } |
| |
| public Class<? extends Annotation> annotationType() |
| { |
| return annotationType; |
| } |
| |
| private Class<T> getAnnotationType(Class<?> definedClazz) |
| { |
| Type superClazz = definedClazz.getGenericSuperclass(); |
| |
| Class<T> clazz = null; |
| |
| if (superClazz.equals(Object.class)) |
| { |
| throw new RuntimeException("Super class must be parametrized type!"); |
| } |
| |
| else if (superClazz instanceof ParameterizedType) |
| { |
| ParameterizedType paramType = (ParameterizedType) superClazz; |
| Type[] actualArgs = paramType.getActualTypeArguments(); |
| |
| if (actualArgs.length == 1) |
| { |
| //Actual annotation type |
| Type type = actualArgs[0]; |
| |
| if (type instanceof Class) |
| { |
| clazz = (Class<T>) type; |
| return clazz; |
| } |
| else |
| { |
| throw new RuntimeException("Not class type!"); |
| } |
| } |
| else |
| { |
| throw new RuntimeException("More than one parametric type!"); |
| } |
| } |
| else |
| { |
| return getAnnotationType((Class<?>) superClazz); |
| } |
| |
| } |
| |
| @Override |
| public boolean equals(Object other) |
| { |
| Method[] methods = (Method[])AccessController.doPrivileged(new PrivilegedAction() { |
| public Object run() |
| { |
| return annotationType.getDeclaredMethods(); |
| } |
| }); |
| |
| if(other == this) |
| { |
| return true; |
| } |
| |
| if(other == null) |
| { |
| return false; |
| } |
| |
| if (other instanceof Annotation) |
| { |
| Annotation annotOther = (Annotation) other; |
| if (this.annotationType().equals(annotOther.annotationType())) |
| { |
| for (Method method : methods) |
| { |
| Object value = callMethod(this, method); |
| Object annotValue = callMethod(annotOther, method); |
| |
| if((value == null && annotValue != null) || (value != null && annotValue == null)) |
| { |
| return false; |
| } |
| |
| if(value == null && annotValue == null) |
| { |
| continue; |
| } |
| |
| Class<?> valueClass = value.getClass(); |
| Class<?> annotValueClass = annotValue.getClass(); |
| |
| if(valueClass.isPrimitive() && annotValueClass.isPrimitive()) |
| { |
| if((valueClass != Float.TYPE && annotValue != Float.TYPE) |
| || (valueClass != Double.TYPE && annotValue != Double.TYPE)) |
| { |
| if(value != annotValue) |
| { |
| return false; |
| } |
| |
| } |
| } |
| else if(valueClass.isArray() && annotValueClass.isArray()) |
| { |
| Class<?> type = valueClass.getComponentType(); |
| if(type.isPrimitive()) |
| { |
| if(Long.TYPE == type) |
| { |
| if(!Arrays.equals(((Long[])value),(Long[])annotValue)) return false; |
| } |
| else if(Integer.TYPE == type) |
| { |
| if(!Arrays.equals(((Integer[])value),(Integer[])annotValue)) return false; |
| } |
| else if(Short.TYPE == type) |
| { |
| if(!Arrays.equals(((Short[])value),(Short[])annotValue)) return false; |
| } |
| else if(Double.TYPE == type) |
| { |
| if(!Arrays.equals(((Double[])value),(Double[])annotValue)) return false; |
| } |
| else if(Float.TYPE == type) |
| { |
| if(!Arrays.equals(((Float[])value),(Float[])annotValue)) return false; |
| } |
| else if(Boolean.TYPE == type) |
| { |
| if(!Arrays.equals(((Boolean[])value),(Boolean[])annotValue)) return false; |
| } |
| else if(Byte.TYPE == type) |
| { |
| if(!Arrays.equals(((Byte[])value),(Byte[])annotValue)) return false; |
| } |
| else if(Character.TYPE == type) |
| { |
| if(!Arrays.equals(((Character[])value),(Character[])annotValue)) return false; |
| } |
| } |
| else |
| { |
| if(!Arrays.equals(((Object[])value),(Object[])annotValue)) return false; |
| } |
| } |
| |
| else if (value != null && annotValue != null) |
| { |
| if (!value.equals(annotValue)) |
| { |
| return false; |
| } |
| } |
| |
| } |
| |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private Object callMethod(Object instance, Method method) |
| { |
| boolean access = method.isAccessible(); |
| |
| try |
| { |
| if (!method.isAccessible()) |
| { |
| AccessController.doPrivileged(new PrivilegedActionForAccessibleObject(method, true)); |
| } |
| |
| return method.invoke(instance, EMPTY_OBJECT_ARRAY); |
| } |
| catch (Exception e) |
| { |
| throw new RuntimeException("Exception in method call : " + method.getName(), e); |
| } |
| finally |
| { |
| AccessController.doPrivileged(new PrivilegedActionForAccessibleObject(method, access)); |
| } |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| Method[] methods = (Method[])AccessController.doPrivileged(new PrivilegedAction() { |
| public Object run() |
| { |
| return annotationType.getDeclaredMethods(); |
| } |
| }); |
| |
| int hashCode = 0; |
| for (Method method : methods) |
| { |
| // Member name |
| int name = 127 * method.getName().hashCode(); |
| |
| // Member value |
| Object object = callMethod(this, method); |
| int value = 0; |
| if(object.getClass().isArray()) |
| { |
| Class<?> type = object.getClass().getComponentType(); |
| if(type.isPrimitive()) |
| { |
| if(Long.TYPE == type) |
| { |
| value = Arrays.hashCode((Long[])object); |
| } |
| else if(Integer.TYPE == type) |
| { |
| value = Arrays.hashCode((Integer[])object); |
| } |
| else if(Short.TYPE == type) |
| { |
| value = Arrays.hashCode((Short[])object); |
| } |
| else if(Double.TYPE == type) |
| { |
| value = Arrays.hashCode((Double[])object); |
| } |
| else if(Float.TYPE == type) |
| { |
| value = Arrays.hashCode((Float[])object); |
| } |
| else if(Boolean.TYPE == type) |
| { |
| value = Arrays.hashCode((Long[])object); |
| } |
| else if(Byte.TYPE == type) |
| { |
| value = Arrays.hashCode((Byte[])object); |
| } |
| else if(Character.TYPE == type) |
| { |
| value = Arrays.hashCode((Character[])object); |
| } |
| } |
| else |
| { |
| value = Arrays.hashCode((Object[])object); |
| } |
| } |
| else |
| { |
| value = object.hashCode(); |
| } |
| |
| hashCode += name ^ value; |
| } |
| return hashCode; |
| } |
| |
| |
| @Override |
| public String toString() |
| { |
| Method[] methods = (Method[])AccessController.doPrivileged(new PrivilegedAction() { |
| public Object run() |
| { |
| return annotationType.getDeclaredMethods(); |
| } |
| }); |
| StringBuilder sb = new StringBuilder("@" + annotationType().getName() + "("); |
| int lenght = methods.length; |
| |
| for (int i = 0; i < lenght; i++) |
| { |
| // Member name |
| sb.append(methods[i].getName()).append("="); |
| |
| // Member value |
| sb.append(callMethod(this, methods[i])); |
| |
| if (i < lenght - 1) |
| { |
| sb.append(","); |
| } |
| } |
| |
| sb.append(")"); |
| |
| return sb.toString(); |
| } |
| |
| protected static class PrivilegedActionForAccessibleObject implements PrivilegedAction<Object> |
| { |
| AccessibleObject object; |
| boolean flag; |
| |
| protected PrivilegedActionForAccessibleObject(AccessibleObject object, boolean flag) |
| { |
| this.object = object; |
| this.flag = flag; |
| } |
| |
| public Object run() |
| { |
| object.setAccessible(flag); |
| return null; |
| } |
| } |
| |
| } |
| |