/** * Find an accessible constructor with compatible parameters. Compatible parameters mean that * every method parameter is assignable from the given parameters. In other words, it finds * constructor that will take the parameters given. * * <p>First it checks if there is constructor matching the exact signature. If no such, all the * constructors of the class are tested if their signatures are assignment compatible with the * parameter types. The first matching constructor is returned. * * @param cls find constructor for this class * @param parameterTypes find method with compatible parameters * @return a valid Constructor object. If there's no matching constructor, returns <code>null * </code>. */ public static Constructor getMatchingAccessibleConstructor(Class cls, Class[] parameterTypes) { // see if we can find the constructor directly // most of the time this works and it's much faster try { Constructor ctor = cls.getConstructor(parameterTypes); MemberUtils.setAccessibleWorkaround(ctor); return ctor; } catch (NoSuchMethodException e) { /* SWALLOW */ } Constructor result = null; // search through all constructors Constructor[] ctors = cls.getConstructors(); for (int i = 0; i < ctors.length; i++) { // compare parameters if (ClassUtils.isAssignable(parameterTypes, ctors[i].getParameterTypes(), true)) { // get accessible version of method Constructor ctor = getAccessibleConstructor(ctors[i]); if (ctor != null) { MemberUtils.setAccessibleWorkaround(ctor); if (result == null || MemberUtils.compareParameterTypes( ctor.getParameterTypes(), result.getParameterTypes(), parameterTypes) < 0) { result = ctor; } } } } return result; }
/** * Gets an accessible <code>Field</code> by name breaking scope if requested. * Superclasses/interfaces will be considered. * * @param cls the class to reflect, must not be null * @param fieldName the field name to obtain * @param forceAccess whether to break scope restrictions using the <code>setAccessible</code> * method. <code>False</code> will only match public fields. * @return the Field object * @throws IllegalArgumentException if the class or field name is null */ public static Field getField(final Class cls, String fieldName, boolean forceAccess) { if (cls == null) { throw new IllegalArgumentException("The class must not be null"); } if (fieldName == null) { throw new IllegalArgumentException("The field name must not be null"); } // Sun Java 1.3 has a bugged implementation of getField hence we write the // code ourselves // getField() will return the Field object with the declaring class // set correctly to the class that declares the field. Thus requesting the // field on a subclass will return the field from the superclass. // // priority order for lookup: // searchclass private/protected/package/public // superclass protected/package/public // private/different package blocks access to further superclasses // implementedinterface public // check up the superclass hierarchy for (Class acls = cls; acls != null; acls = acls.getSuperclass()) { try { Field field = acls.getDeclaredField(fieldName); // getDeclaredField checks for non-public scopes as well // and it returns accurate results if (!Modifier.isPublic(field.getModifiers())) { if (forceAccess) { field.setAccessible(true); } else { continue; } } return field; } catch (NoSuchFieldException ex) { // ignore } } // check the public interface case. This must be manually searched for // incase there is a public supersuperclass field hidden by a private/package // superclass field. Field match = null; for (Iterator intf = ClassUtils.getAllInterfaces(cls).iterator(); intf.hasNext(); ) { try { Field test = ((Class) intf.next()).getField(fieldName); if (match != null) { throw new IllegalArgumentException( "Reference to field " + fieldName + " is ambiguous relative to " + cls + "; a matching field exists on two or more implemented interfaces."); } match = test; } catch (NoSuchFieldException ex) { // ignore } } return match; }