/******************************************************************************* * * Copyright (c) 2004-2010, Oracle Corporation * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * * * *******************************************************************************/ package hudson.util; import org.apache.commons.beanutils.PropertyUtils; import org.kohsuke.stapler.ClassDescriptor; import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.AbstractList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Utility code for reflection. * * @author Kohsuke Kawaguchi * @since 1.351 */ public class ReflectionUtils extends org.springframework.util.ReflectionUtils { /** * Finds a public method of the given name, regardless of its parameter * definitions, */ public static Method getPublicMethodNamed(Class c, String methodName) { for (Method m : c.getMethods()) { if (m.getName().equals(methodName)) { return m; } } return null; } /** * Returns an object-oriented view of parameters of each type. */ public static List<Parameter> getParameters(Method m) { return new MethodInfo(m); } public static Object getPublicProperty(Object o, String p) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { PropertyDescriptor pd = PropertyUtils.getPropertyDescriptor(o, p); if (pd == null) { // field? try { Field f = o.getClass().getField(p); return f.get(o); } catch (NoSuchFieldException e) { throw new IllegalArgumentException("No such property " + p + " on " + o.getClass()); } } else { return PropertyUtils.getProperty(o, p); } } /** * Most reflection operations give us properties of parameters in a batch, * so we use this object to store them, then {@link Parameter} will created * more object-oriented per-parameter view. */ private static final class MethodInfo extends AbstractList<Parameter> { private final Method method; private final Class<?>[] types; private Type[] genericTypes; private Annotation[][] annotations; private String[] names; private MethodInfo(Method method) { this.method = method; types = method.getParameterTypes(); } @Override public Parameter get(int index) { return new Parameter(this, index); } @Override public int size() { return types.length; } public Type[] genericTypes() { if (genericTypes == null) { genericTypes = method.getGenericParameterTypes(); } return genericTypes; } public Annotation[][] annotations() { if (annotations == null) { annotations = method.getParameterAnnotations(); } return annotations; } public String[] names() { if (names == null) { names = ClassDescriptor.loadParameterNames(method); } return names; } } public static final class Parameter { private final MethodInfo parent; private final int index; public Parameter(MethodInfo parent, int index) { this.parent = parent; this.index = index; } /** * 0-origin index of this parameter. */ public int index() { return index; } /** * Gets the type of this parameter. */ public Class<?> type() { return parent.types[index]; } /** * Gets the unerased generic type of this parameter. */ public Type genericType() { return parent.genericTypes()[index]; } /** * Gets all the annotations on this parameter. */ public Annotation[] annotations() { return parent.annotations()[index]; } /** * Gets the specified annotation on this parameter or null. */ public <A extends Annotation> A annotation(Class<A> type) { for (Annotation a : annotations()) { if (a.annotationType() == type) { return type.cast(a); } } return null; } /** * Name of this parameter. * * If unknown, this method returns null. */ public String name() { String[] names = parent.names(); if (index < names.length) { return names[index]; } return null; } } /** * Given the primitive type, returns the VM default value for that type in a * boxed form. */ public static Object getVmDefaultValueForPrimitiveType(Class<?> type) { return defaultPrimitiveValue.get(type); } private static final Map<Class, Object> defaultPrimitiveValue = new HashMap<Class, Object>(); static { defaultPrimitiveValue.put(boolean.class, false); defaultPrimitiveValue.put(int.class, 0); defaultPrimitiveValue.put(long.class, 0L); } }