All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.lang3.ClassUtils Maven / Gradle / Ivy

Go to download

Apache Commons Lang, a package of Java utility classes for the classes that are in java.lang's hierarchy, or are considered to be so standard as to justify existence in java.lang. The code is tested using the latest revision of the JDK for supported LTS releases: 8, 11, 17 and 21 currently. See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml Please ensure your build environment is up-to-date and kindly report any build issues.

There is a newer version: LATEST
Show newest version
/*
 * 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.lang3;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;


/**
 * 

Operates on classes without using reflection.

* *

This class handles invalid {@code null} inputs as best it can. * Each method documents its behaviour in more detail.

* *

The notion of a {@code canonical name} includes the human * readable name for the type, for example {@code int[]}. The * non-canonical method variants work with the JVM names, such as * {@code [I}.

* * @since 2.0 * @version $Id: ClassUtils.java 1145035 2011-07-11 06:09:39Z bayard $ */ public class ClassUtils { /** *

The package separator character: '.' == {@value}.

*/ public static final char PACKAGE_SEPARATOR_CHAR = '.'; /** *

The package separator String: {@code "."}.

*/ public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR); /** *

The inner class separator character: '$' == {@value}.

*/ public static final char INNER_CLASS_SEPARATOR_CHAR = '$'; /** *

The inner class separator String: {@code "$"}.

*/ public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR); /** * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}. */ private static final Map, Class> primitiveWrapperMap = new HashMap, Class>(); static { primitiveWrapperMap.put(Boolean.TYPE, Boolean.class); primitiveWrapperMap.put(Byte.TYPE, Byte.class); primitiveWrapperMap.put(Character.TYPE, Character.class); primitiveWrapperMap.put(Short.TYPE, Short.class); primitiveWrapperMap.put(Integer.TYPE, Integer.class); primitiveWrapperMap.put(Long.TYPE, Long.class); primitiveWrapperMap.put(Double.TYPE, Double.class); primitiveWrapperMap.put(Float.TYPE, Float.class); primitiveWrapperMap.put(Void.TYPE, Void.TYPE); } /** * Maps wrapper {@code Class}es to their corresponding primitive types. */ private static final Map, Class> wrapperPrimitiveMap = new HashMap, Class>(); static { for (Class primitiveClass : primitiveWrapperMap.keySet()) { Class wrapperClass = primitiveWrapperMap.get(primitiveClass); if (!primitiveClass.equals(wrapperClass)) { wrapperPrimitiveMap.put(wrapperClass, primitiveClass); } } } /** * Maps a primitive class name to its corresponding abbreviation used in array class names. */ private static final Map abbreviationMap = new HashMap(); /** * Maps an abbreviation used in array class names to corresponding primitive class name. */ private static final Map reverseAbbreviationMap = new HashMap(); /** * Add primitive type abbreviation to maps of abbreviations. * * @param primitive Canonical name of primitive type * @param abbreviation Corresponding abbreviation of primitive type */ private static void addAbbreviation(String primitive, String abbreviation) { abbreviationMap.put(primitive, abbreviation); reverseAbbreviationMap.put(abbreviation, primitive); } /** * Feed abbreviation maps */ static { addAbbreviation("int", "I"); addAbbreviation("boolean", "Z"); addAbbreviation("float", "F"); addAbbreviation("long", "J"); addAbbreviation("short", "S"); addAbbreviation("byte", "B"); addAbbreviation("double", "D"); addAbbreviation("char", "C"); } /** *

ClassUtils instances should NOT be constructed in standard programming. * Instead, the class should be used as * {@code ClassUtils.getShortClassName(cls)}.

* *

This constructor is public to permit tools that require a JavaBean * instance to operate.

*/ public ClassUtils() { super(); } // Short class name // ---------------------------------------------------------------------- /** *

Gets the class name minus the package name for an {@code Object}.

