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; } }