From 779faeb5ee9277aa9f329519c698b7867031ea43 Mon Sep 17 00:00:00 2001
From: JingMatrix
+ * This method returns an empty array for a {@code null} input array.
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ * This method returns a default array for a {@code null} input array.
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ * If the input array is {@code null}, {@code 0} is returned.
+ *
+ * Any multi-dimensional aspects of the arrays are ignored.
+ *
+ * Multi-dimensional arrays are handled correctly, including
+ * multi-dimensional primitive arrays.
+ *
+ * The format is that of Java source code, for example {@code {a,b}}.
+ *
+ * Multi-dimensional arrays are handled correctly, including
+ * multi-dimensional primitive arrays.
+ *
+ * The format is that of Java source code, for example {@code {a,b}}.
+ *
+ * This class handles invalid {@code null} inputs as best it can. Each method documents its behavior 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}.
+ *
+ * A new {@link List} is returned. {@code null} objects will be copied into the returned list as {@code null}.
+ *
+ * A new {@link List} is returned. If the class name cannot be found, {@code null} is stored in the {@link List}. If the
+ * class name in the {@link List} is {@code null}, {@code null} is stored in the output {@link List}.
+ *
+ * The string passed in is assumed to be a class name - it is not checked.
+ *
+ * The abbreviation algorithm will shorten the class name, usually without significant loss of meaning.
+ *
+ * The abbreviated class name will always include the complete package hierarchy. If enough space is available,
+ * rightmost sub-packages will be displayed in full length. The abbreviated package names will be shortened to a single
+ * character.
+ *
+ * Only package names are shortened, the class simple name remains untouched. (See examples.)
+ *
+ * The result will be longer than the desired length only if all the package names shortened to a single character plus
+ * the class simple name with the separating dots together are longer than the desired length. In other words, when the
+ * class name cannot be shortened to the desired length.
+ *
+ * If the class name can be shortened then the final length will be at most {@code lengthHint} characters.
+ *
+ * If the {@code lengthHint} is zero or negative then the method throws exception. If you want to achieve the shortest
+ * possible version then use {@code 1} as a {@code lengthHint}.
+ *
+ * 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.
+ *
+ * The method does not change the {@code $} separators in case the class is inner class.
+ *
+ * Example:
+ *
+ * ArrayUtils.getLength(null) = 0
+ * ArrayUtils.getLength([]) = 0
+ * ArrayUtils.getLength([null]) = 1
+ * ArrayUtils.getLength([true, false]) = 2
+ * ArrayUtils.getLength([1, 2, 3]) = 3
+ * ArrayUtils.getLength(["a", "b", "c"]) = 3
+ *
+ *
+ * @param array the array to retrieve the length from, may be null
+ * @return The length of the array, or {@code 0} if the array is {@code null}
+ * @throws IllegalArgumentException if the object argument is not an array.
+ * @since 2.1
+ */
+ public static int getLength(final Object array) {
+ return array != null ? Array.getLength(array) : 0;
+ }
+
+ /**
+ * Checks whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ *
+ *
+ * @param className the className to get the abbreviated name for, may be {@code null}
+ * @param lengthHint the desired length of the abbreviated name
+ * @return the abbreviated name or an empty string if the specified class name is {@code null} or empty string. The
+ * abbreviated name may be longer than the desired length if it cannot be abbreviated to the desired length.
+ * @throws IllegalArgumentException if {@code len <= 0}
+ * @since 3.4
+ */
+ public static String getAbbreviatedName(final String className, final int lengthHint) {
+ if (lengthHint <= 0) {
+ throw new IllegalArgumentException("len must be > 0");
+ }
+ if (className == null) {
+ return StringUtils.EMPTY;
+ }
+ if (className.length() <= lengthHint) {
+ return className;
+ }
+ final char[] abbreviated = className.toCharArray();
+ int target = 0;
+ int source = 0;
+ while (source < abbreviated.length) {
+ // copy the next part
+ int runAheadTarget = target;
+ while (source < abbreviated.length && abbreviated[source] != '.') {
+ abbreviated[runAheadTarget++] = abbreviated[source++];
+ }
+
+ ++target;
+ if (useFull(runAheadTarget, source, abbreviated.length, lengthHint) || target > runAheadTarget) {
+ target = runAheadTarget;
+ }
+
+ // copy the '.' unless it was the last part
+ if (source < abbreviated.length) {
+ abbreviated[target++] = abbreviated[source++];
+ }
+ }
+ return new String(abbreviated, 0, target);
+ }
+
+ /**
+ * Gets a {@link List} of all interfaces implemented by the given class and its superclasses.
+ *
+ *
+ *
+ * className
+ * len
+ * return
+ *
+ *
+ * null
+ * 1
+ * ""
+ *
+ *
+ * "java.lang.String"
+ * 5
+ * "j.l.String"
+ *
+ *
+ * "java.lang.String"
+ * 15
+ * "j.lang.String"
+ *
+ *
+ * "java.lang.String"
+ * 30
+ * "java.lang.String"
+ *
+ *
+ * "org.apache.commons.lang3.ClassUtils"
+ * 18
+ * "o.a.c.l.ClassUtils"
+ *
+ *
+ *
+ * The string passed in is assumed to be a class name - it is not checked. + *
+ *+ * If the class is in the default package, return an empty string. + *
+ * + * @param name the 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(final String name) { + return getPackageName(getCanonicalName(name)); + } + + /** + * Gets the package name of a {@link 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(final Class> cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getPackageName(cls.getName()); + } + + /** + * Gets the package name of an {@link 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(final Object object, final String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getPackageName(object.getClass()); + } + + /** + * Gets the package name from a {@link 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 (StringUtils.isEmpty(className)) { + 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); + } + + final int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); + if (i == -1) { + return StringUtils.EMPTY; + } + return className.substring(0, i); + } + + /** + * Gets the primitive class for the given class name, for example "byte". + * + * @param className the primitive class for the given class name. + * @return the primitive class. + */ + static Class> getPrimitiveClass(final String className) { + return namePrimitiveMap.get(className); + } + + /** + * 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 security violation occurred
+ * @throws NoSuchMethodException if the method is not found in the given class or if the method doesn't conform with the
+ * requirements
+ */
+ public static Method getPublicMethod(final Class> cls, final String methodName, final Class>... parameterTypes) throws NoSuchMethodException {
+
+ final Method declaredMethod = cls.getMethod(methodName, parameterTypes);
+ if (isPublic(declaredMethod.getDeclaringClass())) {
+ return declaredMethod;
+ }
+
+ final List+ * The string passed in is assumed to be a class name - it is not checked. + *
+ * + *+ * Note that this method is mainly designed to handle the arrays and primitives properly. If the class is an inner class + * then the result value will not contain the outer classes. This way the behavior of this method is different from + * {@link #getShortClassName(String)}. The argument in that case is class name and not canonical name and the return + * value retains the outer classes. + *
+ * + *+ * Note that there is no way to reliably identify the part of the string representing the package hierarchy and the part + * that is the outer class or classes in case of an inner class. Trying to find the class would require reflective call + * and the class itself may not even be on the class path. Relying on the fact that class names start with capital + * letter and packages with lower case is heuristic. + *
+ * + *+ * It is recommended to use {@link #getShortClassName(String)} for cases when the class is an inner class and use this + * method for cases it is designed for. + *
+ * + *| return value | + *input | + *
| {@code ""} | + *{@code (String)null} | + *
| {@code "Map.Entry"} | + *{@code java.util.Map.Entry.class.getName()} | + *
| {@code "Entry"} | + *{@code java.util.Map.Entry.class.getCanonicalName()} | + *
| {@code "ClassUtils"} | + *{@code "org.apache.commons.lang3.ClassUtils"} | + *
| {@code "ClassUtils[]"} | + *{@code "[Lorg.apache.commons.lang3.ClassUtils;"} | + *
| {@code "ClassUtils[][]"} | + *{@code "[[Lorg.apache.commons.lang3.ClassUtils;"} | + *
| {@code "ClassUtils[]"} | + *{@code "org.apache.commons.lang3.ClassUtils[]"} | + *
| {@code "ClassUtils[][]"} | + *{@code "org.apache.commons.lang3.ClassUtils[][]"} | + *
| {@code "int[]"} | + *{@code "[I"} | + *
| {@code "int[]"} | + *{@code int[].class.getCanonicalName()} | + *
| {@code "int[]"} | + *{@code int[].class.getName()} | + *
| {@code "int[][]"} | + *{@code "[[I"} | + *
| {@code "int[]"} | + *{@code "int[]"} | + *
| {@code "int[][]"} | + *{@code "int[][]"} | + *
+ * This method simply gets the name using {@code Class.getName()} and then calls {@link #getShortClassName(String)}. See + * relevant notes there. + *
+ * + * @param cls the class to get the short name for. + * @return the class name without the package name or an empty string. If the class is an inner class then the returned + * value will contain the outer class or classes separated with {@code .} (dot) character. + */ + public static String getShortClassName(final Class> cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getShortClassName(cls.getName()); + } + + /** + * Gets the class name of the {@code object} without the package name or names. + * + *+ * The method looks up the class of the object and then converts the name of the class invoking + * {@link #getShortClassName(Class)} (see relevant notes there). + *
+ * + * @param object the class to get the short name for, may be {@code null} + * @param valueIfNull the value to return if the object is {@code null} + * @return the class name of the object without the package name, or {@code valueIfNull} if the argument {@code object} + * is {@code null} + */ + public static String getShortClassName(final Object object, final String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getShortClassName(object.getClass()); + } + + /** + * 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. The string has to be formatted the way as the + * JDK method {@code Class.getName()} returns it, and not the usual way as we write it, for example in import + * statements, or as it is formatted by {@code Class.getCanonicalName()}. + *
+ * + *+ * The difference is is significant only in case of classes that are inner classes of some other classes. In this case + * the separator between the outer and inner class (possibly on multiple hierarchy level) has to be {@code $} (dollar + * sign) and not {@code .} (dot), as it is returned by {@code Class.getName()} + *
+ * + *+ * Note that this method is called from the {@link #getShortClassName(Class)} method using the string returned by + * {@code Class.getName()}. + *
+ * + *+ * Note that this method differs from {@link #getSimpleName(Class)} in that this will return, for example + * {@code "Map.Entry"} whilst the {@link Class} variant will simply return {@code "Entry"}. In this example + * the argument {@code className} is the string {@code java.util.Map$Entry} (note the {@code $} sign. + *
+ * + * @param className the className to get the short name for. It has to be formatted as returned by + * {@code Class.getName()} and not {@code Class.getCanonicalName()} + * @return the class name of the class without the package name or an empty string. If the class is an inner class then + * value contains the outer class or classes and the separator is replaced to be {@code .} (dot) character. + */ + public static String getShortClassName(String className) { + if (StringUtils.isEmpty(className)) { + return StringUtils.EMPTY; + } + + final 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); + } + } + + final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); + final 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 {@code cls.getSimpleName()} + * + * @param cls the class for which to get the simple name; may be null + * @return the simple class name or the empty string in case the argument is {@code null} + * @since 3.0 + * @see Class#getSimpleName() + */ + public static String getSimpleName(final Class> cls) { + return getSimpleName(cls, StringUtils.EMPTY); + } + + /** + * Null-safe version of {@code cls.getSimpleName()} + * + * @param cls the class for which to get the simple name; may be null + * @param valueIfNull the value to return if null + * @return the simple class name or {@code valueIfNull} if the argument {@code cls} is {@code null} + * @since 3.0 + * @see Class#getSimpleName() + */ + public static String getSimpleName(final Class> cls, final String valueIfNull) { + return cls == null ? valueIfNull : cls.getSimpleName(); + } + + /** + * Null-safe version of {@code object.getClass().getSimpleName()} + * + *+ * It is to note that this method is overloaded and in case the argument {@code object} is a {@link Class} object then + * the {@link #getSimpleName(Class)} will be invoked. If this is a significant possibility then the caller should check + * this case and call {@code + * getSimpleName(Class.class)} or just simply use the string literal {@code "Class"}, which is the result of the method + * in that case. + *
+ * + * @param object the object for which to get the simple class name; may be null + * @return the simple class name or the empty string in case the argument is {@code null} + * @since 3.7 + * @see Class#getSimpleName() + */ + public static String getSimpleName(final Object object) { + return getSimpleName(object, StringUtils.EMPTY); + } + + /** + * Null-safe version of {@code object.getClass().getSimpleName()} + * + * @param object the object for which to get the simple class name; may be null + * @param valueIfNull the value to return if {@code object} is {@code null} + * @return the simple class name or {@code valueIfNull} if the argument {@code object} is {@code null} + * @since 3.0 + * @see Class#getSimpleName() + */ + public static String getSimpleName(final Object object, final String valueIfNull) { + return object == null ? valueIfNull : object.getClass().getSimpleName(); + } + + /** + * Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order, + * excluding interfaces. + * + * @param type the type to get the class hierarchy from + * @return Iterable an Iterable over the class hierarchy of the given class + * @since 3.2 + */ + public static Iterable+ * 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 {@link Class} parameter can be + * converted to the type represented by this {@link 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(final Class> cls, final Class> toClass) { + return isAssignable(cls, toClass, true); + } + + /** + * Checks if one {@link Class} can be assigned to a variable of another {@link 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 {@link Class} parameter can be + * converted to the type represented by this {@link 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, final Class> toClass, final 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()) { + 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) || 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); + } + + /** + * 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 {@link Class} parameter can be + * converted to the type represented by this {@link 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(final Class>[] classArray, final Class>... toClassArray) { + return isAssignable(classArray, toClassArray, true); + } + + /** + * 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 {@link Class} parameter can be + * converted to the type represented by this {@link 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, final boolean autoboxing) { + if (!ArrayUtils.isSameLength(classArray, toClassArray)) { + return false; + } + classArray = ArrayUtils.nullToEmpty(classArray); + toClassArray = ArrayUtils.nullToEmpty(toClassArray); + for (int i = 0; i < classArray.length; i++) { + if (!isAssignable(classArray[i], toClassArray[i], autoboxing)) { + return false; + } + } + return true; + } + + /** + * 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(final Class> cls) { + return cls != null && cls.getEnclosingClass() != null; + } + + /** + * Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, + * {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). + * + * @param type The class to query or null. + * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, + * {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). + * @since 3.1 + */ + public static boolean isPrimitiveOrWrapper(final Class> type) { + if (type == null) { + return false; + } + return type.isPrimitive() || isPrimitiveWrapper(type); + } + /** + * Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, + * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). + * + * @param type The class to query or null. + * @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, + * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). + * @since 3.1 + */ + public static boolean isPrimitiveWrapper(final Class> type) { + return wrapperPrimitiveMap.containsKey(type); + } + + /** + * Tests whether a {@link Class} is public. + * @param cls Class to test. + * @return {@code true} if {@code cls} is public. + * @since 3.13.0 + */ + public static boolean isPublic(final Class> cls) { + return Modifier.isPublic(cls.getModifiers()); + } + + /** + * 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(final Class>... classes) { + if (classes == null) { + return null; + } + + if (classes.length == 0) { + return classes; + } + + final Class>[] convertedClasses = new Class[classes.length]; + Arrays.setAll(convertedClasses, i -> primitiveToWrapper(classes[i])); + return convertedClasses; + } + + /** + * 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(final Class> cls) { + Class> convertedClass = cls; + if (cls != null && cls.isPrimitive()) { + convertedClass = primitiveWrapperMap.get(cls); + } + return convertedClass; + } + + /** + * Converts a class name to a JLS style class name. + * + * @param className the class name + * @return the converted name + * @throws NullPointerException if the className is null + */ + private static String toCanonicalName(final String className) { + String canonicalName = StringUtils.deleteWhitespace(className); + Objects.requireNonNull(canonicalName, "className"); + if (canonicalName.endsWith("[]")) { + final StringBuilder classNameBuffer = new StringBuilder(); + while (canonicalName.endsWith("[]")) { + canonicalName = canonicalName.substring(0, canonicalName.length() - 2); + classNameBuffer.append("["); + } + final String abbreviation = abbreviationMap.get(canonicalName); + if (abbreviation != null) { + classNameBuffer.append(abbreviation); + } else { + classNameBuffer.append("L").append(canonicalName).append(";"); + } + canonicalName = classNameBuffer.toString(); + } + return canonicalName; + } + + /** + * Converts an array of {@link Object} in to an array of {@link 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 {@link Object} array + * @return a {@link Class} array, {@code null} if null array input + * @since 2.4 + */ + public static Class>[] toClass(final Object... array) { + if (array == null) { + return null; + } + if (array.length == 0) { + return ArrayUtils.EMPTY_CLASS_ARRAY; + } + final Class>[] classes = new Class[array.length]; + Arrays.setAll(classes, i -> array[i] == null ? null : array[i].getClass()); + return classes; + } + + /** + * Decides if the part that was just copied to its destination location in the work array can be kept as it was copied + * or must be abbreviated. It must be kept when the part is the last one, which is the simple name of the class. In this + * case the {@code source} index, from where the characters are copied points one position after the last character, + * a.k.a. {@code source == + * originalLength} + * + *+ * If the part is not the last one then it can be kept unabridged if the number of the characters copied so far plus the + * character that are to be copied is less than or equal to the desired length. + *
+ * + * @param runAheadTarget the target index (where the characters were copied to) pointing after the last character copied + * when the current part was copied + * @param source the source index (where the characters were copied from) pointing after the last character copied when + * the current part was copied + * @param originalLength the original length of the class full name, which is abbreviated + * @param desiredLength the desired length of the abbreviated class name + * @return {@code true} if it can be kept in its original length {@code false} if the current part has to be abbreviated + * and + */ + private static boolean useFull(final int runAheadTarget, final int source, final int originalLength, final int desiredLength) { + return source >= originalLength || runAheadTarget + originalLength - source <= desiredLength; + } + + /** + * 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(final Class>... classes) { + if (classes == null) { + return null; + } + + if (classes.length == 0) { + return classes; + } + + final Class>[] convertedClasses = new Class[classes.length]; + Arrays.setAll(convertedClasses, i -> wrapperToPrimitive(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(final Class> cls) { + return wrapperPrimitiveMap.get(cls); + } + + /** + * 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. + *
+ * + * @deprecated TODO Make private in 4.0. + */ + @Deprecated + public ClassUtils() { + // empty + } + +} diff --git a/core/src/main/java/org/apache/commons/lang3/local/StringUtils.java b/core/src/main/java/org/apache/commons/lang3/local/StringUtils.java new file mode 100644 index 00000000..3e926a7a --- /dev/null +++ b/core/src/main/java/org/apache/commons/lang3/local/StringUtils.java @@ -0,0 +1,73 @@ +package org.apache.commons.lang3.local; + +public class StringUtils { + + /** + * A String for a space character. + * + */ + public static final String SPACE = " "; + + /** + * The empty String {@code ""}. + */ + public static final String EMPTY = ""; + + /** + * Deletes all whitespaces from a String as defined by + * {@link Character#isWhitespace(char)}. + * + *
+ * StringUtils.deleteWhitespace(null) = null
+ * StringUtils.deleteWhitespace("") = ""
+ * StringUtils.deleteWhitespace("abc") = "abc"
+ * StringUtils.deleteWhitespace(" ab c ") = "abc"
+ *
+ *
+ * @param str the String to delete whitespace from, may be null
+ * @return the String without whitespaces, {@code null} if null String input
+ */
+ public static String deleteWhitespace(final String str) {
+ if (isEmpty(str)) {
+ return str;
+ }
+ final int sz = str.length();
+ final char[] chs = new char[sz];
+ int count = 0;
+ for (int i = 0; i < sz; i++) {
+ if (!Character.isWhitespace(str.charAt(i))) {
+ chs[count++] = str.charAt(i);
+ }
+ }
+ if (count == sz) {
+ return str;
+ }
+ if (count == 0) {
+ return EMPTY;
+ }
+ return new String(chs, 0, count);
+ }
+
+ /**
+ * Checks if a CharSequence is empty ("") or null.
+ *
+ *
+ * StringUtils.isEmpty(null) = true
+ * StringUtils.isEmpty("") = true
+ * StringUtils.isEmpty(" ") = false
+ * StringUtils.isEmpty("bob") = false
+ * StringUtils.isEmpty(" bob ") = false
+ *
+ *
+ * NOTE: This method changed in Lang version 2.0. + * It no longer trims the CharSequence. + * That functionality is available in isBlank().
+ * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is empty or null + * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) + */ + public static boolean isEmpty(final CharSequence cs) { + return cs == null || cs.length() == 0; + } +} diff --git a/core/src/main/java/org/apache/commons/lang3/local/mutable/Mutable.java b/core/src/main/java/org/apache/commons/lang3/local/mutable/Mutable.java new file mode 100644 index 00000000..07ef4402 --- /dev/null +++ b/core/src/main/java/org/apache/commons/lang3/local/mutable/Mutable.java @@ -0,0 +1,55 @@ +/* + * 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.local.mutable; + +/** + * Provides mutable access to a value. + *+ * {@link Mutable} is used as a generic interface to the implementations in this package. + *
+ *+ * A typical use case would be to enable a primitive or string to be passed to a method and allow that method to + * effectively change the value of the primitive/string. Another use case is to store a frequently changing primitive in + * a collection (for example a total in a map) without needing to create new Integer/Long wrapper objects. + *
+ * + * @param+ * When a {@code public} class has a default access superclass with {@code public} members, + * these members are accessible. Calling them from compiled code works fine. + * Unfortunately, on some JVMs, using reflection to invoke these members + * seems to (wrongly) prevent access even when the modifier is {@code public}. + * Calling {@code setAccessible(true)} solves the problem but will only work from + * sufficiently privileged code. Better workarounds would be gratefully + * accepted. + *
+ * + * @param obj the AccessibleObject to set as accessible, may be null. + * @return a boolean indicating whether the accessibility of the object was set to true. + */ + static