* * @param object the class to get the short name for, may be null * @param valueIfNull the value to return if null * @return the class name of the object without the package name, or the null value */ public static String getShortClassName(Object object, String valueIfNull) { if (object == null) { return valueIfNull; } return getShortClassName(object.getClass()); } /** *

Gets the class name minus the package name from a {@code Class}.

* *

Consider using the Java 5 API {@link Class#getSimpleName()} instead. * The one known difference is that this code will return {@code "Map.Entry"} while * the {@code java.lang.Class} variant will simply return {@code "Entry"}.

* * @param cls the class to get the short name for. * @return the class name without the package name or an empty string */ public static String getShortClassName(Class cls) { if (cls == null) { return StringUtils.EMPTY; } return getShortClassName(cls.getName()); } /** *

Gets the class name minus the package name from a String.

* *

The string passed in is assumed to be a class name - it is not checked.

*

Note that this method differs from Class.getSimpleName() in that this will * return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply * return {@code "Entry"}.

* * @param className the className to get the short name for * @return the class name of the class without the package name or an empty string */ public static String getShortClassName(String className) { if (className == null) { return StringUtils.EMPTY; } if (className.length() == 0) { return StringUtils.EMPTY; } StringBuilder arrayPrefix = new StringBuilder(); // Handle array encoding if (className.startsWith("[")) { while (className.charAt(0) == '[') { className = className.substring(1); arrayPrefix.append("[]"); } // Strip Object type encoding if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { className = className.substring(1, className.length() - 1); } } if (reverseAbbreviationMap.containsKey(className)) { className = reverseAbbreviationMap.get(className); } int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); int innerIdx = className.indexOf( INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1); String out = className.substring(lastDotIdx + 1); if (innerIdx != -1) { out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR); } return out + arrayPrefix; } /** *

Null-safe version of aClass.getSimpleName()

* * @param cls the class for which to get the simple name. * @return the simple class name. * @since 3.0 * @see Class#getSimpleName() */ public static String getSimpleName(Class cls) { if (cls == null) { return StringUtils.EMPTY; } return cls.getSimpleName(); } /** *

Null-safe version of aClass.getSimpleName()

* * @param object the object for which to get the simple class name. * @param valueIfNull the value to return if object is null * @return the simple class name. * @since 3.0 * @see Class#getSimpleName() */ public static String getSimpleName(Object object, String valueIfNull) { if (object == null) { return valueIfNull; } return getSimpleName(object.getClass()); } // Package name // ---------------------------------------------------------------------- /** *

Gets the package name of an {@code Object}.

* * @param object the class to get the package name for, may be null * @param valueIfNull the value to return if null * @return the package name of the object, or the null value */ public static String getPackageName(Object object, String valueIfNull) { if (object == null) { return valueIfNull; } return getPackageName(object.getClass()); } /** *

Gets the package name of a {@code Class}.

* * @param cls the class to get the package name for, may be {@code null}. * @return the package name or an empty string */ public static String getPackageName(Class cls) { if (cls == null) { return StringUtils.EMPTY; } return getPackageName(cls.getName()); } /** *

Gets the package name from a {@code String}.

* *

The string passed in is assumed to be a class name - it is not checked.

*

If the class is unpackaged, return an empty string.

* * @param className the className to get the package name for, may be {@code null} * @return the package name or an empty string */ public static String getPackageName(String className) { if (className == null || className.length() == 0) { return StringUtils.EMPTY; } // Strip array encoding while (className.charAt(0) == '[') { className = className.substring(1); } // Strip Object type encoding if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { className = className.substring(1); } int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); if (i == -1) { return StringUtils.EMPTY; } return className.substring(0, i); } // Superclasses/Superinterfaces // ---------------------------------------------------------------------- /** *

Gets a {@code List} of superclasses for the given class.

* * @param cls the class to look up, may be {@code null} * @return the {@code List} of superclasses in order going up from this one * {@code null} if null input */ public static List> getAllSuperclasses(Class cls) { if (cls == null) { return null; } List> classes = new ArrayList>(); Class superclass = cls.getSuperclass(); while (superclass != null) { classes.add(superclass); superclass = superclass.getSuperclass(); } return classes; } /** *

Gets a {@code List} of all interfaces implemented by the given * class and its superclasses.

* *

The order is determined by looking through each interface in turn as * declared in the source file and following its hierarchy up. Then each * superclass is considered in the same way. Later duplicates are ignored, * so the order is maintained.

* * @param cls the class to look up, may be {@code null} * @return the {@code List} of interfaces in order, * {@code null} if null input */ public static List> getAllInterfaces(Class cls) { if (cls == null) { return null; } LinkedHashSet> interfacesFound = new LinkedHashSet>(); getAllInterfaces(cls, interfacesFound); return new ArrayList>(interfacesFound); } /** * Get the interfaces for the specified class. * * @param cls the class to look up, may be {@code null} * @param interfacesFound the {@code Set} of interfaces for the class */ private static void getAllInterfaces(Class cls, HashSet> interfacesFound) { while (cls != null) { Class[] interfaces = cls.getInterfaces(); for (Class i : interfaces) { if (interfacesFound.add(i)) { getAllInterfaces(i, interfacesFound); } } cls = cls.getSuperclass(); } } // Convert list // ---------------------------------------------------------------------- /** *

Given a {@code List} of class names, this method converts them into classes.

* *

A new {@code List} is returned. If the class name cannot be found, {@code null} * is stored in the {@code List}. If the class name in the {@code List} is * {@code null}, {@code null} is stored in the output {@code List}.

* * @param classNames the classNames to change * @return a {@code List} of Class objects corresponding to the class names, * {@code null} if null input * @throws ClassCastException if classNames contains a non String entry */ public static List> convertClassNamesToClasses(List classNames) { if (classNames == null) { return null; } List> classes = new ArrayList>(classNames.size()); for (String className : classNames) { try { classes.add(Class.forName(className)); } catch (Exception ex) { classes.add(null); } } return classes; } /** *

Given a {@code List} of {@code Class} objects, this method converts * them into class names.

* *

A new {@code List} is returned. {@code null} objects will be copied into * the returned list as {@code null}.

* * @param classes the classes to change * @return a {@code List} of class names corresponding to the Class objects, * {@code null} if null input * @throws ClassCastException if {@code classes} contains a non-{@code Class} entry */ public static List convertClassesToClassNames(List> classes) { if (classes == null) { return null; } List classNames = new ArrayList(classes.size()); for (Class cls : classes) { if (cls == null) { classNames.add(null); } else { classNames.add(cls.getName()); } } return classNames; } // Is assignable // ---------------------------------------------------------------------- /** *

Checks if an array of Classes can be assigned to another array of Classes.

* *

This method calls {@link #isAssignable(Class, Class) isAssignable} for each * Class pair in the input arrays. It can be used to check if a set of arguments * (the first parameter) are suitably compatible with a set of method parameter types * (the second parameter).

* *

Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this * method takes into account widenings of primitive classes and * {@code null}s.

* *

Primitive widenings allow an int to be assigned to a {@code long}, * {@code float} or {@code double}. This method returns the correct * result for these cases.

* *

{@code Null} may be assigned to any reference type. This method will * return {@code true} if {@code null} is passed in and the toClass is * non-primitive.

* *

Specifically, this method tests whether the type represented by the * specified {@code Class} parameter can be converted to the type * represented by this {@code Class} object via an identity conversion * widening primitive or widening reference conversion. See * The Java Language Specification, * sections 5.1.1, 5.1.2 and 5.1.4 for details.

* *

Since Lang 3.0, this method will default behavior for * calculating assignability between primitive and wrapper types corresponding * to the running Java version; i.e. autoboxing will be the default * behavior in VMs running Java versions >= 1.5.

* * @param classArray the array of Classes to check, may be {@code null} * @param toClassArray the array of Classes to try to assign into, may be {@code null} * @return {@code true} if assignment possible */ public static boolean isAssignable(Class[] classArray, Class... toClassArray) { return isAssignable(classArray, toClassArray, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5)); } /** *

Checks if an array of Classes can be assigned to another array of Classes.

* *

This method calls {@link #isAssignable(Class, Class) isAssignable} for each * Class pair in the input arrays. It can be used to check if a set of arguments * (the first parameter) are suitably compatible with a set of method parameter types * (the second parameter).

* *

Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this * method takes into account widenings of primitive classes and * {@code null}s.

* *

Primitive widenings allow an int to be assigned to a {@code long}, * {@code float} or {@code double}. This method returns the correct * result for these cases.

* *

{@code Null} may be assigned to any reference type. This method will * return {@code true} if {@code null} is passed in and the toClass is * non-primitive.

* *

Specifically, this method tests whether the type represented by the * specified {@code Class} parameter can be converted to the type * represented by this {@code Class} object via an identity conversion * widening primitive or widening reference conversion. See * The Java Language Specification, * sections 5.1.1, 5.1.2 and 5.1.4 for details.

* * @param classArray the array of Classes to check, may be {@code null} * @param toClassArray the array of Classes to try to assign into, may be {@code null} * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers * @return {@code true} if assignment possible */ public static boolean isAssignable(Class[] classArray, Class[] toClassArray, boolean autoboxing) { if (ArrayUtils.isSameLength(classArray, toClassArray) == false) { return false; } if (classArray == null) { classArray = ArrayUtils.EMPTY_CLASS_ARRAY; } if (toClassArray == null) { toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY; } for (int i = 0; i < classArray.length; i++) { if (isAssignable(classArray[i], toClassArray[i], autoboxing) == false) { return false; } } return true; } /** *

Checks if one {@code Class} can be assigned to a variable of * another {@code Class}.

* *

Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, * this method takes into account widenings of primitive classes and * {@code null}s.

* *

Primitive widenings allow an int to be assigned to a long, float or * double. This method returns the correct result for these cases.

* *

{@code Null} may be assigned to any reference type. This method * will return {@code true} if {@code null} is passed in and the * toClass is non-primitive.

* *

Specifically, this method tests whether the type represented by the * specified {@code Class} parameter can be converted to the type * represented by this {@code Class} object via an identity conversion * widening primitive or widening reference conversion. See * The Java Language Specification, * sections 5.1.1, 5.1.2 and 5.1.4 for details.

* *

Since Lang 3.0, this method will default behavior for * calculating assignability between primitive and wrapper types corresponding * to the running Java version; i.e. autoboxing will be the default * behavior in VMs running Java versions >= 1.5.

* * @param cls the Class to check, may be null * @param toClass the Class to try to assign into, returns false if null * @return {@code true} if assignment possible */ public static boolean isAssignable(Class cls, Class toClass) { return isAssignable(cls, toClass, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5)); } /** *

Checks if one {@code Class} can be assigned to a variable of * another {@code Class}.

* *

Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, * this method takes into account widenings of primitive classes and * {@code null}s.

* *

Primitive widenings allow an int to be assigned to a long, float or * double. This method returns the correct result for these cases.

* *

{@code Null} may be assigned to any reference type. This method * will return {@code true} if {@code null} is passed in and the * toClass is non-primitive.

* *

Specifically, this method tests whether the type represented by the * specified {@code Class} parameter can be converted to the type * represented by this {@code Class} object via an identity conversion * widening primitive or widening reference conversion. See * The Java Language Specification, * sections 5.1.1, 5.1.2 and 5.1.4 for details.

* * @param cls the Class to check, may be null * @param toClass the Class to try to assign into, returns false if null * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers * @return {@code true} if assignment possible */ public static boolean isAssignable(Class cls, Class toClass, boolean autoboxing) { if (toClass == null) { return false; } // have to check for null, as isAssignableFrom doesn't if (cls == null) { return !(toClass.isPrimitive()); } //autoboxing: if (autoboxing) { if (cls.isPrimitive() && !toClass.isPrimitive()) { cls = primitiveToWrapper(cls); if (cls == null) { return false; } } if (toClass.isPrimitive() && !cls.isPrimitive()) { cls = wrapperToPrimitive(cls); if (cls == null) { return false; } } } if (cls.equals(toClass)) { return true; } if (cls.isPrimitive()) { if (toClass.isPrimitive() == false) { return false; } if (Integer.TYPE.equals(cls)) { return Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass); } if (Long.TYPE.equals(cls)) { return Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass); } if (Boolean.TYPE.equals(cls)) { return false; } if (Double.TYPE.equals(cls)) { return false; } if (Float.TYPE.equals(cls)) { return Double.TYPE.equals(toClass); } if (Character.TYPE.equals(cls)) { return Integer.TYPE.equals(toClass) || Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass); } if (Short.TYPE.equals(cls)) { return Integer.TYPE.equals(toClass) || Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass); } if (Byte.TYPE.equals(cls)) { return Short.TYPE.equals(toClass) || Integer.TYPE.equals(toClass) || Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass); } // should never get here return false; } return toClass.isAssignableFrom(cls); } /** *

Converts the specified primitive Class object to its corresponding * wrapper Class object.

* *

NOTE: From v2.2, this method handles {@code Void.TYPE}, * returning {@code Void.TYPE}.

* * @param cls the class to convert, may be null * @return the wrapper class for {@code cls} or {@code cls} if * {@code cls} is not a primitive. {@code null} if null input. * @since 2.1 */ public static Class primitiveToWrapper(Class cls) { Class convertedClass = cls; if (cls != null && cls.isPrimitive()) { convertedClass = primitiveWrapperMap.get(cls); } return convertedClass; } /** *

Converts the specified array of primitive Class objects to an array of * its corresponding wrapper Class objects.

* * @param classes the class array to convert, may be null or empty * @return an array which contains for each given class, the wrapper class or * the original class if class is not a primitive. {@code null} if null input. * Empty array if an empty array passed in. * @since 2.1 */ public static Class[] primitivesToWrappers(Class... classes) { if (classes == null) { return null; } if (classes.length == 0) { return classes; } Class[] convertedClasses = new Class[classes.length]; for (int i = 0; i < classes.length; i++) { convertedClasses[i] = primitiveToWrapper(classes[i]); } return convertedClasses; } /** *

Converts the specified wrapper class to its corresponding primitive * class.

* *

This method is the counter part of {@code primitiveToWrapper()}. * If the passed in class is a wrapper class for a primitive type, this * primitive type will be returned (e.g. {@code Integer.TYPE} for * {@code Integer.class}). For other classes, or if the parameter is * null, the return value is null.

* * @param cls the class to convert, may be null * @return the corresponding primitive type if {@code cls} is a * wrapper class, null otherwise * @see #primitiveToWrapper(Class) * @since 2.4 */ public static Class wrapperToPrimitive(Class cls) { return wrapperPrimitiveMap.get(cls); } /** *

Converts the specified array of wrapper Class objects to an array of * its corresponding primitive Class objects.

* *

This method invokes {@code wrapperToPrimitive()} for each element * of the passed in array.

* * @param classes the class array to convert, may be null or empty * @return an array which contains for each given class, the primitive class or * null if the original class is not a wrapper class. {@code null} if null input. * Empty array if an empty array passed in. * @see #wrapperToPrimitive(Class) * @since 2.4 */ public static Class[] wrappersToPrimitives(Class... classes) { if (classes == null) { return null; } if (classes.length == 0) { return classes; } Class[] convertedClasses = new Class[classes.length]; for (int i = 0; i < classes.length; i++) { convertedClasses[i] = wrapperToPrimitive(classes[i]); } return convertedClasses; } // Inner class // ---------------------------------------------------------------------- /** *

Is the specified class an inner class or static nested class.

* * @param cls the class to check, may be null * @return {@code true} if the class is an inner or static nested class, * false if not or {@code null} */ public static boolean isInnerClass(Class cls) { return cls != null && cls.getEnclosingClass() != null; } // Class loading // ---------------------------------------------------------------------- /** * Returns the class represented by {@code className} using the * {@code classLoader}. This implementation supports the syntaxes * "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". * * @param classLoader the class loader to use to load the class * @param className the class name * @param initialize whether the class must be initialized * @return the class represented by {@code className} using the {@code classLoader} * @throws ClassNotFoundException if the class is not found */ public static Class getClass( ClassLoader classLoader, String className, boolean initialize) throws ClassNotFoundException { try { Class clazz; if (abbreviationMap.containsKey(className)) { String clsName = "[" + abbreviationMap.get(className); clazz = Class.forName(clsName, initialize, classLoader).getComponentType(); } else { clazz = Class.forName(toCanonicalName(className), initialize, classLoader); } return clazz; } catch (ClassNotFoundException ex) { // allow path separators (.) as inner class name separators int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); if (lastDotIndex != -1) { try { return getClass(classLoader, className.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1), initialize); } catch (ClassNotFoundException ex2) { // NOPMD // ignore exception } } throw ex; } } /** * Returns the (initialized) class represented by {@code className} * using the {@code classLoader}. This implementation supports * the syntaxes "{@code java.util.Map.Entry[]}", * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", * and "{@code [Ljava.util.Map$Entry;}". * * @param classLoader the class loader to use to load the class * @param className the class name * @return the class represented by {@code className} using the {@code classLoader} * @throws ClassNotFoundException if the class is not found */ public static Class getClass(ClassLoader classLoader, String className) throws ClassNotFoundException { return getClass(classLoader, className, true); } /** * Returns the (initialized) class represented by {@code className} * using the current thread's context class loader. This implementation * supports the syntaxes "{@code java.util.Map.Entry[]}", * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", * and "{@code [Ljava.util.Map$Entry;}". * * @param className the class name * @return the class represented by {@code className} using the current thread's context class loader * @throws ClassNotFoundException if the class is not found */ public static Class getClass(String className) throws ClassNotFoundException { return getClass(className, true); } /** * Returns the class represented by {@code className} using the * current thread's context class loader. This implementation supports the * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". * * @param className the class name * @param initialize whether the class must be initialized * @return the class represented by {@code className} using the current thread's context class loader * @throws ClassNotFoundException if the class is not found */ public static Class getClass(String className, boolean initialize) throws ClassNotFoundException { ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL; return getClass(loader, className, initialize ); } // Public method // ---------------------------------------------------------------------- /** *

Returns the desired Method much like {@code Class.getMethod}, however * it ensures that the returned Method is from a public class or interface and not * from an anonymous inner class. This means that the Method is invokable and * doesn't fall foul of Java bug * 4071957). * *

Set set = Collections.unmodifiableSet(...);
     *  Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty",  new Class[0]);
     *  Object result = method.invoke(set, new Object[]);
*

* * @param cls the class to check, not null * @param methodName the name of the method * @param parameterTypes the list of parameters * @return the method * @throws NullPointerException if the class is null * @throws SecurityException if a a security violation occured * @throws NoSuchMethodException if the method is not found in the given class * or if the metothod doen't conform with the requirements */ public static Method getPublicMethod(Class cls, String methodName, Class... parameterTypes) throws SecurityException, NoSuchMethodException { Method declaredMethod = cls.getMethod(methodName, parameterTypes); if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) { return declaredMethod; } List> candidateClasses = new ArrayList>(); candidateClasses.addAll(getAllInterfaces(cls)); candidateClasses.addAll(getAllSuperclasses(cls)); for (Class candidateClass : candidateClasses) { if (!Modifier.isPublic(candidateClass.getModifiers())) { continue; } Method candidateMethod; try { candidateMethod = candidateClass.getMethod(methodName, parameterTypes); } catch (NoSuchMethodException ex) { continue; } if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) { return candidateMethod; } } throw new NoSuchMethodException("Can't find a public method for " + methodName + " " + ArrayUtils.toString(parameterTypes)); } // ---------------------------------------------------------------------- /** * Converts a class name to a JLS style class name. * * @param className the class name * @return the converted name */ private static String toCanonicalName(String className) { className = StringUtils.deleteWhitespace(className); if (className == null) { throw new NullPointerException("className must not be null."); } else if (className.endsWith("[]")) { StringBuilder classNameBuffer = new StringBuilder(); while (className.endsWith("[]")) { className = className.substring(0, className.length() - 2); classNameBuffer.append("["); } String abbreviation = abbreviationMap.get(className); if (abbreviation != null) { classNameBuffer.append(abbreviation); } else { classNameBuffer.append("L").append(className).append(";"); } className = classNameBuffer.toString(); } return className; } /** *

Converts an array of {@code Object} in to an array of {@code Class} objects. * If any of these objects is null, a null element will be inserted into the array.

* *

This method returns {@code null} for a {@code null} input array.

* * @param array an {@code Object} array * @return a {@code Class} array, {@code null} if null array input * @since 2.4 */ public static Class[] toClass(Object... array) { if (array == null) { return null; } else if (array.length == 0) { return ArrayUtils.EMPTY_CLASS_ARRAY; } Class[] classes = new Class[array.length]; for (int i = 0; i < array.length; i++) { classes[i] = array[i] == null ? null : array[i].getClass(); } return classes; } // Short canonical name // ---------------------------------------------------------------------- /** *

Gets the canonical name minus the package name for an {@code Object}.

* * @param object the class to get the short name for, may be null * @param valueIfNull the value to return if null * @return the canonical name of the object without the package name, or the null value * @since 2.4 */ public static String getShortCanonicalName(Object object, String valueIfNull) { if (object == null) { return valueIfNull; } return getShortCanonicalName(object.getClass().getName()); } /** *

Gets the canonical name minus the package name from a {@code Class}.

* * @param cls the class to get the short name for. * @return the canonical name without the package name or an empty string * @since 2.4 */ public static String getShortCanonicalName(Class cls) { if (cls == null) { return StringUtils.EMPTY; } return getShortCanonicalName(cls.getName()); } /** *

Gets the canonical name minus the package name from a String.

* *

The string passed in is assumed to be a canonical name - it is not checked.

* * @param canonicalName the class name to get the short name for * @return the canonical name of the class without the package name or an empty string * @since 2.4 */ public static String getShortCanonicalName(String canonicalName) { return ClassUtils.getShortClassName(getCanonicalName(canonicalName)); } // Package name // ---------------------------------------------------------------------- /** *

Gets the package name from the canonical name of an {@code Object}.

* * @param object the class to get the package name for, may be null * @param valueIfNull the value to return if null * @return the package name of the object, or the null value * @since 2.4 */ public static String getPackageCanonicalName(Object object, String valueIfNull) { if (object == null) { return valueIfNull; } return getPackageCanonicalName(object.getClass().getName()); } /** *

Gets the package name from the canonical name of a {@code Class}.

* * @param cls the class to get the package name for, may be {@code null}. * @return the package name or an empty string * @since 2.4 */ public static String getPackageCanonicalName(Class cls) { if (cls == null) { return StringUtils.EMPTY; } return getPackageCanonicalName(cls.getName()); } /** *

Gets the package name from the canonical name.

* *

The string passed in is assumed to be a canonical name - it is not checked.

*

If the class is unpackaged, return an empty string.

* * @param canonicalName the canonical name to get the package name for, may be {@code null} * @return the package name or an empty string * @since 2.4 */ public static String getPackageCanonicalName(String canonicalName) { return ClassUtils.getPackageName(getCanonicalName(canonicalName)); } /** *

Converts a given name of class into canonical format. * If name of class is not a name of array class it returns * unchanged name.

*

Example: *

    *
  • {@code getCanonicalName("[I") = "int[]"}
  • *
  • {@code getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"}
  • *
  • {@code getCanonicalName("java.lang.String") = "java.lang.String"}
  • *
*

* * @param className the name of class * @return canonical form of class name * @since 2.4 */ private static String getCanonicalName(String className) { className = StringUtils.deleteWhitespace(className); if (className == null) { return null; } else { int dim = 0; while (className.startsWith("[")) { dim++; className = className.substring(1); } if (dim < 1) { return className; } else { if (className.startsWith("L")) { className = className.substring( 1, className.endsWith(";") ? className.length() - 1 : className.length()); } else { if (className.length() > 0) { className = reverseAbbreviationMap.get(className.substring(0, 1)); } } StringBuilder canonicalClassNameBuffer = new StringBuilder(className); for (int i = 0; i < dim; i++) { canonicalClassNameBuffer.append("[]"); } return canonicalClassNameBuffer.toString(); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy