From 6b2ce6c6140415463511acf2889b4901449cac27 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Mon, 16 Sep 2024 18:31:27 +0200 Subject: [PATCH] Add commons-lang as a subproject Avoid using a local version of this apache module --- .gitmodules | 3 + apache/build.gradle.kts | 16 + apache/commons-lang | 1 + .../commons/lang3}/reflect/MemberUtilsX.java | 2 +- core/build.gradle.kts | 2 +- .../de/robv/android/xposed/XposedHelpers.java | 4 +- .../commons/lang3/local/ArrayUtils.java | 154 -- .../commons/lang3/local/ClassUtils.java | 1633 ----------------- .../commons/lang3/local/StringUtils.java | 73 - .../commons/lang3/local/mutable/Mutable.java | 55 - .../lang3/local/mutable/MutableObject.java | 121 -- .../lang3/local/reflect/MemberUtils.java | 342 ---- daemon/build.gradle.kts | 2 +- gradle/libs.versions.toml | 1 - settings.gradle.kts | 1 + 15 files changed, 26 insertions(+), 2384 deletions(-) create mode 100644 apache/build.gradle.kts create mode 160000 apache/commons-lang rename {core/src/main/java/org/apache/commons/lang3/local => apache/local/org/apache/commons/lang3}/reflect/MemberUtilsX.java (96%) delete mode 100644 core/src/main/java/org/apache/commons/lang3/local/ArrayUtils.java delete mode 100644 core/src/main/java/org/apache/commons/lang3/local/ClassUtils.java delete mode 100644 core/src/main/java/org/apache/commons/lang3/local/StringUtils.java delete mode 100644 core/src/main/java/org/apache/commons/lang3/local/mutable/Mutable.java delete mode 100644 core/src/main/java/org/apache/commons/lang3/local/mutable/MutableObject.java delete mode 100644 core/src/main/java/org/apache/commons/lang3/local/reflect/MemberUtils.java diff --git a/.gitmodules b/.gitmodules index 533f7b78365..6b59e25a71f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "external/xz-embedded"] path = external/xz-embedded url = https://github.com/tukaani-project/xz-embedded +[submodule "apache/commons-lang"] + path = apache/commons-lang + url = https://github.com/apache/commons-lang diff --git a/apache/build.gradle.kts b/apache/build.gradle.kts new file mode 100644 index 00000000000..af8055912b2 --- /dev/null +++ b/apache/build.gradle.kts @@ -0,0 +1,16 @@ +val androidSourceCompatibility: JavaVersion by rootProject.extra +val androidTargetCompatibility: JavaVersion by rootProject.extra + +plugins { + id("java-library") +} + +java { + sourceCompatibility = androidSourceCompatibility + targetCompatibility = androidTargetCompatibility + sourceSets { + main { + java.srcDirs("commons-lang/src/main/java", "local") + } + } +} diff --git a/apache/commons-lang b/apache/commons-lang new file mode 160000 index 00000000000..c2cd0525d97 --- /dev/null +++ b/apache/commons-lang @@ -0,0 +1 @@ +Subproject commit c2cd0525d97495daa820d2fcb29d6875b52c09a6 diff --git a/core/src/main/java/org/apache/commons/lang3/local/reflect/MemberUtilsX.java b/apache/local/org/apache/commons/lang3/reflect/MemberUtilsX.java similarity index 96% rename from core/src/main/java/org/apache/commons/lang3/local/reflect/MemberUtilsX.java rename to apache/local/org/apache/commons/lang3/reflect/MemberUtilsX.java index bd4c5aac004..36c872096fb 100644 --- a/core/src/main/java/org/apache/commons/lang3/local/reflect/MemberUtilsX.java +++ b/apache/local/org/apache/commons/lang3/reflect/MemberUtilsX.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.commons.lang3.local.reflect; +package org.apache.commons.lang3.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Method; diff --git a/core/build.gradle.kts b/core/build.gradle.kts index b199f3d77e3..baccd0e0bd7 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -57,7 +57,7 @@ copy { dependencies { api(libs.libxposed.api) - implementation(libs.commons.lang3) + implementation(projects.apache) implementation(projects.axml) implementation(projects.hiddenapi.bridge) implementation(projects.services.daemonService) diff --git a/core/src/main/java/de/robv/android/xposed/XposedHelpers.java b/core/src/main/java/de/robv/android/xposed/XposedHelpers.java index 284b8d7aca7..a0495fbf7e5 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedHelpers.java +++ b/core/src/main/java/de/robv/android/xposed/XposedHelpers.java @@ -26,8 +26,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.apache.commons.lang3.local.ClassUtils; -import org.apache.commons.lang3.local.reflect.MemberUtilsX; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.reflect.MemberUtilsX; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; diff --git a/core/src/main/java/org/apache/commons/lang3/local/ArrayUtils.java b/core/src/main/java/org/apache/commons/lang3/local/ArrayUtils.java deleted file mode 100644 index f9e65908431..00000000000 --- a/core/src/main/java/org/apache/commons/lang3/local/ArrayUtils.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.apache.commons.lang3.local; - -import java.lang.reflect.Array; - -public class ArrayUtils { - - /** - * An empty immutable {@link Class} array. - */ - public static final Class[] EMPTY_CLASS_ARRAY = {}; - - /** - * Defensive programming technique to change a {@code null} - * reference to an empty one. - *

