blob: 7df753475d17cdeaa4483c138c4711784fa2d9fd [file] [log] [blame]
/*
* 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;
}
}
}