/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ClassUtils;
Utility reflection methods focussed on constructors, modelled after MethodUtils
.
Known Limitations
Accessing Public Constructors In A Default
Access Superclass
There is an issue when invoking public constructors
contained in a default access superclass. Reflection locates these
constructors fine and correctly assigns them as public. However, an
IllegalAccessException
is thrown if the constructors is
invoked.
ConstructorUtils
contains a workaround for this situation. It
will attempt to call setAccessible
on this constructor. If this
call succeeds, then the method can be invoked as normal. This call will only
succeed when the application has sufficient security privilages. If this call
fails then a warning will be logged and the method may fail.
Author: Apache Software Foundation, Craig R. McClanahan, Ralph Schaer, Chris Audley, Rey Francois, Gregor Rayman, Jan Sorensen, Robert Burrell Donkin, Rodney Waldhoff Since: 2.5 Version: $Id: ConstructorUtils.java 1056863 2011-01-09 02:00:25Z niallp $
/**
* <p> Utility reflection methods focussed on constructors, modelled after
* {@link MethodUtils}. </p>
*
* <h3>Known Limitations</h3> <h4>Accessing Public Constructors In A Default
* Access Superclass</h4> <p>There is an issue when invoking public constructors
* contained in a default access superclass. Reflection locates these
* constructors fine and correctly assigns them as public. However, an
* <code>IllegalAccessException</code> is thrown if the constructors is
* invoked.</p>
*
* <p><code>ConstructorUtils</code> contains a workaround for this situation. It
* will attempt to call <code>setAccessible</code> on this constructor. If this
* call succeeds, then the method can be invoked as normal. This call will only
* succeed when the application has sufficient security privilages. If this call
* fails then a warning will be logged and the method may fail.</p>
*
* @author Apache Software Foundation
* @author Craig R. McClanahan
* @author Ralph Schaer
* @author Chris Audley
* @author Rey Francois
* @author Gregor Rayman
* @author Jan Sorensen
* @author Robert Burrell Donkin
* @author Rodney Waldhoff
* @since 2.5
* @version $Id: ConstructorUtils.java 1056863 2011-01-09 02:00:25Z niallp $
*/
public class ConstructorUtils {
ConstructorUtils instances should NOT be constructed in standard
programming. Instead, the class should be used as
ConstructorUtils.invokeConstructor(cls, args)
.
This constructor is public to permit tools that require a JavaBean
instance to operate.
/**
* <p>ConstructorUtils instances should NOT be constructed in standard
* programming. Instead, the class should be used as
* <code>ConstructorUtils.invokeConstructor(cls, args)</code>.</p>
*
* <p>This constructor is public to permit tools that require a JavaBean
* instance to operate.</p>
*/
public ConstructorUtils() {
super();
}
Returns new instance of klazz
created using the actual
arguments args
. The formal parameter types are inferred from
the actual values of args
. See invokeExactConstructor(Class, Object[], Class[])
for more details.
The signatures should be assignment compatible.
Params: - cls – the class to be constructed.
- arg – the actual argument
Throws: - NoSuchMethodException – If the constructor cannot be found
- IllegalAccessException – If an error occurs accessing the constructor
- InvocationTargetException – If an error occurs invoking the constructor
- InstantiationException – If an error occurs instantiating the class
See Also: Returns: new instance of klazz
/**
* <p>Returns new instance of <code>klazz</code> created using the actual
* arguments <code>args</code>. The formal parameter types are inferred from
* 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>
*
* @param cls the class to be constructed.
* @param arg the actual argument
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the constructor
* @throws InvocationTargetException If an error occurs invoking the constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
public static Object invokeConstructor(Class cls, Object arg)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
return invokeConstructor(cls, new Object[] { arg });
}
Returns new instance of klazz
created using the actual
arguments args
. The formal parameter types are inferred from
the actual values of args
. See invokeExactConstructor(Class, Object[], Class[])
for more details.
The signatures should be assignment compatible.
Params: - cls – the class to be constructed.
- args – actual argument array
Throws: - NoSuchMethodException – If the constructor cannot be found
- IllegalAccessException – If an error occurs accessing the
constructor
- InvocationTargetException – If an error occurs invoking the
constructor
- InstantiationException – If an error occurs instantiating the class
See Also: Returns: new instance of klazz
/**
* <p>Returns new instance of <code>klazz</code> created using the actual
* arguments <code>args</code>. The formal parameter types are inferred from
* 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>
*
* @param cls the class to be constructed.
* @param args actual argument array
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the
* constructor
* @throws InvocationTargetException If an error occurs invoking the
* constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeConstructor(java.lang.Class, java.lang.Object[],
* java.lang.Class[])
*/
public static Object invokeConstructor(Class cls, Object[] args)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InstantiationException {
if (null == args) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Class parameterTypes[] = new Class[args.length];
for (int i = 0; i < args.length; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeConstructor(cls, args, parameterTypes);
}
Returns new instance of klazz
created using constructor
with signature parameterTypes
and actual arguments
args
.
The signatures should be assignment compatible.
Params: - cls – the class to be constructed.
- args – actual argument array
- parameterTypes – parameter types array
Throws: - NoSuchMethodException – if matching constructor cannot be found
- IllegalAccessException – thrown on the constructor's invocation
- InvocationTargetException – thrown on the constructor's invocation
- InstantiationException – thrown on the constructor's invocation
See Also: Returns: new instance of klazz
/**
* <p>Returns new instance of <code>klazz</code> created using constructor
* with signature <code>parameterTypes</code> and actual arguments
* <code>args</code>.</p>
*
* <p>The signatures should be assignment compatible.</p>
*
* @param cls the class to be constructed.
* @param args actual argument array
* @param parameterTypes parameter types array
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException if matching constructor cannot be found
* @throws IllegalAccessException thrown on the constructor's invocation
* @throws InvocationTargetException thrown on the constructor's invocation
* @throws InstantiationException thrown on the constructor's invocation
* @see Constructor#newInstance
*/
public static Object invokeConstructor(Class cls, Object[] args, Class[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InstantiationException {
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Constructor ctor = getMatchingAccessibleConstructor(cls, parameterTypes);
if (null == ctor) {
throw new NoSuchMethodException("No such accessible constructor on object: "
+ cls.getName());
}
return ctor.newInstance(args);
}
Returns new instance of klazz
created using the actual
arguments args
. The formal parameter types are inferred from
the actual values of args
. See invokeExactConstructor(Class, Object[], Class[])
for more details.
The signatures should match exactly.
Params: - cls – the class to be constructed.
- arg – the actual argument
Throws: - NoSuchMethodException – If the constructor cannot be found
- IllegalAccessException – If an error occurs accessing the constructor
- InvocationTargetException – If an error occurs invoking the constructor
- InstantiationException – If an error occurs instantiating the class
See Also: Returns: new instance of klazz
/**
* <p>Returns new instance of <code>klazz</code> created using the actual
* arguments <code>args</code>. The formal parameter types are inferred from
* the actual values of <code>args</code>. See
* {@link #invokeExactConstructor(Class, Object[], Class[])} for more
* details.</p>
*
* <p>The signatures should match exactly.</p>
*
* @param cls the class to be constructed.
* @param arg the actual argument
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the constructor
* @throws InvocationTargetException If an error occurs invoking the constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
*/
public static Object invokeExactConstructor(Class cls, Object arg)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
return invokeExactConstructor(cls, new Object[] { arg });
}
Returns new instance of klazz
created using the actual
arguments args
. The formal parameter types are inferred from
the actual values of args
. See invokeExactConstructor(Class, Object[], Class[])
for more details.
The signatures should match exactly.
Params: - cls – the class to be constructed.
- args – actual argument array
Throws: - NoSuchMethodException – If the constructor cannot be found
- IllegalAccessException – If an error occurs accessing the
constructor
- InvocationTargetException – If an error occurs invoking the
constructor
- InstantiationException – If an error occurs instantiating the class
See Also: Returns: new instance of klazz
/**
* <p>Returns new instance of <code>klazz</code> created using the actual
* arguments <code>args</code>. The formal parameter types are inferred from
* the actual values of <code>args</code>. See
* {@link #invokeExactConstructor(Class, Object[], Class[])} for more
* details.</p>
*
* <p>The signatures should match exactly.</p>
*
* @param cls the class to be constructed.
* @param args actual argument array
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException If the constructor cannot be found
* @throws IllegalAccessException If an error occurs accessing the
* constructor
* @throws InvocationTargetException If an error occurs invoking the
* constructor
* @throws InstantiationException If an error occurs instantiating the class
*
* @see #invokeExactConstructor(java.lang.Class, java.lang.Object[],
* java.lang.Class[])
*/
public static Object invokeExactConstructor(Class cls, Object[] args)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InstantiationException {
if (null == args) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class parameterTypes[] = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeExactConstructor(cls, args, parameterTypes);
}
Returns new instance of klazz
created using constructor
with signature parameterTypes
and actual arguments
args
.
The signatures should match exactly.
Params: - cls – the class to be constructed.
- args – actual argument array
- parameterTypes – parameter types array
Throws: - NoSuchMethodException – if matching constructor cannot be found
- IllegalAccessException – thrown on the constructor's invocation
- InvocationTargetException – thrown on the constructor's invocation
- InstantiationException – thrown on the constructor's invocation
See Also: Returns: new instance of klazz
/**
* <p>Returns new instance of <code>klazz</code> created using constructor
* with signature <code>parameterTypes</code> and actual arguments
* <code>args</code>.</p>
*
* <p>The signatures should match exactly.</p>
*
* @param cls the class to be constructed.
* @param args actual argument array
* @param parameterTypes parameter types array
* @return new instance of <code>klazz</code>
*
* @throws NoSuchMethodException if matching constructor cannot be found
* @throws IllegalAccessException thrown on the constructor's invocation
* @throws InvocationTargetException thrown on the constructor's invocation
* @throws InstantiationException thrown on the constructor's invocation
* @see Constructor#newInstance
*/
public static Object invokeExactConstructor(Class cls, Object[] args,
Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
Constructor ctor = getAccessibleConstructor(cls, parameterTypes);
if (null == ctor) {
throw new NoSuchMethodException("No such accessible constructor on object: "
+ cls.getName());
}
return ctor.newInstance(args);
}
Returns a constructor with single argument.
Params: - cls – the class to be constructed
- parameterType – The constructor parameter type
See Also: Returns: null if matching accessible constructor can not be found.
/**
* Returns a constructor with single argument.
* @param cls the class to be constructed
* @param parameterType The constructor parameter type
* @return null if matching accessible constructor can not be found.
* @see Class#getConstructor
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
*/
public static Constructor getAccessibleConstructor(Class cls,
Class parameterType) {
return getAccessibleConstructor(cls, new Class[] { parameterType });
}
Returns a constructor given a class and signature.
Params: - cls – the class to be constructed
- parameterTypes – the parameter array
See Also: Returns: null if matching accessible constructor can not be found
/**
* Returns a constructor given a class and signature.
* @param cls the class to be constructed
* @param parameterTypes the parameter array
* @return null if matching accessible constructor can not be found
* @see Class#getConstructor
* @see #getAccessibleConstructor(java.lang.reflect.Constructor)
*/
public static Constructor getAccessibleConstructor(Class cls,
Class[] parameterTypes) {
try {
return getAccessibleConstructor(cls.getConstructor(parameterTypes));
} catch (NoSuchMethodException e) {
return (null);
}
}
Returns accessible version of the given constructor.
Params: - ctor – prototype constructor object.
See Also: Returns: null
if accessible constructor can not be found.
/**
* Returns accessible version of the given constructor.
* @param ctor prototype constructor object.
* @return <code>null</code> if accessible constructor can not be found.
* @see java.lang.SecurityManager
*/
public static Constructor getAccessibleConstructor(Constructor ctor) {
return MemberUtils.isAccessible(ctor)
&& Modifier.isPublic(ctor.getDeclaringClass().getModifiers()) ? ctor : null;
}
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.
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.
Params: - cls – find constructor for this class
- parameterTypes – find method with compatible parameters
Returns: a valid Constructor object. If there's no matching constructor,
returns null
.
/**
* <p>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>
*
* <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.</p>
*
* @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();
// return best match:
for (int i = 0; i < ctors.length; i++) {
// compare parameters
if (ClassUtils.isAssignable(parameterTypes, ctors[i].getParameterTypes(), true)) {
// get accessible version of constructor
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;
}
}