- * 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. - *

- * - * @param array the array to check for {@code null} or empty - * @return the same array, {@code public static} empty array if {@code null} or empty input - * @since 3.2 - */ - public static Class[] nullToEmpty(final Class[] array) { - return nullTo(array, EMPTY_CLASS_ARRAY); - } - - /** - * Defensive programming technique to change a {@code null} - * reference to an empty one. - *

- * 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. - *

- * - * @param The array type. - * @param array the array to check for {@code null} or empty - * @param defaultArray A default array, usually empty. - * @return the same array, or defaultArray if {@code null} or empty input. - * @since 3.15.0 - */ - public static T[] nullTo(final T[] array, final T[] defaultArray) { - return isEmpty(array) ? defaultArray : array; - } - - /** - * Checks if an array of Objects is empty or {@code null}. - * - * @param array the array to test - * @return {@code true} if the array is empty or {@code null} - * @since 2.1 - */ - public static boolean isEmpty(final Object[] array) { - return isArrayEmpty(array); - } - - /** - * Checks if an array is empty or {@code null}. - * - * @param array the array to test - * @return {@code true} if the array is empty or {@code null} - */ - private static boolean isArrayEmpty(final Object array) { - return getLength(array) == 0; - } - - /** - * Returns the length of the specified array. - * This method can deal with {@link Object} arrays and with primitive arrays. - *

- * If the input array is {@code null}, {@code 0} is returned. - *

- *
-     * 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}. - *

- * Any multi-dimensional aspects of the arrays are ignored. - *

- * - * @param array1 the first array, may be {@code null} - * @param array2 the second array, may be {@code null} - * @return {@code true} if length of arrays matches, treating - * {@code null} as an empty array - * @since 3.11 - */ - public static boolean isSameLength(final Object array1, final Object array2) { - return getLength(array1) == getLength(array2); - } - - /** - * Outputs an array as a String, treating {@code null} as an empty array. - *

- * Multi-dimensional arrays are handled correctly, including - * multi-dimensional primitive arrays. - *

- *

- * The format is that of Java source code, for example {@code {a,b}}. - *

- * - * @param array the array to get a toString for, may be {@code null} - * @return a String representation of the array, '{}' if null array input - */ - public static String toString(final Object array) { - return toString(array, "{}"); - } - - /** - * Outputs an array as a String handling {@code null}s. - *

- * Multi-dimensional arrays are handled correctly, including - * multi-dimensional primitive arrays. - *

- *

- * The format is that of Java source code, for example {@code {a,b}}. - *

- * - * @param array the array to get a toString for, may be {@code null} - * @param stringIfNull the String to return if the array is {@code null} - * @return a String representation of the array - */ - public static String toString(final Object array, final String stringIfNull) { - if (array == null) { - return stringIfNull; - } - // return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString(); - // TODO: add a proper implement - return array.toString(); - } - -} diff --git a/core/src/main/java/org/apache/commons/lang3/local/ClassUtils.java b/core/src/main/java/org/apache/commons/lang3/local/ClassUtils.java deleted file mode 100644 index 32f03e128a0..00000000000 --- a/core/src/main/java/org/apache/commons/lang3/local/ClassUtils.java +++ /dev/null @@ -1,1633 +0,0 @@ -/* - * 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; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.local.mutable.MutableObject; - -/** - * Operates on classes without using reflection. - * - *

- * 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}. - *

