move/comment SuppressWarnings(unchecked)/refactor surrounding code
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@983709 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2f66e0fdf8
commit
e51c8d6cfb
|
@ -24,19 +24,21 @@
|
||||||
import org.apache.commons.lang3.ClassUtils;
|
import org.apache.commons.lang3.ClassUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p> Utility reflection methods focussed on constructors, modelled after {@link MethodUtils}. </p>
|
* <p> Utility reflection methods focussed on constructors, modelled after
|
||||||
|
* {@link MethodUtils}. </p>
|
||||||
*
|
*
|
||||||
* <h3>Known Limitations</h3>
|
* <h3>Known Limitations</h3> <h4>Accessing Public Constructors In A Default
|
||||||
* <h4>Accessing Public Constructors In A Default Access Superclass</h4>
|
* Access Superclass</h4> <p>There is an issue when invoking public constructors
|
||||||
* <p>There is an issue when invoking public constructors contained in a default access superclass.
|
* contained in a default access superclass. Reflection locates these
|
||||||
* Reflection locates these constructors fine and correctly assigns them as public.
|
* constructors fine and correctly assigns them as public. However, an
|
||||||
* However, an <code>IllegalAccessException</code> is thrown if the constructors is invoked.</p>
|
* <code>IllegalAccessException</code> is thrown if the constructors is
|
||||||
|
* invoked.</p>
|
||||||
*
|
*
|
||||||
* <p><code>ConstructorUtils</code> contains a workaround for this situation.
|
* <p><code>ConstructorUtils</code> contains a workaround for this situation. It
|
||||||
* It will attempt to call <code>setAccessible</code> on this constructor.
|
* will attempt to call <code>setAccessible</code> on this constructor. If this
|
||||||
* If this call succeeds, then the method can be invoked as normal.
|
* call succeeds, then the method can be invoked as normal. This call will only
|
||||||
* This call will only succeed when the application has sufficient security privilages.
|
* succeed when the application has sufficient security privilages. If this call
|
||||||
* If this call fails then a warning will be logged and the method may fail.</p>
|
* fails then a warning will be logged and the method may fail.</p>
|
||||||
*
|
*
|
||||||
* @author Apache Software Foundation
|
* @author Apache Software Foundation
|
||||||
* @author Craig R. McClanahan
|
* @author Craig R. McClanahan
|
||||||
|
@ -53,8 +55,8 @@
|
||||||
public class ConstructorUtils {
|
public class ConstructorUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>ConstructorUtils instances should NOT be constructed in standard programming.
|
* <p>ConstructorUtils instances should NOT be constructed in standard
|
||||||
* Instead, the class should be used as
|
* programming. Instead, the class should be used as
|
||||||
* <code>ConstructorUtils.invokeConstructor(cls, args)</code>.</p>
|
* <code>ConstructorUtils.invokeConstructor(cls, args)</code>.</p>
|
||||||
*
|
*
|
||||||
* <p>This constructor is public to permit tools that require a JavaBean
|
* <p>This constructor is public to permit tools that require a JavaBean
|
||||||
|
@ -65,9 +67,11 @@ public ConstructorUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns new instance of <code>klazz</code> created using the actual arguments <code>args</code>.
|
* <p>Returns new instance of <code>klazz</code> created using the actual
|
||||||
* The formal parameter types are inferred from the actual values of <code>args</code>.
|
* arguments <code>args</code>. The formal parameter types are inferred from
|
||||||
* See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
|
* the actual values of <code>args</code>. See
|
||||||
|
* {@link #invokeExactConstructor(Class, Object[], Class[])} for more
|
||||||
|
* details.</p>
|
||||||
*
|
*
|
||||||
* <p>The signatures should be assignment compatible.</p>
|
* <p>The signatures should be assignment compatible.</p>
|
||||||
*
|
*
|
||||||
|
@ -76,15 +80,18 @@ public ConstructorUtils() {
|
||||||
* @return new instance of <code>klazz</code>
|
* @return new instance of <code>klazz</code>
|
||||||
*
|
*
|
||||||
* @throws NoSuchMethodException If the constructor cannot be found
|
* @throws NoSuchMethodException If the constructor cannot be found
|
||||||
* @throws IllegalAccessException If an error occurs accessing the constructor
|
* @throws IllegalAccessException If an error occurs accessing the
|
||||||
* @throws InvocationTargetException If an error occurs invoking the constructor
|
* constructor
|
||||||
|
* @throws InvocationTargetException If an error occurs invoking the
|
||||||
|
* constructor
|
||||||
* @throws InstantiationException If an error occurs instantiating the class
|
* @throws InstantiationException If an error occurs instantiating the class
|
||||||
*
|
*
|
||||||
* @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
|
* @see #invokeConstructor(java.lang.Class, java.lang.Object[],
|
||||||
|
* java.lang.Class[])
|
||||||
*/
|
*/
|
||||||
public static <T> T invokeConstructor(Class<T> cls, Object... args)
|
public static <T> T invokeConstructor(Class<T> cls, Object... args)
|
||||||
throws NoSuchMethodException, IllegalAccessException,
|
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
|
||||||
InvocationTargetException, InstantiationException {
|
InstantiationException {
|
||||||
if (null == args) {
|
if (null == args) {
|
||||||
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +104,8 @@ public static <T> T invokeConstructor(Class<T> cls, Object... args)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns new instance of <code>klazz</code> created using constructor
|
* <p>Returns new instance of <code>klazz</code> created using constructor
|
||||||
* with signature <code>parameterTypes</code> and actual arguments <code>args</code>.</p>
|
* with signature <code>parameterTypes</code> and actual arguments
|
||||||
|
* <code>args</code>.</p>
|
||||||
*
|
*
|
||||||
* <p>The signatures should be assignment compatible.</p>
|
* <p>The signatures should be assignment compatible.</p>
|
||||||
*
|
*
|
||||||
|
@ -112,9 +120,8 @@ public static <T> T invokeConstructor(Class<T> cls, Object... args)
|
||||||
* @throws InstantiationException thrown on the constructor's invocation
|
* @throws InstantiationException thrown on the constructor's invocation
|
||||||
* @see Constructor#newInstance
|
* @see Constructor#newInstance
|
||||||
*/
|
*/
|
||||||
public static <T> T invokeConstructor(Class<T> cls, Object[] args,
|
public static <T> T invokeConstructor(Class<T> cls, Object[] args, Class<?>[] parameterTypes)
|
||||||
Class<?>[] parameterTypes) throws NoSuchMethodException,
|
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
|
||||||
IllegalAccessException, InvocationTargetException,
|
|
||||||
InstantiationException {
|
InstantiationException {
|
||||||
if (parameterTypes == null) {
|
if (parameterTypes == null) {
|
||||||
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
|
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
|
||||||
|
@ -124,17 +131,18 @@ public static <T> T invokeConstructor(Class<T> cls, Object[] args,
|
||||||
}
|
}
|
||||||
Constructor<T> ctor = getMatchingAccessibleConstructor(cls, parameterTypes);
|
Constructor<T> ctor = getMatchingAccessibleConstructor(cls, parameterTypes);
|
||||||
if (null == ctor) {
|
if (null == ctor) {
|
||||||
throw new NoSuchMethodException(
|
throw new NoSuchMethodException("No such accessible constructor on object: "
|
||||||
"No such accessible constructor on object: "
|
|
||||||
+ cls.getName());
|
+ cls.getName());
|
||||||
}
|
}
|
||||||
return ctor.newInstance(args);
|
return ctor.newInstance(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns new instance of <code>klazz</code> created using the actual arguments <code>args</code>.
|
* <p>Returns new instance of <code>klazz</code> created using the actual
|
||||||
* The formal parameter types are inferred from the actual values of <code>args</code>.
|
* arguments <code>args</code>. The formal parameter types are inferred from
|
||||||
* See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
|
* the actual values of <code>args</code>. See
|
||||||
|
* {@link #invokeExactConstructor(Class, Object[], Class[])} for more
|
||||||
|
* details.</p>
|
||||||
*
|
*
|
||||||
* <p>The signatures should match exactly.</p>
|
* <p>The signatures should match exactly.</p>
|
||||||
*
|
*
|
||||||
|
@ -143,15 +151,18 @@ public static <T> T invokeConstructor(Class<T> cls, Object[] args,
|
||||||
* @return new instance of <code>klazz</code>
|
* @return new instance of <code>klazz</code>
|
||||||
*
|
*
|
||||||
* @throws NoSuchMethodException If the constructor cannot be found
|
* @throws NoSuchMethodException If the constructor cannot be found
|
||||||
* @throws IllegalAccessException If an error occurs accessing the constructor
|
* @throws IllegalAccessException If an error occurs accessing the
|
||||||
* @throws InvocationTargetException If an error occurs invoking the constructor
|
* constructor
|
||||||
|
* @throws InvocationTargetException If an error occurs invoking the
|
||||||
|
* constructor
|
||||||
* @throws InstantiationException If an error occurs instantiating the class
|
* @throws InstantiationException If an error occurs instantiating the class
|
||||||
*
|
*
|
||||||
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
|
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[],
|
||||||
|
* java.lang.Class[])
|
||||||
*/
|
*/
|
||||||
public static <T> T invokeExactConstructor(Class<T> cls, Object... args)
|
public static <T> T invokeExactConstructor(Class<T> cls, Object... args)
|
||||||
throws NoSuchMethodException, IllegalAccessException,
|
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
|
||||||
InvocationTargetException, InstantiationException {
|
InstantiationException {
|
||||||
if (null == args) {
|
if (null == args) {
|
||||||
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
||||||
}
|
}
|
||||||
|
@ -182,9 +193,8 @@ public static <T> T invokeExactConstructor(Class<T> cls, Object... args)
|
||||||
* @see Constructor#newInstance
|
* @see Constructor#newInstance
|
||||||
*/
|
*/
|
||||||
public static <T> T invokeExactConstructor(Class<T> cls, Object[] args,
|
public static <T> T invokeExactConstructor(Class<T> cls, Object[] args,
|
||||||
Class<?>[] parameterTypes) throws NoSuchMethodException,
|
Class<?>[] parameterTypes) throws NoSuchMethodException, IllegalAccessException,
|
||||||
IllegalAccessException, InvocationTargetException,
|
InvocationTargetException, InstantiationException {
|
||||||
InstantiationException {
|
|
||||||
if (args == null) {
|
if (args == null) {
|
||||||
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
|
||||||
}
|
}
|
||||||
|
@ -193,8 +203,7 @@ public static <T> T invokeExactConstructor(Class<T> cls, Object[] args,
|
||||||
}
|
}
|
||||||
Constructor<T> ctor = getAccessibleConstructor(cls, parameterTypes);
|
Constructor<T> ctor = getAccessibleConstructor(cls, parameterTypes);
|
||||||
if (null == ctor) {
|
if (null == ctor) {
|
||||||
throw new NoSuchMethodException(
|
throw new NoSuchMethodException("No such accessible constructor on object: "
|
||||||
"No such accessible constructor on object: "
|
|
||||||
+ cls.getName());
|
+ cls.getName());
|
||||||
}
|
}
|
||||||
return ctor.newInstance(args);
|
return ctor.newInstance(args);
|
||||||
|
@ -225,24 +234,24 @@ public static <T> Constructor<T> getAccessibleConstructor(Class<T> cls,
|
||||||
*/
|
*/
|
||||||
public static <T> Constructor<T> getAccessibleConstructor(Constructor<T> ctor) {
|
public static <T> Constructor<T> getAccessibleConstructor(Constructor<T> ctor) {
|
||||||
return MemberUtils.isAccessible(ctor)
|
return MemberUtils.isAccessible(ctor)
|
||||||
&& Modifier.isPublic(ctor.getDeclaringClass().getModifiers()) ? ctor
|
&& Modifier.isPublic(ctor.getDeclaringClass().getModifiers()) ? ctor : null;
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Find an accessible constructor with compatible parameters.
|
* <p>Find an accessible constructor with compatible parameters. Compatible
|
||||||
* Compatible parameters mean that every method parameter is assignable from
|
* parameters mean that every method parameter is assignable from the given
|
||||||
* the given parameters. In other words, it finds constructor that will take
|
* parameters. In other words, it finds constructor that will take the
|
||||||
* the parameters given.</p>
|
* parameters given.</p>
|
||||||
*
|
*
|
||||||
* <p>First it checks if there is constructor matching the exact signature.
|
* <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
|
* If no such, all the constructors of the class are tested if their
|
||||||
* are assignment compatible with the parameter types.
|
* signatures are assignment compatible with the parameter types. The first
|
||||||
* The first matching constructor is returned.</p>
|
* matching constructor is returned.</p>
|
||||||
*
|
*
|
||||||
* @param cls find constructor for this class
|
* @param cls find constructor for this class
|
||||||
* @param parameterTypes find method with compatible parameters
|
* @param parameterTypes find method with compatible parameters
|
||||||
* @return a valid Constructor object. If there's no matching constructor, returns <code>null</code>.
|
* @return a valid Constructor object. If there's no matching constructor,
|
||||||
|
* returns <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public static <T> Constructor<T> getMatchingAccessibleConstructor(Class<T> cls,
|
public static <T> Constructor<T> getMatchingAccessibleConstructor(Class<T> cls,
|
||||||
Class<?>... parameterTypes) {
|
Class<?>... parameterTypes) {
|
||||||
|
@ -255,20 +264,23 @@ public static <T> Constructor<T> getMatchingAccessibleConstructor(Class<T> cls,
|
||||||
} catch (NoSuchMethodException e) { /* SWALLOW */
|
} catch (NoSuchMethodException e) { /* SWALLOW */
|
||||||
}
|
}
|
||||||
Constructor<T> result = null;
|
Constructor<T> result = null;
|
||||||
// search through all constructors
|
/*
|
||||||
Constructor<?>[] ctors = cls.getConstructors();
|
* Class.getConstructors() is documented to return Constructor<T> so as
|
||||||
for (int i = 0; i < ctors.length; i++) {
|
* long as the array is not subsequently modified, everything's fine:
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Constructor<T>[] ctors = (Constructor<T>[]) cls.getConstructors();
|
||||||
|
|
||||||
|
// return best match:
|
||||||
|
for (Constructor<T> ctor : ctors) {
|
||||||
// compare parameters
|
// compare parameters
|
||||||
if (ClassUtils.isAssignable(parameterTypes, ctors[i]
|
if (ClassUtils.isAssignable(parameterTypes, ctor.getParameterTypes(), true)) {
|
||||||
.getParameterTypes(), true)) {
|
// get accessible version of constructor
|
||||||
// get accessible version of method
|
ctor = getAccessibleConstructor(ctor);
|
||||||
@SuppressWarnings("unchecked") // TODO is this OK? If so, why?
|
|
||||||
Constructor<T> ctor = getAccessibleConstructor((Constructor<T>) ctors[i]);
|
|
||||||
if (ctor != null) {
|
if (ctor != null) {
|
||||||
MemberUtils.setAccessibleWorkaround(ctor);
|
MemberUtils.setAccessibleWorkaround(ctor);
|
||||||
if (result == null
|
if (result == null
|
||||||
|| MemberUtils.compareParameterTypes(ctor
|
|| MemberUtils.compareParameterTypes(ctor.getParameterTypes(), result
|
||||||
.getParameterTypes(), result
|
|
||||||
.getParameterTypes(), parameterTypes) < 0) {
|
.getParameterTypes(), parameterTypes) < 0) {
|
||||||
result = ctor;
|
result = ctor;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue