blob: ff8753b452c9b31310b4dbbd53455ce0e465e97c [file] [log] [blame]
package com.beust.jcommander;
import com.beust.jcommander.internal.Lists;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
/**
* Encapsulate a field or a method annotated with @Parameter or @DynamicParameter
*/
public class Parameterized {
// Either a method or a field
private Field m_field;
private Method m_method;
private Method m_getter;
// Either of these two
private WrappedParameter m_wrappedParameter;
private ParametersDelegate m_parametersDelegate;
public Parameterized(WrappedParameter wp, ParametersDelegate pd,
Field field, Method method) {
m_wrappedParameter = wp;
m_method = method;
m_field = field;
if (m_field != null) {
m_field.setAccessible(true);
}
m_parametersDelegate = pd;
}
public static List<Parameterized> parseArg(Object arg) {
List<Parameterized> result = Lists.newArrayList();
Class<? extends Object> cls = arg.getClass();
while (!Object.class.equals(cls)) {
for (Field f : cls.getDeclaredFields()) {
Annotation annotation = f.getAnnotation(Parameter.class);
Annotation delegateAnnotation = f.getAnnotation(ParametersDelegate.class);
Annotation dynamicParameter = f.getAnnotation(DynamicParameter.class);
if (annotation != null) {
result.add(new Parameterized(new WrappedParameter((Parameter) annotation), null,
f, null));
} else if (dynamicParameter != null) {
result.add(new Parameterized(new WrappedParameter((DynamicParameter) dynamicParameter), null,
f, null));
} else if (delegateAnnotation != null) {
result.add(new Parameterized(null, (ParametersDelegate) delegateAnnotation,
f, null));
}
}
cls = cls.getSuperclass();
}
// Reassigning
cls = arg.getClass();
while (!Object.class.equals(cls)) {
for (Method m : cls.getDeclaredMethods()) {
Annotation annotation = m.getAnnotation(Parameter.class);
Annotation delegateAnnotation = m.getAnnotation(ParametersDelegate.class);
Annotation dynamicParameter = m.getAnnotation(DynamicParameter.class);
if (annotation != null) {
result.add(new Parameterized(new WrappedParameter((Parameter) annotation), null,
null, m));
} else if (dynamicParameter != null) {
result.add(new Parameterized(new WrappedParameter((DynamicParameter) annotation), null,
null, m));
} else if (delegateAnnotation != null) {
result.add(new Parameterized(null, (ParametersDelegate) delegateAnnotation,
null, m));
}
}
cls = cls.getSuperclass();
}
return result;
}
public WrappedParameter getWrappedParameter() {
return m_wrappedParameter;
}
public Class<?> getType() {
if (m_method != null) {
return m_method.getParameterTypes()[0];
} else {
return m_field.getType();
}
}
public String getName() {
if (m_method != null) {
return m_method.getName();
} else {
return m_field.getName();
}
}
public Object get(Object object) {
try {
if (m_method != null) {
if (m_getter == null) {
m_getter = m_method.getDeclaringClass()
.getMethod("g" + m_method.getName().substring(1),
new Class[0]);
}
return m_getter.invoke(object);
} else {
return m_field.get(object);
}
} catch (SecurityException e) {
throw new ParameterException(e);
} catch (NoSuchMethodException e) {
// Try to find a field
String name = m_method.getName();
String fieldName = Character.toLowerCase(name.charAt(3)) + name.substring(4);
Object result = null;
try {
Field field = m_method.getDeclaringClass().getDeclaredField(fieldName);
if (field != null) {
field.setAccessible(true);
result = field.get(object);
}
} catch(NoSuchFieldException ex) {
// ignore
} catch(IllegalAccessException ex) {
// ignore
}
return result;
} catch (IllegalArgumentException e) {
throw new ParameterException(e);
} catch (IllegalAccessException e) {
throw new ParameterException(e);
} catch (InvocationTargetException e) {
throw new ParameterException(e);
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((m_field == null) ? 0 : m_field.hashCode());
result = prime * result + ((m_method == null) ? 0 : m_method.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Parameterized other = (Parameterized) obj;
if (m_field == null) {
if (other.m_field != null)
return false;
} else if (!m_field.equals(other.m_field))
return false;
if (m_method == null) {
if (other.m_method != null)
return false;
} else if (!m_method.equals(other.m_method))
return false;
return true;
}
public boolean isDynamicParameter(Field field) {
if (m_method != null) {
return m_method.getAnnotation(DynamicParameter.class) != null;
} else {
return m_field.getAnnotation(DynamicParameter.class) != null;
}
}
public void set(Object object, Object value) {
try {
if (m_method != null) {
m_method.invoke(object, value);
} else {
m_field.set(object, value);
}
} catch (IllegalArgumentException ex) {
throw new ParameterException(ex);
} catch (IllegalAccessException ex) {
throw new ParameterException(ex);
} catch (InvocationTargetException ex) {
// If a ParameterException was thrown, don't wrap it into another one
if (ex.getTargetException() instanceof ParameterException) {
throw (ParameterException) ex.getTargetException();
} else {
throw new ParameterException(ex);
}
}
}
public ParametersDelegate getDelegateAnnotation() {
return m_parametersDelegate;
}
public Type getGenericType() {
if (m_method != null) {
return m_method.getGenericParameterTypes()[0];
} else {
return m_field.getGenericType();
}
}
public Parameter getParameter() {
return m_wrappedParameter.getParameter();
}
/**
* @return the generic type of the collection for this field, or null if not applicable.
*/
public Type findFieldGenericType() {
if (m_method != null) {
return null;
} else {
if (m_field.getGenericType() instanceof ParameterizedType) {
ParameterizedType p = (ParameterizedType) m_field.getGenericType();
Type cls = p.getActualTypeArguments()[0];
if (cls instanceof Class) {
return cls;
}
}
}
return null;
}
public boolean isDynamicParameter() {
return m_wrappedParameter.getDynamicParameter() != null;
}
}