- * - * @since 2.0 - */ -public class ClassUtils { - - /** - * Inclusivity literals for {@link #hierarchy(Class, Interfaces)}. - * - * @since 3.2 - */ - public enum Interfaces { - - /** Includes interfaces. */ - INCLUDE, - - /** Excludes interfaces. */ - EXCLUDE - } - - private static final Comparator> COMPARATOR = (o1, o2) -> Objects.compare(getName(o1), getName(o2), String::compareTo); - - /** - * The package separator character: {@code '.' == {@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: {@code '$' == {@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 names of primitives to their corresponding primitive {@link Class}es. - */ - private static final Map> namePrimitiveMap = new HashMap<>(); - - static { - namePrimitiveMap.put(Boolean.TYPE.getSimpleName(), Boolean.TYPE); - namePrimitiveMap.put(Byte.TYPE.getSimpleName(), Byte.TYPE); - namePrimitiveMap.put(Character.TYPE.getSimpleName(), Character.TYPE); - namePrimitiveMap.put(Double.TYPE.getSimpleName(), Double.TYPE); - namePrimitiveMap.put(Float.TYPE.getSimpleName(), Float.TYPE); - namePrimitiveMap.put(Integer.TYPE.getSimpleName(), Integer.TYPE); - namePrimitiveMap.put(Long.TYPE.getSimpleName(), Long.TYPE); - namePrimitiveMap.put(Short.TYPE.getSimpleName(), Short.TYPE); - namePrimitiveMap.put(Void.TYPE.getSimpleName(), Void.TYPE); - } - - /** - * Maps primitive {@link Class}es to their corresponding wrapper {@link Class}. - */ - private static final Map, Class> primitiveWrapperMap = new HashMap<>(); - - 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 {@link Class}es to their corresponding primitive types. - */ - private static final Map, Class> wrapperPrimitiveMap = new HashMap<>(); - - static { - primitiveWrapperMap.forEach((primitiveClass, wrapperClass) -> { - 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; - - /** - * Maps an abbreviation used in array class names to corresponding primitive class name. - */ - private static final Map reverseAbbreviationMap; - - /** Feed abbreviation maps. */ - static { - final Map map = new HashMap<>(); - map.put("int", "I"); - map.put("boolean", "Z"); - map.put("float", "F"); - map.put("long", "J"); - map.put("short", "S"); - map.put("byte", "B"); - map.put("double", "D"); - map.put("char", "C"); - abbreviationMap = Collections.unmodifiableMap(map); - reverseAbbreviationMap = Collections.unmodifiableMap(map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey))); - } - - /** - * Gets the class comparator, comparing by class name. - * - * @return the class comparator. - * @since 3.13.0 - */ - public static Comparator> comparator() { - return COMPARATOR; - } - - /** - * Given a {@link List} of {@link Class} objects, this method converts them into class names. - * - *

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

- * - * @param classes the classes to change - * @return a {@link List} of class names corresponding to the Class objects, {@code null} if null input - * @throws ClassCastException if {@code classes} contains a non-{@link Class} entry - */ - public static List convertClassesToClassNames(final List> classes) { - return classes == null ? null : classes.stream().map(e -> getName(e, null)).collect(Collectors.toList()); - } - - /** - * Given a {@link List} of class names, this method converts them into classes. - * - *

- * 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}. - *

- * - * @param classNames the classNames to change - * @return a {@link 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(final List classNames) { - if (classNames == null) { - return null; - } - final List> classes = new ArrayList<>(classNames.size()); - classNames.forEach(className -> { - try { - classes.add(Class.forName(className)); - } catch (final Exception ex) { - classes.add(null); - } - }); - return classes; - } - - /** - * Gets the abbreviated name of a {@link Class}. - * - * @param cls the class 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 - * @throws IllegalArgumentException if len <= 0 - * @see #getAbbreviatedName(String, int) - * @since 3.4 - */ - public static String getAbbreviatedName(final Class cls, final int lengthHint) { - if (cls == null) { - return StringUtils.EMPTY; - } - return getAbbreviatedName(cls.getName(), lengthHint); - } - - /** - * Gets the abbreviated class name from a {@link String}. - * - *

- * 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}. - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Examples
classNamelenreturn
null1""
"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"
- * - * @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. - * - *

- * 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 {@link List} of interfaces in order, {@code null} if null input - */ - public static List> getAllInterfaces(final Class cls) { - if (cls == null) { - return null; - } - - final LinkedHashSet> interfacesFound = new LinkedHashSet<>(); - getAllInterfaces(cls, interfacesFound); - - return new ArrayList<>(interfacesFound); - } - - /** - * Gets the interfaces for the specified class. - * - * @param cls the class to look up, may be {@code null} - * @param interfacesFound the {@link Set} of interfaces for the class - */ - private static void getAllInterfaces(Class cls, final HashSet> interfacesFound) { - while (cls != null) { - final Class[] interfaces = cls.getInterfaces(); - - for (final Class i : interfaces) { - if (interfacesFound.add(i)) { - getAllInterfaces(i, interfacesFound); - } - } - - cls = cls.getSuperclass(); - } - } - - /** - * Gets a {@link List} of superclasses for the given class. - * - * @param cls the class to look up, may be {@code null} - * @return the {@link List} of superclasses in order going up from this one {@code null} if null input - */ - public static List> getAllSuperclasses(final Class cls) { - if (cls == null) { - return null; - } - final List> classes = new ArrayList<>(); - Class superclass = cls.getSuperclass(); - while (superclass != null) { - classes.add(superclass); - superclass = superclass.getSuperclass(); - } - return classes; - } - - /** - * Gets the canonical class name for a {@link Class}. - * - * @param cls the class for which to get the canonical class name; may be null - * @return the canonical name of the class, or the empty String - * @since 3.7 - * @see Class#getCanonicalName() - */ - public static String getCanonicalName(final Class cls) { - return getCanonicalName(cls, StringUtils.EMPTY); - } - - /** - * Gets the canonical name for a {@link Class}. - * - * @param cls the class for which to get the canonical class name; may be null - * @param valueIfNull the return value if null - * @return the canonical name of the class, or {@code valueIfNull} - * @since 3.7 - * @see Class#getCanonicalName() - */ - public static String getCanonicalName(final Class cls, final String valueIfNull) { - if (cls == null) { - return valueIfNull; - } - final String canonicalName = cls.getCanonicalName(); - return canonicalName == null ? valueIfNull : canonicalName; - } - - /** - * Gets the canonical name for an {@link Object}. - * - * @param object the object for which to get the canonical class name; may be null - * @return the canonical name of the object, or the empty String - * @since 3.7 - * @see Class#getCanonicalName() - */ - public static String getCanonicalName(final Object object) { - return getCanonicalName(object, StringUtils.EMPTY); - } - - /** - * Gets the canonical name for an {@link Object}. - * - * @param object the object for which to get the canonical class name; may be null - * @param valueIfNull the return value if null - * @return the canonical name of the object or {@code valueIfNull} - * @since 3.7 - * @see Class#getCanonicalName() - */ - public static String getCanonicalName(final Object object, final String valueIfNull) { - if (object == null) { - return valueIfNull; - } - final String canonicalName = object.getClass().getCanonicalName(); - return canonicalName == null ? valueIfNull : 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. - * - *

- * The method does not change the {@code $} separators in case the class is inner class. - *

- * - *

- * 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; - } - int dim = 0; - while (className.startsWith("[")) { - dim++; - className = className.substring(1); - } - if (dim < 1) { - return className; - } - if (className.startsWith("L")) { - className = className.substring(1, className.endsWith(";") ? className.length() - 1 : className.length()); - } else if (!className.isEmpty()) { - className = reverseAbbreviationMap.get(className.substring(0, 1)); - } - final StringBuilder canonicalClassNameBuffer = new StringBuilder(className); - for (int i = 0; i < dim; i++) { - canonicalClassNameBuffer.append("[]"); - } - return canonicalClassNameBuffer.toString(); - } - - /** - * 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 NullPointerException if the className is null - * @throws ClassNotFoundException if the class is not found - */ - public static Class getClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException { - return getClass(classLoader, className, true); - } - - /** - * 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 NullPointerException if the className is null - * @throws ClassNotFoundException if the class is not found - */ - public static Class getClass(final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException { - try { - final Class clazz = getPrimitiveClass(className); - return clazz != null ? clazz : Class.forName(toCanonicalName(className), initialize, classLoader); - } catch (final ClassNotFoundException ex) { - // allow path separators (.) as inner class name separators - final 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 (final ClassNotFoundException ignored) { - // ignore exception - } - } - - throw ex; - } - } - - /** - * 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 NullPointerException if the className is null - * @throws ClassNotFoundException if the class is not found - */ - public static Class getClass(final 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 NullPointerException if the className is null - * @throws ClassNotFoundException if the class is not found - */ - public static Class getClass(final String className, final boolean initialize) throws ClassNotFoundException { - final ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL; - return getClass(loader, className, initialize); - } - - /** - * Delegates to {@link Class#getComponentType()} using generics. - * - * @param The array class type. - * @param cls A class or null. - * @return The array component type or null. - * @see Class#getComponentType() - * @since 3.13.0 - */ - @SuppressWarnings("unchecked") - public static Class getComponentType(final Class cls) { - return cls == null ? null : (Class) cls.getComponentType(); - } - - /** - * Null-safe version of {@code cls.getName()} - * - * @param cls the class for which to get the class name; may be null - * @return the class name or the empty string in case the argument is {@code null} - * @since 3.7 - * @see Class#getSimpleName() - */ - public static String getName(final Class cls) { - return getName(cls, StringUtils.EMPTY); - } - - /** - * Null-safe version of {@code cls.getName()} - * - * @param cls the class for which to get the class name; may be null - * @param valueIfNull the return value if the argument {@code cls} is {@code null} - * @return the class name or {@code valueIfNull} - * @since 3.7 - * @see Class#getName() - */ - public static String getName(final Class cls, final String valueIfNull) { - return cls == null ? valueIfNull : cls.getName(); - } - - /** - * Null-safe version of {@code object.getClass().getName()} - * - * @param object the object for which to get the class name; may be null - * @return the class name or the empty String - * @since 3.7 - * @see Class#getSimpleName() - */ - public static String getName(final Object object) { - return getName(object, StringUtils.EMPTY); - } - - /** - * Null-safe version of {@code object.getClass().getSimpleName()} - * - * @param object the object for which to get the class name; may be null - * @param valueIfNull the value to return if {@code object} is {@code null} - * @return the class name or {@code valueIfNull} - * @since 3.0 - * @see Class#getName() - */ - public static String getName(final Object object, final String valueIfNull) { - return object == null ? valueIfNull : object.getClass().getName(); - } - - /** - * Gets the package name from the canonical 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 - * @since 2.4 - */ - public static String getPackageCanonicalName(final Class cls) { - if (cls == null) { - return StringUtils.EMPTY; - } - return getPackageCanonicalName(cls.getName()); - } - - /** - * Gets the package name from the class 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 - * @since 2.4 - */ - public static String getPackageCanonicalName(final Object object, final String valueIfNull) { - if (object == null) { - return valueIfNull; - } - return getPackageCanonicalName(object.getClass().getName()); - } - - /** - * Gets the package name from the class name. - * - *

- * 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> candidateClasses = new ArrayList<>(getAllInterfaces(cls)); - candidateClasses.addAll(getAllSuperclasses(cls)); - - for (final Class candidateClass : candidateClasses) { - if (!isPublic(candidateClass)) { - continue; - } - final Method candidateMethod; - try { - candidateMethod = candidateClass.getMethod(methodName, parameterTypes); - } catch (final 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)); - } - - /** - * Gets the canonical name minus the package name from a {@link Class}. - * - * @param cls the class for which to get the short canonical class name; may be null - * @return the canonical name without the package name or an empty string - * @since 2.4 - * @see Class#getCanonicalName() - */ - public static String getShortCanonicalName(final Class cls) { - return cls == null ? StringUtils.EMPTY : getShortCanonicalName(cls.getCanonicalName()); - } - - /** - * Gets the canonical name minus the package name for an {@link 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 - * @see Class#getCanonicalName() - */ - public static String getShortCanonicalName(final Object object, final String valueIfNull) { - return object == null ? valueIfNull : getShortCanonicalName(object.getClass().getCanonicalName()); - } - - /** - * Gets the canonical 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 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. - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Examples
return valueinput
{@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[][]"}
- * - * @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(final String canonicalName) { - return getShortClassName(getCanonicalName(canonicalName)); - } - - /** - * Gets the class name minus the package name from a {@link Class}. - * - *

- * 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> hierarchy(final Class type) { - return hierarchy(type, Interfaces.EXCLUDE); - } - - /** - * Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order. - * - * @param type the type to get the class hierarchy from - * @param interfacesBehavior switch indicating whether to include or exclude interfaces - * @return Iterable an Iterable over the class hierarchy of the given class - * @since 3.2 - */ - public static Iterable> hierarchy(final Class type, final Interfaces interfacesBehavior) { - final Iterable> classes = () -> { - final MutableObject> next = new MutableObject<>(type); - return new Iterator>() { - - @Override - public boolean hasNext() { - return next.getValue() != null; - } - - @Override - public Class next() { - final Class result = next.getValue(); - next.setValue(result.getSuperclass()); - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - }; - }; - if (interfacesBehavior != Interfaces.INCLUDE) { - return classes; - } - return () -> { - final Set> seenInterfaces = new HashSet<>(); - final Iterator> wrapped = classes.iterator(); - - return new Iterator>() { - Iterator> interfaces = Collections.emptyIterator(); - - @Override - public boolean hasNext() { - return interfaces.hasNext() || wrapped.hasNext(); - } - - @Override - public Class next() { - if (interfaces.hasNext()) { - final Class nextInterface = interfaces.next(); - seenInterfaces.add(nextInterface); - return nextInterface; - } - final Class nextSuperclass = wrapped.next(); - final Set> currentInterfaces = new LinkedHashSet<>(); - walkInterfaces(currentInterfaces, nextSuperclass); - interfaces = currentInterfaces.iterator(); - return nextSuperclass; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - private void walkInterfaces(final Set> addTo, final Class c) { - for (final Class iface : c.getInterfaces()) { - if (!seenInterfaces.contains(iface)) { - addTo.add(iface); - } - walkInterfaces(addTo, iface); - } - } - - }; - }; - } - - /** - * 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. - *

- * - *

- * 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 deleted file mode 100644 index 3e926a7abc6..00000000000 --- a/core/src/main/java/org/apache/commons/lang3/local/StringUtils.java +++ /dev/null @@ -1,73 +0,0 @@ -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 deleted file mode 100644 index 07ef4402016..00000000000 --- a/core/src/main/java/org/apache/commons/lang3/local/mutable/Mutable.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 the type to set and get - * @since 2.1 - */ -public interface Mutable { - - /** - * Gets the value of this mutable. - * - * @return the stored value - */ - T getValue(); - - /** - * Sets the value of this mutable. - * - * @param value - * the value to store - * @throws NullPointerException - * if the object is null and null is invalid - * @throws ClassCastException - * if the type is invalid - */ - void setValue(T value); - -} diff --git a/core/src/main/java/org/apache/commons/lang3/local/mutable/MutableObject.java b/core/src/main/java/org/apache/commons/lang3/local/mutable/MutableObject.java deleted file mode 100644 index a8264871743..00000000000 --- a/core/src/main/java/org/apache/commons/lang3/local/mutable/MutableObject.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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; - -import java.io.Serializable; -import java.util.Objects; - -/** - * A mutable {@link Object} wrapper. - * - * @param the type to set and get - * @since 2.1 - */ -public class MutableObject implements Mutable, Serializable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 86241875189L; - - /** The mutable value. */ - private T value; - - /** - * Constructs a new MutableObject with the default value of {@code null}. - */ - public MutableObject() { - } - - /** - * Constructs a new MutableObject with the specified value. - * - * @param value the initial value to store - */ - public MutableObject(final T value) { - this.value = value; - } - - /** - * Compares this object against the specified object. The result is {@code true} if and only if the argument - * is not {@code null} and is a {@link MutableObject} object that contains the same {@link T} - * value as this object. - * - * @param obj the object to compare with, {@code null} returns {@code false} - * @return {@code true} if the objects are the same; - * {@code true} if the objects have equivalent {@code value} fields; - * {@code false} otherwise. - */ - @Override - public boolean equals(final Object obj) { - if (obj == null) { - return false; - } - if (this == obj) { - return true; - } - if (this.getClass() == obj.getClass()) { - final MutableObject that = (MutableObject) obj; - return Objects.equals(this.value, that.value); - } - return false; - } - - /** - * Gets the value. - * - * @return the value, may be null - */ - @Override - public T getValue() { - return this.value; - } - - /** - * Returns the value's hash code or {@code 0} if the value is {@code null}. - * - * @return the value's hash code or {@code 0} if the value is {@code null}. - */ - @Override - public int hashCode() { - return Objects.hashCode(value); - } - - /** - * Sets the value. - * - * @param value the value to set - */ - @Override - public void setValue(final T value) { - this.value = value; - } - - /** - * Returns the String value of this mutable. - * - * @return the mutable value as a string - */ - @Override - public String toString() { - return Objects.toString(value); - } - -} diff --git a/core/src/main/java/org/apache/commons/lang3/local/reflect/MemberUtils.java b/core/src/main/java/org/apache/commons/lang3/local/reflect/MemberUtils.java deleted file mode 100644 index 9e0d4562689..00000000000 --- a/core/src/main/java/org/apache/commons/lang3/local/reflect/MemberUtils.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * 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.reflect; - -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Constructor; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -import org.apache.commons.lang3.local.ClassUtils; - -/** - * Contains common code for working with {@link java.lang.reflect.Method Methods}/{@link java.lang.reflect.Constructor Constructors}, - * extracted and refactored from {@link MethodUtils} when it was imported from Commons BeanUtils. - * - * @since 2.5 - */ -final class MemberUtils { - // TODO extract an interface to implement compareParameterSets(...)? - - /** - * A class providing a subset of the API of java.lang.reflect.Executable in Java 1.8, - * providing a common representation for function signatures for Constructors and Methods. - */ - private static final class Executable { - private static Executable of(final Constructor constructor) { - return new Executable(constructor); - } - private static Executable of(final Method method) { - return new Executable(method); - } - - private final Class[] parameterTypes; - - private final boolean isVarArgs; - - private Executable(final Constructor constructor) { - parameterTypes = constructor.getParameterTypes(); - isVarArgs = constructor.isVarArgs(); - } - - private Executable(final Method method) { - parameterTypes = method.getParameterTypes(); - isVarArgs = method.isVarArgs(); - } - - public Class[] getParameterTypes() { - return parameterTypes; - } - - public boolean isVarArgs() { - return isVarArgs; - } - } - - private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE; - - /** Array of primitive number types ordered by "promotability" */ - private static final Class[] ORDERED_PRIMITIVE_TYPES = { Byte.TYPE, Short.TYPE, - Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE }; - - /** - * Compares the relative fitness of two Constructors in terms of how well they - * match a set of runtime parameter types, such that a list ordered - * by the results of the comparison would return the best match first - * (least). - * - * @param left the "left" Constructor - * @param right the "right" Constructor - * @param actual the runtime parameter types to match against - * {@code left}/{@code right} - * @return int consistent with {@code compare} semantics - * @since 3.5 - */ - static int compareConstructorFit(final Constructor left, final Constructor right, final Class[] actual) { - return compareParameterTypes(Executable.of(left), Executable.of(right), actual); - } - - /** - * Compares the relative fitness of two Methods in terms of how well they - * match a set of runtime parameter types, such that a list ordered - * by the results of the comparison would return the best match first - * (least). - * - * @param left the "left" Method - * @param right the "right" Method - * @param actual the runtime parameter types to match against - * {@code left}/{@code right} - * @return int consistent with {@code compare} semantics - * @since 3.5 - */ - static int compareMethodFit(final Method left, final Method right, final Class[] actual) { - return compareParameterTypes(Executable.of(left), Executable.of(right), actual); - } - - /** - * Compares the relative fitness of two Executables in terms of how well they - * match a set of runtime parameter types, such that a list ordered - * by the results of the comparison would return the best match first - * (least). - * - * @param left the "left" Executable - * @param right the "right" Executable - * @param actual the runtime parameter types to match against - * {@code left}/{@code right} - * @return int consistent with {@code compare} semantics - */ - private static int compareParameterTypes(final Executable left, final Executable right, final Class[] actual) { - final float leftCost = getTotalTransformationCost(actual, left); - final float rightCost = getTotalTransformationCost(actual, right); - return Float.compare(leftCost, rightCost); - } - - /** - * Gets the number of steps needed to turn the source class into - * the destination class. This represents the number of steps in the object - * hierarchy graph. - * @param srcClass The source class - * @param destClass The destination class - * @return The cost of transforming an object - */ - private static float getObjectTransformationCost(Class srcClass, final Class destClass) { - if (destClass.isPrimitive()) { - return getPrimitivePromotionCost(srcClass, destClass); - } - float cost = 0.0f; - while (srcClass != null && !destClass.equals(srcClass)) { - if (destClass.isInterface() && ClassUtils.isAssignable(srcClass, destClass)) { - // slight penalty for interface match. - // we still want an exact match to override an interface match, - // but - // an interface match should override anything where we have to - // get a superclass. - cost += 0.25f; - break; - } - cost++; - srcClass = srcClass.getSuperclass(); - } - /* - * If the destination class is null, we've traveled all the way up to - * an Object match. We'll penalize this by adding 1.5 to the cost. - */ - if (srcClass == null) { - cost += 1.5f; - } - return cost; - } - - /** - * Gets the number of steps required to promote a primitive number to another - * type. - * @param srcClass the (primitive) source class - * @param destClass the (primitive) destination class - * @return The cost of promoting the primitive - */ - private static float getPrimitivePromotionCost(final Class srcClass, final Class destClass) { - if (srcClass == null) { - return 1.5f; - } - float cost = 0.0f; - Class cls = srcClass; - if (!cls.isPrimitive()) { - // slight unwrapping penalty - cost += 0.1f; - cls = ClassUtils.wrapperToPrimitive(cls); - } - for (int i = 0; cls != destClass && i < ORDERED_PRIMITIVE_TYPES.length; i++) { - if (cls == ORDERED_PRIMITIVE_TYPES[i]) { - cost += 0.1f; - if (i < ORDERED_PRIMITIVE_TYPES.length - 1) { - cls = ORDERED_PRIMITIVE_TYPES[i + 1]; - } - } - } - return cost; - } - - /** - * Returns the sum of the object transformation cost for each class in the - * source argument list. - * @param srcArgs The source arguments - * @param executable The executable to calculate transformation costs for - * @return The total transformation cost - */ - private static float getTotalTransformationCost(final Class[] srcArgs, final Executable executable) { - final Class[] destArgs = executable.getParameterTypes(); - final boolean isVarArgs = executable.isVarArgs(); - - // "source" and "destination" are the actual and declared args respectively. - float totalCost = 0.0f; - final long normalArgsLen = isVarArgs ? destArgs.length - 1 : destArgs.length; - if (srcArgs.length < normalArgsLen) { - return Float.MAX_VALUE; - } - for (int i = 0; i < normalArgsLen; i++) { - totalCost += getObjectTransformationCost(srcArgs[i], destArgs[i]); - } - if (isVarArgs) { - // When isVarArgs is true, srcArgs and dstArgs may differ in length. - // There are two special cases to consider: - final boolean noVarArgsPassed = srcArgs.length < destArgs.length; - final boolean explicitArrayForVarargs = srcArgs.length == destArgs.length && srcArgs[srcArgs.length - 1] != null - && srcArgs[srcArgs.length - 1].isArray(); - - final float varArgsCost = 0.001f; - final Class destClass = destArgs[destArgs.length - 1].getComponentType(); - if (noVarArgsPassed) { - // When no varargs passed, the best match is the most generic matching type, not the most specific. - totalCost += getObjectTransformationCost(destClass, Object.class) + varArgsCost; - } else if (explicitArrayForVarargs) { - final Class sourceClass = srcArgs[srcArgs.length - 1].getComponentType(); - totalCost += getObjectTransformationCost(sourceClass, destClass) + varArgsCost; - } else { - // This is typical varargs case. - for (int i = destArgs.length - 1; i < srcArgs.length; i++) { - final Class srcClass = srcArgs[i]; - totalCost += getObjectTransformationCost(srcClass, destClass) + varArgsCost; - } - } - } - return totalCost; - } - - /** - * Tests whether a {@link Member} is accessible. - * - * @param member Member to test, may be null. - * @return {@code true} if {@code m} is accessible - */ - static boolean isAccessible(final Member member) { - return isPublic(member) && !member.isSynthetic(); - } - - static boolean isMatchingConstructor(final Constructor method, final Class[] parameterTypes) { - return isMatchingExecutable(Executable.of(method), parameterTypes); - } - - private static boolean isMatchingExecutable(final Executable method, final Class[] parameterTypes) { - final Class[] methodParameterTypes = method.getParameterTypes(); - if (ClassUtils.isAssignable(parameterTypes, methodParameterTypes, true)) { - return true; - } - if (method.isVarArgs()) { - int i; - for (i = 0; i < methodParameterTypes.length - 1 && i < parameterTypes.length; i++) { - if (!ClassUtils.isAssignable(parameterTypes[i], methodParameterTypes[i], true)) { - return false; - } - } - final Class varArgParameterType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); - for (; i < parameterTypes.length; i++) { - if (!ClassUtils.isAssignable(parameterTypes[i], varArgParameterType, true)) { - return false; - } - } - return true; - } - return false; - } - - static boolean isMatchingMethod(final Method method, final Class[] parameterTypes) { - return isMatchingExecutable(Executable.of(method), parameterTypes); - } - - /** - * Tests whether a given set of modifiers implies package access. - * - * @param modifiers to test - * @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected - */ - static boolean isPackageAccess(final int modifiers) { - return (modifiers & ACCESS_TEST) == 0; - } - - /** - * Tests whether a {@link Member} is public. - * - * @param member Member to test, may be null. - * @return {@code true} if {@code m} is public - */ - static boolean isPublic(final Member member) { - return member != null && Modifier.isPublic(member.getModifiers()); - } - - /** - * Tests whether a {@link Member} is static. - * - * @param member Member to test, may be null. - * @return {@code true} if {@code m} is static - */ - static boolean isStatic(final Member member) { - return member != null && Modifier.isStatic(member.getModifiers()); - } - - /** - * Default access superclass workaround. - *

- * 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 T setAccessibleWorkaround(final T obj) { - if (obj == null || obj.isAccessible()) { - return obj; - } - final Member m = (Member) obj; - if (!obj.isAccessible() && isPublic(m) && isPackageAccess(m.getDeclaringClass().getModifiers())) { - try { - obj.setAccessible(true); - return obj; - } catch (final SecurityException ignored) { - // ignore in favor of subsequent IllegalAccessException - } - } - return obj; - } - -} diff --git a/daemon/build.gradle.kts b/daemon/build.gradle.kts index 5d97ed903cf..3514b4f5a82 100644 --- a/daemon/build.gradle.kts +++ b/daemon/build.gradle.kts @@ -116,7 +116,7 @@ android.applicationVariants.all { dependencies { implementation(libs.libxposed.`interface`) implementation(libs.agp.apksig) - implementation(libs.commons.lang3) + implementation(projects.apache) implementation(projects.hiddenapi.bridge) implementation(projects.services.daemonService) implementation(projects.services.managerService) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 05c492804b0..71e8457a819 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -56,7 +56,6 @@ okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-i agp-apksig = { group = "com.android.tools.build", name = "apksig", version.ref = "agp" } appiconloader = { module = "me.zhanghai.android.appiconloader:appiconloader", version = "1.5.0" } -commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.17.0" } material = { module = "com.google.android.material:material", version = "1.12.0" } gson = { module = "com.google.code.gson:gson", version = "2.11.0" } hiddenapibypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version = "4.3" } diff --git a/settings.gradle.kts b/settings.gradle.kts index f4cdaa479b9..2d4e03d10f8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,6 +26,7 @@ dependencyResolutionManagement { rootProject.name = "LSPosed" include( + ":apache", ":app", ":axml", ":core",