- *
Useful for identifying programmer errors early and clearly at runtime. - *
- *
For example, if the contract of a public method states it does not - * allow {@code null} arguments, {@code Assert} can be used to validate that - * contract. Doing this clearly indicates a contract violation when it - * occurs and protects the class's invariants. - *
- *
Typically used to validate method arguments rather than configuration - * properties, to check for cases that are usually programmer errors rather - * than configuration errors. In contrast to configuration initialization - * code, there is usually no point in falling back to defaults in such methods. - *
- *
This class is similar to JUnit's assertion library. If an argument value is - * deemed invalid, an {@link IllegalArgumentException} is thrown (typically). - * For example: - *
- *
- * Assert.notNull(clazz, "The class must not be null"); - * Assert.isTrue(i > 0, "The value must be greater than zero");- *
- *
Mainly for internal use within the framework; consider - * Apache's Commons Lang - * for a more comprehensive suite of {@code String} utilities. - * - * @author Keith Donald - * @author Juergen Hoeller - * @author Sam Brannen - * @author Colin Sampaleanu - * @author Rob Harrop - * @since 1.1.2 - */ -public abstract class Assert { - - /** - * Assert a boolean expression, throwing an {@code IllegalStateException} - * if the expression evaluates to {@code false}. - *
Call {@link #isTrue} if you wish to throw an {@code IllegalArgumentException} - * on an assertion failure. - *
- * Assert.state(id == null, - * () -> "ID for " + entity.getName() + " must not already be initialized"); - *- * - * @param expression a boolean expression - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalStateException if {@code expression} is {@code false} - * @since 5.0 - */ - public static void state(boolean expression, Supplier
Call {@link #isTrue} if you wish to throw an {@code IllegalArgumentException} - * on an assertion failure. - *
Assert.state(id == null, "The id property must not already be initialized");- * - * @param expression a boolean expression - * @param message the exception message to use if the assertion fails - * - * @throws IllegalStateException if {@code expression} is {@code false} - */ - public static void state(boolean expression, String message) { - if (!expression) { - throw new IllegalStateException(message); - } - } - - /** - * Assert a boolean expression, throwing an {@code IllegalArgumentException} - * if the expression evaluates to {@code false}. - *
- * Assert.isTrue(i > 0, () -> "The value '" + i + "' must be greater than zero"); - *- * - * @param expression a boolean expression - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if {@code expression} is {@code false} - * @since 5.0 - */ - public static void isTrue(boolean expression, Supplier
Assert.isTrue(i > 0, "The value must be greater than zero");- * - * @param expression a boolean expression - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if {@code expression} is {@code false} - */ - public static void isTrue(boolean expression, String message) { - if (!expression) { - throw new IllegalArgumentException(message); - } - } - - /** - * Assert that an object is {@code null}. - *
- * Assert.isNull(value, () -> "The value '" + value + "' must be null"); - *- * - * @param object the object to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if the object is not {@code null} - * @since 5.0 - */ - public static void isNull(Object object, Supplier
Assert.isNull(value, "The value must be null");- * - * @param object the object to check - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if the object is not {@code null} - */ - public static void isNull(Object object, String message) { - if (object != null) { - throw new IllegalArgumentException(message); - } - } - - /** - * Assert that an object is not {@code null}. - *
- * Assert.notNull(clazz, () -> "The class '" + clazz.getName() + "' must not be null"); - *- * - * @param object the object to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if the object is {@code null} - * @since 5.0 - */ - public static void notNull(Object object, Supplier
Assert.notNull(clazz, "The class must not be null");- * - * @param object the object to check - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if the object is {@code null} - */ - public static void notNull(Object object, String message) { - if (object == null) { - throw new IllegalArgumentException(message); - } - } - - /** - * Assert that the given String is not empty; that is, - * it must not be {@code null} and not the empty String. - *
- * Assert.hasLength(name, () -> "Name for account '" + account.getId() + "' must not be empty"); - *- * - * @param text the String to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if the text is empty - * @see StringUtils#hasLength - * @since 5.0 - */ - public static void hasLength(String text, Supplier
Assert.hasLength(name, "Name must not be empty");- * - * @param text the String to check - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if the text is empty - * @see StringUtils#hasLength - */ - public static void hasLength(String text, String message) { - if (!StringUtils.hasLength(text)) { - throw new IllegalArgumentException(message); - } - } - - /** - * Assert that the given String contains valid text content; that is, it must not - * be {@code null} and must contain at least one non-whitespace character. - *
- * Assert.hasText(name, () -> "Name for account '" + account.getId() + "' must not be empty"); - *- * - * @param text the String to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if the text does not contain valid text content - * @see StringUtils#hasText - * @since 5.0 - */ - public static void hasText(String text, Supplier
Assert.hasText(name, "'name' must not be empty");- * - * @param text the String to check - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if the text does not contain valid text content - * @see StringUtils#hasText - */ - public static void hasText(String text, String message) { - if (!StringUtils.hasText(text)) { - throw new IllegalArgumentException(message); - } - } - - /** - * Assert that the given text does not contain the given substring. - *
Assert.doesNotContain(name, "rod", "Name must not contain 'rod'");- * - * @param textToSearch the text to search - * @param substring the substring to find within the text - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if the text contains the substring - */ - public static void doesNotContain(String textToSearch, String substring, String message) { - if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) && - textToSearch.contains(substring)) { - throw new IllegalArgumentException(message); - } - } - - /** - * @deprecated as of 4.3.7, in favor of {@link #doesNotContain(String, String, String)} - */ - @Deprecated - public static void doesNotContain(String textToSearch, String substring) { - doesNotContain(textToSearch, substring, - () -> "[Assertion failed] - this String argument must not contain the substring [" + substring + "]"); - } - - /** - * Assert that the given text does not contain the given substring. - *
- * Assert.doesNotContain(name, forbidden, () -> "Name must not contain '" + forbidden + "'"); - *- * - * @param textToSearch the text to search - * @param substring the substring to find within the text - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if the text contains the substring - * @since 5.0 - */ - public static void doesNotContain(String textToSearch, String substring, Supplier
- * Assert.notEmpty(array, () -> "The " + arrayType + " array must contain elements"); - *- * - * @param array the array to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if the object array is {@code null} or contains no elements - * @since 5.0 - */ - public static void notEmpty(Object[] array, Supplier
Assert.notEmpty(array, "The array must contain elements");- * - * @param array the array to check - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if the object array is {@code null} or contains no elements - */ - public static void notEmpty(Object[] array, String message) { - if (ObjectUtils.isEmpty(array)) { - throw new IllegalArgumentException(message); - } - } - - /** - * Assert that an array contains no {@code null} elements. - *
Note: Does not complain if the array is empty! - *
- * Assert.noNullElements(array, () -> "The " + arrayType + " array must contain non-null elements"); - *- * - * @param array the array to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if the object array contains a {@code null} element - * @since 5.0 - */ - public static void noNullElements(Object[] array, Supplier
Note: Does not complain if the array is empty! - *
Assert.noNullElements(array, "The array must contain non-null elements");- * - * @param array the array to check - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if the object array contains a {@code null} element - */ - public static void noNullElements(Object[] array, String message) { - if (array != null) { - for (Object element : array) { - if (element == null) { - throw new IllegalArgumentException(message); - } - } - } - } - - /** - * Assert that a collection contains elements; that is, it must not be - * {@code null} and must contain at least one element. - *
- * Assert.notEmpty(collection, () -> "The " + collectionType + " collection must contain elements"); - *- * - * @param collection the collection to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if the collection is {@code null} or - * contains no elements - * @since 5.0 - */ - public static void notEmpty(Collection> collection, Supplier
Assert.notEmpty(collection, "Collection must contain elements");- * - * @param collection the collection to check - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if the collection is {@code null} or - * contains no elements - */ - public static void notEmpty(Collection> collection, String message) { - if (CollectionUtils.isEmpty(collection)) { - throw new IllegalArgumentException(message); - } - } - - /** - * Assert that a Map contains entries; that is, it must not be {@code null} - * and must contain at least one entry. - *
- * Assert.notEmpty(map, () -> "The " + mapType + " map must contain entries"); - *- * - * @param map the map to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails - * - * @throws IllegalArgumentException if the map is {@code null} or contains no entries - * @since 5.0 - */ - public static void notEmpty(Map, ?> map, Supplier
Assert.notEmpty(map, "Map must contain entries");- * - * @param map the map to check - * @param message the exception message to use if the assertion fails - * - * @throws IllegalArgumentException if the map is {@code null} or contains no entries - */ - public static void notEmpty(Map, ?> map, String message) { - if (CollectionUtils.isEmpty(map)) { - throw new IllegalArgumentException(message); - } - } - - /** - * Assert that the provided object is an instance of the provided class. - *
- * Assert.instanceOf(Foo.class, foo, () -> "Processing " + Foo.class.getSimpleName() + ":"); - *- * - * @param type the type to check against - * @param obj the object to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails. See {@link #isInstanceOf(Class, Object, String)} for details. - * - * @throws IllegalArgumentException if the object is not an instance of type - * @since 5.0 - */ - public static void isInstanceOf(Class> type, Object obj, Supplier
Assert.instanceOf(Foo.class, foo);- * - * @param type the type to check against - * @param obj the object to check - * - * @throws IllegalArgumentException if the object is not an instance of type - */ - public static void isInstanceOf(Class> type, Object obj) { - isInstanceOf(type, obj, ""); - } - - /** - * Assert that the provided object is an instance of the provided class. - *
Assert.instanceOf(Foo.class, foo, "Foo expected");- * - * @param type the type to check against - * @param obj the object to check - * @param message a message which will be prepended to provide further context. - * If it is empty or ends in ":" or ";" or "," or ".", a full exception message - * will be appended. If it ends in a space, the name of the offending object's - * type will be appended. In any other case, a ":" with a space and the name - * of the offending object's type will be appended. - * - * @throws IllegalArgumentException if the object is not an instance of type - */ - public static void isInstanceOf(Class> type, Object obj, String message) { - notNull(type, "Type to check against must not be null"); - if (!type.isInstance(obj)) { - instanceCheckFailed(type, obj, message); - } - } - - /** - * Assert that {@code superType.isAssignableFrom(subType)} is {@code true}. - *
- * Assert.isAssignable(Number.class, myClass, () -> "Processing " + myAttributeName + ":"); - *- * - * @param superType the super type to check against - * @param subType the sub type to check - * @param messageSupplier a supplier for the exception message to use if the - * assertion fails. See {@link #isAssignable(Class, Class, String)} for details. - * - * @throws IllegalArgumentException if the classes are not assignable - * @since 5.0 - */ - public static void isAssignable(Class> superType, Class> subType, Supplier
Assert.isAssignable(Number.class, myClass);- * - * @param superType the super type to check - * @param subType the sub type to check - * - * @throws IllegalArgumentException if the classes are not assignable - */ - public static void isAssignable(Class> superType, Class> subType) { - isAssignable(superType, subType, ""); - } - - /** - * Assert that {@code superType.isAssignableFrom(subType)} is {@code true}. - *
Assert.isAssignable(Number.class, myClass, "Number expected");- * - * @param superType the super type to check against - * @param subType the sub type to check - * @param message a message which will be prepended to provide further context. - * If it is empty or ends in ":" or ";" or "," or ".", a full exception message - * will be appended. If it ends in a space, the name of the offending sub type - * will be appended. In any other case, a ":" with a space and the name of the - * offending sub type will be appended. - * - * @throws IllegalArgumentException if the classes are not assignable - */ - public static void isAssignable(Class> superType, Class> subType, String message) { - notNull(superType, "Super type to check against must not be null"); - if (subType == null || !superType.isAssignableFrom(subType)) { - assignableCheckFailed(superType, subType, message); - } - } - -} diff --git a/src/main/java/com/antkorwin/xsync/springframework/util/ClassUtils.java b/src/main/java/com/antkorwin/xsync/springframework/util/ClassUtils.java deleted file mode 100644 index 2cf6844..0000000 --- a/src/main/java/com/antkorwin/xsync/springframework/util/ClassUtils.java +++ /dev/null @@ -1,1387 +0,0 @@ -/* - * Copyright 2002-2018 the original author or authors. - * - * Licensed 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 com.antkorwin.xsync.springframework.util; - - -import java.beans.Introspector; -import java.io.Closeable; -import java.io.Externalizable; -import java.io.Serializable; -import java.lang.reflect.*; -import java.util.*; - -/** - * Miscellaneous class utility methods. - * Mainly for internal use within the framework. - * - * @author Juergen Hoeller - * @author Keith Donald - * @author Rob Harrop - * @author Sam Brannen - * @see TypeUtils - * @see ReflectionUtils - * @since 1.1 - */ -public abstract class ClassUtils { - - /** - * Suffix for array class names: "[]" - */ - public static final String ARRAY_SUFFIX = "[]"; - /** - * The CGLIB class separator: "$$" - */ - public static final String CGLIB_CLASS_SEPARATOR = "$$"; - /** - * The ".class" file suffix - */ - public static final String CLASS_FILE_SUFFIX = ".class"; - /** - * Prefix for internal array class names: "[" - */ - private static final String INTERNAL_ARRAY_PREFIX = "["; - /** - * Prefix for internal non-primitive array class names: "[L" - */ - private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L"; - /** - * The package separator character: '.' - */ - private static final char PACKAGE_SEPARATOR = '.'; - /** - * The path separator character: '/' - */ - private static final char PATH_SEPARATOR = '/'; - /** - * The inner class separator character: '$' - */ - private static final char INNER_CLASS_SEPARATOR = '$'; - /** - * Map with primitive wrapper type as key and corresponding primitive - * type as value, for example: Integer.class -> int.class. - */ - private static final Map
Call this method if you intend to use the thread context ClassLoader - * in a scenario where you clearly prefer a non-null ClassLoader reference: - * for example, for class path resource loading (but not necessarily for - * {@code Class.forName}, which accepts a {@code null} ClassLoader - * reference as well). - * - * @return the default ClassLoader (only {@code null} if even the system - * ClassLoader isn't accessible) - * @see Thread#getContextClassLoader() - * @see ClassLoader#getSystemClassLoader() - */ - public static ClassLoader getDefaultClassLoader() { - ClassLoader cl = null; - try { - cl = Thread.currentThread().getContextClassLoader(); - } catch (Throwable ex) { - // Cannot access thread context ClassLoader - falling back... - } - if (cl == null) { - // No thread context class loader -> use class loader of this class. - cl = ClassUtils.class.getClassLoader(); - if (cl == null) { - // getClassLoader() returning null indicates the bootstrap ClassLoader - try { - cl = ClassLoader.getSystemClassLoader(); - } catch (Throwable ex) { - // Cannot access system ClassLoader - oh well, maybe the caller can live with null... - } - } - } - return cl; - } - - /** - * Override the thread context ClassLoader with the environment's bean ClassLoader - * if necessary, i.e. if the bean ClassLoader is not equivalent to the thread - * context ClassLoader already. - * - * @param classLoaderToUse the actual ClassLoader to use for the thread context - * - * @return the original thread context ClassLoader, or {@code null} if not overridden - */ - public static ClassLoader overrideThreadContextClassLoader(ClassLoader classLoaderToUse) { - Thread currentThread = Thread.currentThread(); - ClassLoader threadContextClassLoader = currentThread.getContextClassLoader(); - if (classLoaderToUse != null && !classLoaderToUse.equals(threadContextClassLoader)) { - currentThread.setContextClassLoader(classLoaderToUse); - return threadContextClassLoader; - } else { - return null; - } - } - - /** - * Replacement for {@code Class.forName()} that also returns Class instances - * for primitives (e.g. "int") and array class names (e.g. "String[]"). - * Furthermore, it is also capable of resolving inner class names in Java source - * style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State"). - * - * @param name the name of the Class - * @param classLoader the class loader to use - * (may be {@code null}, which indicates the default class loader) - * - * @return Class instance for the supplied name - * @throws ClassNotFoundException if the class was not found - * @throws LinkageError if the class file could not be loaded - * @see Class#forName(String, boolean, ClassLoader) - */ - public static Class> forName(String name, ClassLoader classLoader) - throws ClassNotFoundException, LinkageError { - - Assert.notNull(name, "Name must not be null"); - - Class> clazz = resolvePrimitiveClassName(name); - if (clazz == null) { - clazz = commonClassCache.get(name); - } - if (clazz != null) { - return clazz; - } - - // "java.lang.String[]" style arrays - if (name.endsWith(ARRAY_SUFFIX)) { - String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length()); - Class> elementClass = forName(elementClassName, classLoader); - return Array.newInstance(elementClass, 0).getClass(); - } - - // "[Ljava.lang.String;" style arrays - if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) { - String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1); - Class> elementClass = forName(elementName, classLoader); - return Array.newInstance(elementClass, 0).getClass(); - } - - // "[[I" or "[[Ljava.lang.String;" style arrays - if (name.startsWith(INTERNAL_ARRAY_PREFIX)) { - String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length()); - Class> elementClass = forName(elementName, classLoader); - return Array.newInstance(elementClass, 0).getClass(); - } - - ClassLoader clToUse = classLoader; - if (clToUse == null) { - clToUse = getDefaultClassLoader(); - } - try { - return (clToUse != null ? clToUse.loadClass(name) : Class.forName(name)); - } catch (ClassNotFoundException ex) { - int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR); - if (lastDotIndex != -1) { - String innerClassName = - name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1); - try { - return (clToUse != null ? clToUse.loadClass(innerClassName) : Class.forName(innerClassName)); - } catch (ClassNotFoundException ex2) { - // Swallow - let original exception get through - } - } - throw ex; - } - } - - /** - * Resolve the given class name into a Class instance. Supports - * primitives (like "int") and array class names (like "String[]"). - *
This is effectively equivalent to the {@code forName} - * method with the same arguments, with the only difference being - * the exceptions thrown in case of class loading failure. - * - * @param className the name of the Class - * @param classLoader the class loader to use - * (may be {@code null}, which indicates the default class loader) - * - * @return Class instance for the supplied name - * @throws IllegalArgumentException if the class name was not resolvable - * (that is, the class could not be found or the class file could not be loaded) - * @see #forName(String, ClassLoader) - */ - public static Class> resolveClassName(String className, ClassLoader classLoader) - throws IllegalArgumentException { - - try { - return forName(className, classLoader); - } catch (ClassNotFoundException ex) { - throw new IllegalArgumentException("Could not find class [" + className + "]", ex); - } catch (LinkageError err) { - throw new IllegalArgumentException("Unresolvable class definition for class [" + className + "]", err); - } - } - - /** - * Determine whether the {@link Class} identified by the supplied name is present - * and can be loaded. Will return {@code false} if either the class or - * one of its dependencies is not present or cannot be loaded. - * - * @param className the name of the class to check - * @param classLoader the class loader to use - * (may be {@code null} which indicates the default class loader) - * - * @return whether the specified class is present - */ - public static boolean isPresent(String className, ClassLoader classLoader) { - try { - forName(className, classLoader); - return true; - } catch (Throwable ex) { - // Class or one of its dependencies is not present... - return false; - } - } - - /** - * Check whether the given class is cache-safe in the given context, - * i.e. whether it is loaded by the given ClassLoader or a parent of it. - * - * @param clazz the class to analyze - * @param classLoader the ClassLoader to potentially cache metadata in - * (may be {@code null} which indicates the system class loader) - */ - public static boolean isCacheSafe(Class> clazz, ClassLoader classLoader) { - Assert.notNull(clazz, "Class must not be null"); - try { - ClassLoader target = clazz.getClassLoader(); - // Common cases - if (target == classLoader || target == null) { - return true; - } - if (classLoader == null) { - return false; - } - // Check for match in ancestors -> positive - ClassLoader current = classLoader; - while (current != null) { - current = current.getParent(); - if (current == target) { - return true; - } - } - // Check for match in children -> negative - while (target != null) { - target = target.getParent(); - if (target == classLoader) { - return false; - } - } - } catch (SecurityException ex) { - // Fall through to loadable check below - } - - // Fallback for ClassLoaders without parent/child relationship: - // safe if same Class can be loaded from given ClassLoader - return (classLoader != null && isLoadable(clazz, classLoader)); - } - - /** - * Check whether the given class is loadable in the given ClassLoader. - * - * @param clazz the class to check (typically an interface) - * @param classLoader the ClassLoader to check against - * - * @since 5.0.6 - */ - private static boolean isLoadable(Class> clazz, ClassLoader classLoader) { - try { - return (clazz == classLoader.loadClass(clazz.getName())); - // Else: different class with same name found - } catch (ClassNotFoundException ex) { - // No corresponding class found at all - return false; - } - } - - /** - * Resolve the given class name as primitive class, if appropriate, - * according to the JVM's naming rules for primitive classes. - *
Also supports the JVM's internal class names for primitive arrays.
- * Does not support the "[]" suffix notation for primitive arrays;
- * this is only supported by {@link #forName(String, ClassLoader)}.
- *
- * @param name the name of the potentially primitive class
- *
- * @return the primitive class, or {@code null} if the name does not denote
- * a primitive class or primitive array class
- */
- public static Class> resolvePrimitiveClassName(String name) {
- Class> result = null;
- // Most class names will be quite long, considering that they
- // SHOULD sit in a package, so a length check is worthwhile.
- if (name != null && name.length() <= 8) {
- // Could be a primitive - likely.
- result = primitiveTypeNameMap.get(name);
- }
- return result;
- }
-
- /**
- * Check if the given class represents a primitive (i.e. boolean, byte,
- * char, short, int, long, float, or double) or a primitive wrapper
- * (i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double).
- *
- * @param clazz the class to check
- *
- * @return whether the given class is a primitive or primitive wrapper class
- */
- public static boolean isPrimitiveOrWrapper(Class> clazz) {
- Assert.notNull(clazz, "Class must not be null");
- return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
- }
-
- /**
- * Check if the given class represents a primitive wrapper,
- * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double.
- *
- * @param clazz the class to check
- *
- * @return whether the given class is a primitive wrapper class
- */
- public static boolean isPrimitiveWrapper(Class> clazz) {
- Assert.notNull(clazz, "Class must not be null");
- return primitiveWrapperTypeMap.containsKey(clazz);
- }
-
- /**
- * Check if the given class represents an array of primitives,
- * i.e. boolean, byte, char, short, int, long, float, or double.
- *
- * @param clazz the class to check
- *
- * @return whether the given class is a primitive array class
- */
- public static boolean isPrimitiveArray(Class> clazz) {
- Assert.notNull(clazz, "Class must not be null");
- return (clazz.isArray() && clazz.getComponentType().isPrimitive());
- }
-
- /**
- * Check if the given class represents an array of primitive wrappers,
- * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double.
- *
- * @param clazz the class to check
- *
- * @return whether the given class is a primitive wrapper array class
- */
- public static boolean isPrimitiveWrapperArray(Class> clazz) {
- Assert.notNull(clazz, "Class must not be null");
- return (clazz.isArray() && isPrimitiveWrapper(clazz.getComponentType()));
- }
-
- /**
- * Resolve the given class if it is a primitive class,
- * returning the corresponding primitive wrapper type instead.
- *
- * @param clazz the class to check
- *
- * @return the original class, or a primitive wrapper for the original primitive type
- */
- public static Class> resolvePrimitiveIfNecessary(Class> clazz) {
- Assert.notNull(clazz, "Class must not be null");
- return (clazz.isPrimitive() && clazz != void.class ? primitiveTypeToWrapperMap.get(clazz) : clazz);
- }
-
- /**
- * Determine if the given type is assignable from the given value,
- * assuming setting by reflection. Considers primitive wrapper classes
- * as assignable to the corresponding primitive types.
- *
- * @param type the target type
- * @param value the value that should be assigned to the type
- *
- * @return if the type is assignable from the value
- */
- public static boolean isAssignableValue(Class> type, Object value) {
- Assert.notNull(type, "Type must not be null");
- return (value != null ? isAssignable(type, value.getClass()) : !type.isPrimitive());
- }
-
- /**
- * Check if the right-hand side type may be assigned to the left-hand side
- * type, assuming setting by reflection. Considers primitive wrapper
- * classes as assignable to the corresponding primitive types.
- *
- * @param lhsType the target type
- * @param rhsType the value type that should be assigned to the target type
- *
- * @return if the target type is assignable from the value type
- * @see TypeUtils#isAssignable
- */
- public static boolean isAssignable(Class> lhsType, Class> rhsType) {
- Assert.notNull(lhsType, "Left-hand side type must not be null");
- Assert.notNull(rhsType, "Right-hand side type must not be null");
- if (lhsType.isAssignableFrom(rhsType)) {
- return true;
- }
- if (lhsType.isPrimitive()) {
- Class> resolvedPrimitive = primitiveWrapperTypeMap.get(rhsType);
- if (lhsType == resolvedPrimitive) {
- return true;
- }
- } else {
- Class> resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType);
- if (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Convert a "/"-based resource path to a "."-based fully qualified class name.
- *
- * @param resourcePath the resource path pointing to a class
- *
- * @return the corresponding fully qualified class name
- */
- public static String convertResourcePathToClassName(String resourcePath) {
- Assert.notNull(resourcePath, "Resource path must not be null");
- return resourcePath.replace(PATH_SEPARATOR, PACKAGE_SEPARATOR);
- }
-
- /**
- * Convert a "."-based fully qualified class name to a "/"-based resource path.
- *
- * @param className the fully qualified class name
- *
- * @return the corresponding resource path, pointing to the class
- */
- public static String convertClassNameToResourcePath(String className) {
- Assert.notNull(className, "Class name must not be null");
- return className.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
- }
-
- /**
- * Return a path suitable for use with {@code ClassLoader.getResource}
- * (also suitable for use with {@code Class.getResource} by prepending a
- * slash ('/') to the return value). Built by taking the package of the specified
- * class file, converting all dots ('.') to slashes ('/'), adding a trailing slash
- * if necessary, and concatenating the specified resource name to this.
- *
As such, this function may be used to build a path suitable for
- * loading a resource file that is in the same package as a class file,
- * although {@link org.springframework.core.io.ClassPathResource} is usually
- * even more convenient.
- *
- * @param clazz the Class whose package will be used as the base
- * @param resourceName the resource name to append. A leading slash is optional.
- *
- * @return the built-up resource path
- * @see ClassLoader#getResource
- * @see Class#getResource
- */
- public static String addResourcePathToPackagePath(Class> clazz, String resourceName) {
- Assert.notNull(resourceName, "Resource name must not be null");
- if (!resourceName.startsWith("/")) {
- return classPackageAsResourcePath(clazz) + '/' + resourceName;
- }
- return classPackageAsResourcePath(clazz) + resourceName;
- }
-
- /**
- * Given an input class object, return a string which consists of the
- * class's package name as a pathname, i.e., all dots ('.') are replaced by
- * slashes ('/'). Neither a leading nor trailing slash is added. The result
- * could be concatenated with a slash and the name of a resource and fed
- * directly to {@code ClassLoader.getResource()}. For it to be fed to
- * {@code Class.getResource} instead, a leading slash would also have
- * to be prepended to the returned value.
- *
- * @param clazz the input class. A {@code null} value or the default
- * (empty) package will result in an empty string ("") being returned.
- *
- * @return a path which represents the package name
- * @see ClassLoader#getResource
- * @see Class#getResource
- */
- public static String classPackageAsResourcePath(Class> clazz) {
- if (clazz == null) {
- return "";
- }
- String className = clazz.getName();
- int packageEndIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
- if (packageEndIndex == -1) {
- return "";
- }
- String packageName = className.substring(0, packageEndIndex);
- return packageName.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
- }
-
- /**
- * Build a String that consists of the names of the classes/interfaces
- * in the given array.
- *
Basically like {@code AbstractCollection.toString()}, but stripping - * the "class "/"interface " prefix before every class name. - * - * @param classes an array of Class objects - * - * @return a String of form "[com.foo.Bar, com.foo.Baz]" - * @see java.util.AbstractCollection#toString() - */ - public static String classNamesToString(Class>... classes) { - return classNamesToString(Arrays.asList(classes)); - } - - /** - * Build a String that consists of the names of the classes/interfaces - * in the given collection. - *
Basically like {@code AbstractCollection.toString()}, but stripping
- * the "class "/"interface " prefix before every class name.
- *
- * @param classes a Collection of Class objects (may be {@code null})
- *
- * @return a String of form "[com.foo.Bar, com.foo.Baz]"
- * @see java.util.AbstractCollection#toString()
- */
- public static String classNamesToString(Collection If the class itself is an interface, it gets returned as sole interface.
- *
- * @param clazz the class to analyze for interfaces
- *
- * @return all interfaces that the given object implements as an array
- */
- public static Class>[] getAllInterfacesForClass(Class> clazz) {
- return getAllInterfacesForClass(clazz, null);
- }
-
- /**
- * Return all interfaces that the given class implements as an array,
- * including ones implemented by superclasses.
- * If the class itself is an interface, it gets returned as sole interface.
- *
- * @param clazz the class to analyze for interfaces
- * @param classLoader the ClassLoader that the interfaces need to be visible in
- * (may be {@code null} when accepting all declared interfaces)
- *
- * @return all interfaces that the given object implements as an array
- */
- public static Class>[] getAllInterfacesForClass(Class> clazz, ClassLoader classLoader) {
- return toClassArray(getAllInterfacesForClassAsSet(clazz, classLoader));
- }
-
- /**
- * Copy the given {@code Collection} into a {@code Class} array.
- * The {@code Collection} must contain {@code Class} elements only.
- *
- * @param collection the {@code Collection} to copy
- *
- * @return the {@code Class} array
- * @see StringUtils#toStringArray
- * @since 3.1
- */
- public static Class>[] toClassArray(Collection If the class itself is an interface, it gets returned as sole interface.
- *
- * @param clazz the class to analyze for interfaces
- * @param classLoader the ClassLoader that the interfaces need to be visible in
- * (may be {@code null} when accepting all declared interfaces)
- *
- * @return all interfaces that the given object implements as a Set
- */
- public static Set If the class itself is an interface, it gets returned as sole interface.
- *
- * @param clazz the class to analyze for interfaces
- *
- * @return all interfaces that the given object implements as a Set
- */
- public static Set This implementation builds a JDK proxy class for the given interfaces.
- *
- * @param interfaces the interfaces to merge
- * @param classLoader the ClassLoader to create the composite Class in
- *
- * @return the merged interface as Class
- * @see Proxy#getProxyClass
- */
- @SuppressWarnings("deprecation")
- public static Class> createCompositeInterface(Class>[] interfaces, ClassLoader classLoader) {
- Assert.notEmpty(interfaces, "Interfaces must not be empty");
- return Proxy.getProxyClass(classLoader, interfaces);
- }
-
- /**
- * Determine the common ancestor of the given classes, if any.
- *
- * @param clazz1 the class to introspect
- * @param clazz2 the other class to introspect
- *
- * @return the common ancestor (i.e. common superclass, one interface
- * extending the other), or {@code null} if none found. If any of the
- * given classes is {@code null}, the other class will be returned.
- * @since 3.2.6
- */
- public static Class> determineCommonAncestor(Class> clazz1, Class> clazz2) {
- if (clazz1 == null) {
- return clazz2;
- }
- if (clazz2 == null) {
- return clazz1;
- }
- if (clazz1.isAssignableFrom(clazz2)) {
- return clazz1;
- }
- if (clazz2.isAssignableFrom(clazz1)) {
- return clazz2;
- }
- Class> ancestor = clazz1;
- do {
- ancestor = ancestor.getSuperclass();
- if (ancestor == null || Object.class == ancestor) {
- return null;
- }
- }
- while (!ancestor.isAssignableFrom(clazz2));
- return ancestor;
- }
-
- /**
- * Determine whether the given interface is a common Java language interface:
- * {@link Serializable}, {@link Externalizable}, {@link Closeable}, {@link AutoCloseable},
- * {@link Cloneable}, {@link Comparable} - all of which can be ignored when looking
- * for 'primary' user-level interfaces. Common characteristics: no service-level
- * operations, no bean property methods, no default methods.
- *
- * @param ifc the interface to check
- *
- * @since 5.0.3
- */
- public static boolean isJavaLanguageInterface(Class> ifc) {
- return javaLanguageInterfaces.contains(ifc);
- }
-
- /**
- * Determine if the supplied class is an inner class,
- * i.e. a non-static member of an enclosing class.
- *
- * @return {@code true} if the supplied class is an inner class
- * @see Class#isMemberClass()
- * @since 5.0.5
- */
- public static boolean isInnerClass(Class> clazz) {
- return (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers()));
- }
-
- /**
- * Check whether the given object is a CGLIB proxy.
- *
- * @param object the object to check
- *
- * @see #isCglibProxyClass(Class)
- * @see org.springframework.aop.support.AopUtils#isCglibProxy(Object)
- */
- public static boolean isCglibProxy(Object object) {
- return isCglibProxyClass(object.getClass());
- }
-
- /**
- * Check whether the specified class is a CGLIB-generated class.
- *
- * @param clazz the class to check
- *
- * @see #isCglibProxyClassName(String)
- */
- public static boolean isCglibProxyClass(Class> clazz) {
- return (clazz != null && isCglibProxyClassName(clazz.getName()));
- }
-
- /**
- * Check whether the specified class name is a CGLIB-generated class.
- *
- * @param className the class name to check
- */
- public static boolean isCglibProxyClassName(String className) {
- return (className != null && className.contains(CGLIB_CLASS_SEPARATOR));
- }
-
- /**
- * Return the user-defined class for the given instance: usually simply
- * the class of the given instance, but the original class in case of a
- * CGLIB-generated subclass.
- *
- * @param instance the instance to check
- *
- * @return the user-defined class
- */
- public static Class> getUserClass(Object instance) {
- Assert.notNull(instance, "Instance must not be null");
- return getUserClass(instance.getClass());
- }
-
- /**
- * Return the user-defined class for the given class: usually simply the given
- * class, but the original class in case of a CGLIB-generated subclass.
- *
- * @param clazz the class to check
- *
- * @return the user-defined class
- */
- public static Class> getUserClass(Class> clazz) {
- if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
- Class> superclass = clazz.getSuperclass();
- if (superclass != null && Object.class != superclass) {
- return superclass;
- }
- }
- return clazz;
- }
-
- /**
- * Return a descriptive name for the given object's type: usually simply
- * the class name, but component type class name + "[]" for arrays,
- * and an appended list of implemented interfaces for JDK proxies.
- *
- * @param value the value to introspect
- *
- * @return the qualified name of the class
- */
- public static String getDescriptiveType(Object value) {
- if (value == null) {
- return null;
- }
- Class> clazz = value.getClass();
- if (Proxy.isProxyClass(clazz)) {
- StringBuilder result = new StringBuilder(clazz.getName());
- result.append(" implementing ");
- Class>[] ifcs = clazz.getInterfaces();
- for (int i = 0; i < ifcs.length; i++) {
- result.append(ifcs[i].getName());
- if (i < ifcs.length - 1) {
- result.append(',');
- }
- }
- return result.toString();
- } else {
- return clazz.getTypeName();
- }
- }
-
- /**
- * Check whether the given class matches the user-specified type name.
- *
- * @param clazz the class to check
- * @param typeName the type name to match
- */
- public static boolean matchesTypeName(Class> clazz, String typeName) {
- return (typeName != null &&
- (typeName.equals(clazz.getTypeName()) || typeName.equals(clazz.getSimpleName())));
- }
-
- /**
- * Return the short string name of a Java class in uncapitalized JavaBeans
- * property format. Strips the outer class name in case of an inner class.
- *
- * @param clazz the class
- *
- * @return the short name rendered in a standard JavaBeans property format
- * @see Introspector#decapitalize(String)
- */
- public static String getShortNameAsProperty(Class> clazz) {
- String shortName = getShortName(clazz);
- int dotIndex = shortName.lastIndexOf(PACKAGE_SEPARATOR);
- shortName = (dotIndex != -1 ? shortName.substring(dotIndex + 1) : shortName);
- return Introspector.decapitalize(shortName);
- }
-
- /**
- * Get the class name without the qualified package name.
- *
- * @param clazz the class to get the short name for
- *
- * @return the class name of the class without the package name
- */
- public static String getShortName(Class> clazz) {
- return getShortName(getQualifiedName(clazz));
- }
-
- /**
- * Get the class name without the qualified package name.
- *
- * @param className the className to get the short name for
- *
- * @return the class name of the class without the package name
- * @throws IllegalArgumentException if the className is empty
- */
- public static String getShortName(String className) {
- Assert.hasLength(className, "Class name must not be empty");
- int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
- int nameEndIndex = className.indexOf(CGLIB_CLASS_SEPARATOR);
- if (nameEndIndex == -1) {
- nameEndIndex = className.length();
- }
- String shortName = className.substring(lastDotIndex + 1, nameEndIndex);
- shortName = shortName.replace(INNER_CLASS_SEPARATOR, PACKAGE_SEPARATOR);
- return shortName;
- }
-
- /**
- * Return the qualified name of the given class: usually simply
- * the class name, but component type class name + "[]" for arrays.
- *
- * @param clazz the class
- *
- * @return the qualified name of the class
- */
- public static String getQualifiedName(Class> clazz) {
- Assert.notNull(clazz, "Class must not be null");
- return clazz.getTypeName();
- }
-
- /**
- * Determine the name of the class file, relative to the containing
- * package: e.g. "String.class"
- *
- * @param clazz the class
- *
- * @return the file name of the ".class" file
- */
- public static String getClassFileName(Class> clazz) {
- Assert.notNull(clazz, "Class must not be null");
- String className = clazz.getName();
- int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
- return className.substring(lastDotIndex + 1) + CLASS_FILE_SUFFIX;
- }
-
- /**
- * Return the qualified name of the given method, consisting of
- * fully qualified interface/class name + "." + method name.
- *
- * @param method the method
- *
- * @return the qualified name of the method
- */
- public static String getQualifiedMethodName(Method method) {
- return getQualifiedMethodName(method, null);
- }
-
- /**
- * Return the qualified name of the given method, consisting of
- * fully qualified interface/class name + "." + method name.
- *
- * @param method the method
- * @param clazz the clazz that the method is being invoked on
- * (may be {@code null} to indicate the method's declaring class)
- *
- * @return the qualified name of the method
- * @since 4.3.4
- */
- public static String getQualifiedMethodName(Method method, Class> clazz) {
- Assert.notNull(method, "Method must not be null");
- return (clazz != null ? clazz : method.getDeclaringClass()).getName() + '.' + method.getName();
- }
-
- /**
- * Determine whether the given class has a public constructor with the given signature.
- * Essentially translates {@code NoSuchMethodException} to "false".
- *
- * @param clazz the clazz to analyze
- * @param paramTypes the parameter types of the method
- *
- * @return whether the class has a corresponding constructor
- * @see Class#getMethod
- */
- public static boolean hasConstructor(Class> clazz, Class>... paramTypes) {
- return (getConstructorIfAvailable(clazz, paramTypes) != null);
- }
-
- /**
- * Determine whether the given class has a public constructor with the given signature,
- * and return it if available (else return {@code null}).
- * Essentially translates {@code NoSuchMethodException} to {@code null}.
- *
- * @param clazz the clazz to analyze
- * @param paramTypes the parameter types of the method
- *
- * @return the constructor, or {@code null} if not found
- * @see Class#getConstructor
- */
- public static Essentially translates {@code NoSuchMethodException} to "false".
- *
- * @param clazz the clazz to analyze
- * @param methodName the name of the method
- * @param paramTypes the parameter types of the method
- *
- * @return whether the class has a corresponding method
- * @see Class#getMethod
- */
- public static boolean hasMethod(Class> clazz, String methodName, Class>... paramTypes) {
- return (getMethodIfAvailable(clazz, methodName, paramTypes) != null);
- }
-
- /**
- * Determine whether the given class has a public method with the given signature,
- * and return it if available (else return {@code null}).
- * In case of any signature specified, only returns the method if there is a
- * unique candidate, i.e. a single public method with the specified name.
- * Essentially translates {@code NoSuchMethodException} to {@code null}.
- *
- * @param clazz the clazz to analyze
- * @param methodName the name of the method
- * @param paramTypes the parameter types of the method
- * (may be {@code null} to indicate any signature)
- *
- * @return the method, or {@code null} if not found
- * @see Class#getMethod
- */
- public static Method getMethodIfAvailable(Class> clazz, String methodName, Class>... paramTypes) {
- Assert.notNull(clazz, "Class must not be null");
- Assert.notNull(methodName, "Method name must not be null");
- if (paramTypes != null) {
- try {
- return clazz.getMethod(methodName, paramTypes);
- } catch (NoSuchMethodException ex) {
- return null;
- }
- } else {
- Set In case of any signature specified, only returns the method if there is a
- * unique candidate, i.e. a single public method with the specified name.
- * Essentially translates {@code NoSuchMethodException} to {@code IllegalStateException}.
- *
- * @param clazz the clazz to analyze
- * @param methodName the name of the method
- * @param paramTypes the parameter types of the method
- * (may be {@code null} to indicate any signature)
- *
- * @return the method (never {@code null})
- * @throws IllegalStateException if the method has not been found
- * @see Class#getMethod
- */
- public static Method getMethod(Class> clazz, String methodName, Class>... paramTypes) {
- Assert.notNull(clazz, "Class must not be null");
- Assert.notNull(methodName, "Method name must not be null");
- if (paramTypes != null) {
- try {
- return clazz.getMethod(methodName, paramTypes);
- } catch (NoSuchMethodException ex) {
- throw new IllegalStateException("Expected method not found: " + ex);
- }
- } else {
- Set NOTE: In contrast to {@link org.springframework.aop.support.AopUtils#getMostSpecificMethod},
- * this method does not resolve Java 5 bridge methods automatically.
- * Call {@link org.springframework.core.BridgeMethodResolver#findBridgedMethod}
- * if bridge method resolution is desirable (e.g. for obtaining metadata from
- * the original method definition).
- * NOTE: Since Spring 3.1.1, if Java security settings disallow reflective
- * access (e.g. calls to {@code Class#getDeclaredMethods} etc, this implementation
- * will fall back to returning the originally provided method.
- *
- * @param method the method to be invoked, which may come from an interface
- * @param targetClass the target class for the current invocation.
- * May be {@code null} or may not even implement the method.
- *
- * @return the specific target method, or the original method if the
- * {@code targetClass} doesn't implement it or is {@code null}
- */
- public static Method getMostSpecificMethod(Method method, Class> targetClass) {
- if (targetClass != null && targetClass != method.getDeclaringClass() && isOverridable(method, targetClass)) {
- try {
- if (Modifier.isPublic(method.getModifiers())) {
- try {
- return targetClass.getMethod(method.getName(), method.getParameterTypes());
- } catch (NoSuchMethodException ex) {
- return method;
- }
- } else {
- Method specificMethod =
- ReflectionUtils.findMethod(targetClass, method.getName(), method.getParameterTypes());
- return (specificMethod != null ? specificMethod : method);
- }
- } catch (SecurityException ex) {
- // Security settings are disallowing reflective access; fall back to 'method' below.
- }
- }
- return method;
- }
-
- /**
- * Determine whether the given method is overridable in the given target class.
- *
- * @param method the method to check
- * @param targetClass the target class to check against
- */
- private static boolean isOverridable(Method method, Class> targetClass) {
- if (Modifier.isPrivate(method.getModifiers())) {
- return false;
- }
- if (Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers())) {
- return true;
- }
- return (targetClass == null ||
- getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass)));
- }
-
- /**
- * Determine the name of the package of the given class,
- * e.g. "java.lang" for the {@code java.lang.String} class.
- *
- * @param clazz the class
- *
- * @return the package name, or the empty String if the class
- * is defined in the default package
- */
- public static String getPackageName(Class> clazz) {
- Assert.notNull(clazz, "Class must not be null");
- return getPackageName(clazz.getName());
- }
-
- /**
- * Determine the name of the package of the given fully-qualified class name,
- * e.g. "java.lang" for the {@code java.lang.String} class name.
- *
- * @param fqClassName the fully-qualified class name
- *
- * @return the package name, or the empty String if the class
- * is defined in the default package
- */
- public static String getPackageName(String fqClassName) {
- Assert.notNull(fqClassName, "Class name must not be null");
- int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
- return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
- }
-
- /**
- * Determine whether the given method is declared by the user or at least pointing to
- * a user-declared method.
- * Checks {@link Method#isSynthetic()} (for implementation methods) as well as the
- * {@code GroovyObject} interface (for interface methods; on an implementation class,
- * implementations of the {@code GroovyObject} methods will be marked as synthetic anyway).
- * Note that, despite being synthetic, bridge methods ({@link Method#isBridge()}) are considered
- * as user-level methods since they are eventually pointing to a user-declared generic method.
- *
- * @param method the method to check
- *
- * @return {@code true} if the method can be considered as user-declared; [@code false} otherwise
- */
- public static boolean isUserLevelMethod(Method method) {
- Assert.notNull(method, "Method must not be null");
- return (method.isBridge() || (!method.isSynthetic() && !isGroovyObjectMethod(method)));
- }
-
- private static boolean isGroovyObjectMethod(Method method) {
- return method.getDeclaringClass().getName().equals("groovy.lang.GroovyObject");
- }
-
- /**
- * Return a public static method of a class.
- *
- * @param clazz the class which defines the method
- * @param methodName the static method name
- * @param args the parameter types to the method
- *
- * @return the static method, or {@code null} if no static method was found
- * @throws IllegalArgumentException if the method name is blank or the clazz is null
- */
- public static Method getStaticMethod(Class> clazz, String methodName, Class>... args) {
- Assert.notNull(clazz, "Class must not be null");
- Assert.notNull(methodName, "Method name must not be null");
- try {
- Method method = clazz.getMethod(methodName, args);
- return Modifier.isStatic(method.getModifiers()) ? method : null;
- } catch (NoSuchMethodException ex) {
- return null;
- }
- }
-
-}
diff --git a/src/main/java/com/antkorwin/xsync/springframework/util/CollectionUtils.java b/src/main/java/com/antkorwin/xsync/springframework/util/CollectionUtils.java
deleted file mode 100644
index a7e3eb6..0000000
--- a/src/main/java/com/antkorwin/xsync/springframework/util/CollectionUtils.java
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * Copyright 2002-2018 the original author or authors.
- *
- * Licensed 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 com.antkorwin.xsync.springframework.util;
-
-
-import java.io.Serializable;
-import java.util.*;
-
-/**
- * Miscellaneous collection utility methods.
- * Mainly for internal use within the framework.
- *
- * @author Juergen Hoeller
- * @author Rob Harrop
- * @author Arjen Poutsma
- * @since 1.1.3
- */
-public abstract class CollectionUtils {
-
- /**
- * Return {@code true} if the supplied Map is {@code null} or empty.
- * Otherwise, return {@code false}.
- *
- * @param map the Map to check
- *
- * @return whether the given Map is empty
- */
- public static boolean isEmpty(Map, ?> map) {
- return (map == null || map.isEmpty());
- }
-
- /**
- * Convert the supplied array into a List. A primitive array gets converted
- * into a List of the appropriate wrapper type.
- * NOTE: Generally prefer the standard {@link Arrays#asList} method.
- * This {@code arrayToList} method is just meant to deal with an incoming Object
- * value that might be an {@code Object[]} or a primitive array at runtime.
- * A {@code null} source value will be converted to an empty List.
- *
- * @param source the (potentially primitive) array
- *
- * @return the converted List result
- * @see ObjectUtils#toObjectArray(Object)
- * @see Arrays#asList(Object[])
- */
- @SuppressWarnings("rawtypes")
- public static List arrayToList(Object source) {
- return Arrays.asList(ObjectUtils.toObjectArray(source));
- }
-
- /**
- * Merge the given array into the given Collection.
- *
- * @param array the array to merge (may be {@code null})
- * @param collection the target Collection to merge the array into
- */
- @SuppressWarnings("unchecked")
- public static Uses {@code Properties.propertyNames()} to even catch
- * default properties linked into the original Properties instance.
- *
- * @param props the Properties instance to merge (may be {@code null})
- * @param map the target Map to merge the properties into
- */
- @SuppressWarnings("unchecked")
- public static Enforces the given instance to be present, rather than returning
- * {@code true} for an equal element as well.
- *
- * @param collection the Collection to check
- * @param element the element to look for
- *
- * @return {@code true} if found, {@code false} otherwise
- */
- public static boolean containsInstance(Collection> collection, Object element) {
- if (collection != null) {
- for (Object candidate : collection) {
- if (candidate == element) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Return {@code true} if any element in '{@code candidates}' is
- * contained in '{@code source}'; otherwise returns {@code false}.
- *
- * @param source the source Collection
- * @param candidates the candidates to search for
- *
- * @return whether any of the candidates has been found
- */
- public static boolean containsAny(Collection> source, Collection> candidates) {
- if (isEmpty(source) || isEmpty(candidates)) {
- return false;
- }
- for (Object candidate : candidates) {
- if (source.contains(candidate)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return {@code true} if the supplied Collection is {@code null} or empty.
- * Otherwise, return {@code false}.
- *
- * @param collection the Collection to check
- *
- * @return whether the given Collection is empty
- */
- public static boolean isEmpty(Collection> collection) {
- return (collection == null || collection.isEmpty());
- }
-
- /**
- * Return the first element in '{@code candidates}' that is contained in
- * '{@code source}'. If no element in '{@code candidates}' is present in
- * '{@code source}' returns {@code null}. Iteration order is
- * {@link Collection} implementation specific.
- *
- * @param source the source Collection
- * @param candidates the candidates to search for
- *
- * @return the first present object, or {@code null} if not found
- */
- @SuppressWarnings("unchecked")
- public static
- * This class can be used as an alternative to
- * {@code Collections.synchronizedMap(new WeakHashMap
- * NOTE: The use of references means that there is no guarantee that items
- * placed into the map will be subsequently available. The garbage collector may discard
- * references at any time, so it may appear that an unknown thread is silently removing
- * entries.
- *
- * If not explicitly specified, this implementation will use
- * {@linkplain SoftReference soft entry references}.
- *
- * @param
- * Mainly for internal use within the framework.
- *
- * Thanks to Alex Ruiz for contributing several enhancements to this class!
- *
- * @author Juergen Hoeller
- * @author Keith Donald
- * @author Rod Johnson
- * @author Rob Harrop
- * @author Chris Beams
- * @author Sam Brannen
- * @see ClassUtils
- * @see CollectionUtils
- * @see StringUtils
- * @since 19.03.2004
- */
-public abstract class ObjectUtils {
-
- private static final int INITIAL_HASH = 7;
- private static final int MULTIPLIER = 31;
-
- private static final String EMPTY_STRING = "";
- private static final String NULL_STRING = "null";
- private static final String ARRAY_START = "{";
- private static final String ARRAY_END = "}";
- private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END;
- private static final String ARRAY_ELEMENT_SEPARATOR = ", ";
-
- /**
- * Check whether the given exception is compatible with the specified
- * exception types, as declared in a throws clause.
- *
- * @param ex the exception to check
- * @param declaredExceptions the exception types declared in the throws clause
- *
- * @return whether the given exception is compatible
- */
- public static boolean isCompatibleWithThrowsClause(Throwable ex, Class>... declaredExceptions) {
- if (!isCheckedException(ex)) {
- return true;
- }
- if (declaredExceptions != null) {
- for (Class> declaredException : declaredExceptions) {
- if (declaredException.isInstance(ex)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Return whether the given throwable is a checked exception:
- * that is, neither a RuntimeException nor an Error.
- *
- * @param ex the throwable to check
- *
- * @return whether the throwable is a checked exception
- * @see Exception
- * @see RuntimeException
- * @see Error
- */
- public static boolean isCheckedException(Throwable ex) {
- return !(ex instanceof RuntimeException || ex instanceof Error);
- }
-
- /**
- * Determine whether the given object is an array:
- * either an Object array or a primitive array.
- *
- * @param obj the object to check
- */
- public static boolean isArray(Object obj) {
- return (obj != null && obj.getClass().isArray());
- }
-
- /**
- * Determine whether the given array is empty:
- * i.e. {@code null} or of zero length.
- *
- * @param array the array to check
- *
- * @see #isEmpty(Object)
- */
- public static boolean isEmpty(Object[] array) {
- return (array == null || array.length == 0);
- }
-
- /**
- * Determine whether the given object is empty.
- * This method supports the following object types.
- * If the given object is non-null and not one of the aforementioned
- * supported types, this method returns {@code false}.
- *
- * @param obj the object to check
- *
- * @return {@code true} if the object is {@code null} or empty
- * @see Optional#isPresent()
- * @see ObjectUtils#isEmpty(Object[])
- * @see StringUtils#hasLength(CharSequence)
- * @see StringUtils#isEmpty(Object)
- * @see CollectionUtils#isEmpty(Collection)
- * @see CollectionUtils#isEmpty(Map)
- * @since 4.2
- */
- @SuppressWarnings("rawtypes")
- public static boolean isEmpty(Object obj) {
- if (obj == null) {
- return true;
- }
-
- if (obj instanceof Optional) {
- return !((Optional) obj).isPresent();
- }
- if (obj instanceof CharSequence) {
- return ((CharSequence) obj).length() == 0;
- }
- if (obj.getClass().isArray()) {
- return Array.getLength(obj) == 0;
- }
- if (obj instanceof Collection) {
- return ((Collection) obj).isEmpty();
- }
- if (obj instanceof Map) {
- return ((Map) obj).isEmpty();
- }
-
- // else
- return false;
- }
-
- /**
- * Unwrap the given object which is potentially a {@link Optional}.
- *
- * @param obj the candidate object
- *
- * @return either the value held within the {@code Optional}, {@code null}
- * if the {@code Optional} is empty, or simply the given object as-is
- * @since 5.0
- */
- public static Object unwrapOptional(Object obj) {
- if (obj instanceof Optional) {
- Optional> optional = (Optional>) obj;
- if (!optional.isPresent()) {
- return null;
- }
- Object result = optional.get();
- Assert.isTrue(!(result instanceof Optional), "Multi-level Optional usage not supported");
- return result;
- }
- return obj;
- }
-
- /**
- * Check whether the given array contains the given element.
- *
- * @param array the array to check (may be {@code null},
- * in which case the return value will always be {@code false})
- * @param element the element to check for
- *
- * @return whether the element has been found in the given array
- */
- public static boolean containsElement(Object[] array, Object element) {
- if (array == null) {
- return false;
- }
- for (Object arrayEle : array) {
- if (nullSafeEquals(arrayEle, element)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Determine if the given objects are equal, returning {@code true} if
- * both are {@code null} or {@code false} if only one is {@code null}.
- * Compares arrays with {@code Arrays.equals}, performing an equality
- * check based on the array elements rather than the array reference.
- *
- * @param o1 first Object to compare
- * @param o2 second Object to compare
- *
- * @return whether the given objects are equal
- * @see Object#equals(Object)
- * @see Arrays#equals
- */
- public static boolean nullSafeEquals(Object o1, Object o2) {
- if (o1 == o2) {
- return true;
- }
- if (o1 == null || o2 == null) {
- return false;
- }
- if (o1.equals(o2)) {
- return true;
- }
- if (o1.getClass().isArray() && o2.getClass().isArray()) {
- return arrayEquals(o1, o2);
- }
- return false;
- }
-
- /**
- * Compare the given arrays with {@code Arrays.equals}, performing an equality
- * check based on the array elements rather than the array reference.
- *
- * @param o1 first array to compare
- * @param o2 second array to compare
- *
- * @return whether the given objects are equal
- * @see #nullSafeEquals(Object, Object)
- * @see Arrays#equals
- */
- private static boolean arrayEquals(Object o1, Object o2) {
- if (o1 instanceof Object[] && o2 instanceof Object[]) {
- return Arrays.equals((Object[]) o1, (Object[]) o2);
- }
- if (o1 instanceof boolean[] && o2 instanceof boolean[]) {
- return Arrays.equals((boolean[]) o1, (boolean[]) o2);
- }
- if (o1 instanceof byte[] && o2 instanceof byte[]) {
- return Arrays.equals((byte[]) o1, (byte[]) o2);
- }
- if (o1 instanceof char[] && o2 instanceof char[]) {
- return Arrays.equals((char[]) o1, (char[]) o2);
- }
- if (o1 instanceof double[] && o2 instanceof double[]) {
- return Arrays.equals((double[]) o1, (double[]) o2);
- }
- if (o1 instanceof float[] && o2 instanceof float[]) {
- return Arrays.equals((float[]) o1, (float[]) o2);
- }
- if (o1 instanceof int[] && o2 instanceof int[]) {
- return Arrays.equals((int[]) o1, (int[]) o2);
- }
- if (o1 instanceof long[] && o2 instanceof long[]) {
- return Arrays.equals((long[]) o1, (long[]) o2);
- }
- if (o1 instanceof short[] && o2 instanceof short[]) {
- return Arrays.equals((short[]) o1, (short[]) o2);
- }
- return false;
- }
-
- /**
- * Check whether the given array of enum constants contains a constant with the given name,
- * ignoring case when determining a match.
- *
- * @param enumValues the enum values to check, typically the product of a call to MyEnum.values()
- * @param constant the constant name to find (must not be null or empty string)
- *
- * @return whether the constant has been found in the given array
- */
- public static boolean containsConstant(Enum>[] enumValues, String constant) {
- return containsConstant(enumValues, constant, false);
- }
-
- /**
- * Check whether the given array of enum constants contains a constant with the given name.
- *
- * @param enumValues the enum values to check, typically the product of a call to MyEnum.values()
- * @param constant the constant name to find (must not be null or empty string)
- * @param caseSensitive whether case is significant in determining a match
- *
- * @return whether the constant has been found in the given array
- */
- public static boolean containsConstant(Enum>[] enumValues, String constant, boolean caseSensitive) {
- for (Enum> candidate : enumValues) {
- if (caseSensitive ?
- candidate.toString().equals(constant) :
- candidate.toString().equalsIgnoreCase(constant)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Case insensitive alternative to {@link Enum#valueOf(Class, String)}.
- *
- * @param A {@code null} source value will be converted to an
- * empty Object array.
- *
- * @param source the (potentially primitive) array
- *
- * @return the corresponding object array (never {@code null})
- * @throws IllegalArgumentException if the parameter is not an array
- */
- public static Object[] toObjectArray(Object source) {
- if (source instanceof Object[]) {
- return (Object[]) source;
- }
- if (source == null) {
- return new Object[0];
- }
- if (!source.getClass().isArray()) {
- throw new IllegalArgumentException("Source is not an array: " + source);
- }
- int length = Array.getLength(source);
- if (length == 0) {
- return new Object[0];
- }
- Class> wrapperType = Array.get(source, 0).getClass();
- Object[] newArray = (Object[]) Array.newInstance(wrapperType, length);
- for (int i = 0; i < length; i++) {
- newArray[i] = Array.get(source, i);
- }
- return newArray;
- }
-
- /**
- * Return as hash code for the given object; typically the value of
- * {@code Object#hashCode()}}. If the object is an array,
- * this method will delegate to any of the {@code nullSafeHashCode}
- * methods for arrays in this class. If the object is {@code null},
- * this method returns 0.
- *
- * @see Object#hashCode()
- * @see #nullSafeHashCode(Object[])
- * @see #nullSafeHashCode(boolean[])
- * @see #nullSafeHashCode(byte[])
- * @see #nullSafeHashCode(char[])
- * @see #nullSafeHashCode(double[])
- * @see #nullSafeHashCode(float[])
- * @see #nullSafeHashCode(int[])
- * @see #nullSafeHashCode(long[])
- * @see #nullSafeHashCode(short[])
- */
- public static int nullSafeHashCode(Object obj) {
- if (obj == null) {
- return 0;
- }
- if (obj.getClass().isArray()) {
- if (obj instanceof Object[]) {
- return nullSafeHashCode((Object[]) obj);
- }
- if (obj instanceof boolean[]) {
- return nullSafeHashCode((boolean[]) obj);
- }
- if (obj instanceof byte[]) {
- return nullSafeHashCode((byte[]) obj);
- }
- if (obj instanceof char[]) {
- return nullSafeHashCode((char[]) obj);
- }
- if (obj instanceof double[]) {
- return nullSafeHashCode((double[]) obj);
- }
- if (obj instanceof float[]) {
- return nullSafeHashCode((float[]) obj);
- }
- if (obj instanceof int[]) {
- return nullSafeHashCode((int[]) obj);
- }
- if (obj instanceof long[]) {
- return nullSafeHashCode((long[]) obj);
- }
- if (obj instanceof short[]) {
- return nullSafeHashCode((short[]) obj);
- }
- }
- return obj.hashCode();
- }
-
- /**
- * Return a hash code based on the contents of the specified array.
- * If {@code array} is {@code null}, this method returns 0.
- */
- public static int nullSafeHashCode(Object[] array) {
- if (array == null) {
- return 0;
- }
- int hash = INITIAL_HASH;
- for (Object element : array) {
- hash = MULTIPLIER * hash + nullSafeHashCode(element);
- }
- return hash;
- }
-
- /**
- * Return a hash code based on the contents of the specified array.
- * If {@code array} is {@code null}, this method returns 0.
- */
- public static int nullSafeHashCode(boolean[] array) {
- if (array == null) {
- return 0;
- }
- int hash = INITIAL_HASH;
- for (boolean element : array) {
- hash = MULTIPLIER * hash + Boolean.hashCode(element);
- }
- return hash;
- }
-
- /**
- * Return a hash code based on the contents of the specified array.
- * If {@code array} is {@code null}, this method returns 0.
- */
- public static int nullSafeHashCode(byte[] array) {
- if (array == null) {
- return 0;
- }
- int hash = INITIAL_HASH;
- for (byte element : array) {
- hash = MULTIPLIER * hash + element;
- }
- return hash;
- }
-
- /**
- * Return a hash code based on the contents of the specified array.
- * If {@code array} is {@code null}, this method returns 0.
- */
- public static int nullSafeHashCode(char[] array) {
- if (array == null) {
- return 0;
- }
- int hash = INITIAL_HASH;
- for (char element : array) {
- hash = MULTIPLIER * hash + element;
- }
- return hash;
- }
-
- /**
- * Return a hash code based on the contents of the specified array.
- * If {@code array} is {@code null}, this method returns 0.
- */
- public static int nullSafeHashCode(double[] array) {
- if (array == null) {
- return 0;
- }
- int hash = INITIAL_HASH;
- for (double element : array) {
- hash = MULTIPLIER * hash + Double.hashCode(element);
- }
- return hash;
- }
-
- /**
- * Return a hash code based on the contents of the specified array.
- * If {@code array} is {@code null}, this method returns 0.
- */
- public static int nullSafeHashCode(float[] array) {
- if (array == null) {
- return 0;
- }
- int hash = INITIAL_HASH;
- for (float element : array) {
- hash = MULTIPLIER * hash + Float.hashCode(element);
- }
- return hash;
- }
-
- /**
- * Return a hash code based on the contents of the specified array.
- * If {@code array} is {@code null}, this method returns 0.
- */
- public static int nullSafeHashCode(int[] array) {
- if (array == null) {
- return 0;
- }
- int hash = INITIAL_HASH;
- for (int element : array) {
- hash = MULTIPLIER * hash + element;
- }
- return hash;
- }
-
- /**
- * Return a hash code based on the contents of the specified array.
- * If {@code array} is {@code null}, this method returns 0.
- */
- public static int nullSafeHashCode(long[] array) {
- if (array == null) {
- return 0;
- }
- int hash = INITIAL_HASH;
- for (long element : array) {
- hash = MULTIPLIER * hash + Long.hashCode(element);
- }
- return hash;
- }
-
- /**
- * Return a hash code based on the contents of the specified array.
- * If {@code array} is {@code null}, this method returns 0.
- */
- public static int nullSafeHashCode(short[] array) {
- if (array == null) {
- return 0;
- }
- int hash = INITIAL_HASH;
- for (short element : array) {
- hash = MULTIPLIER * hash + element;
- }
- return hash;
- }
-
- /**
- * Return the same value as {@link Boolean#hashCode(boolean)}}.
- *
- * @deprecated as of Spring Framework 5.0, in favor of the native JDK 8 variant
- */
- @Deprecated
- public static int hashCode(boolean bool) {
- return Boolean.hashCode(bool);
- }
-
- /**
- * Return the same value as {@link Double#hashCode(double)}}.
- *
- * @deprecated as of Spring Framework 5.0, in favor of the native JDK 8 variant
- */
- @Deprecated
- public static int hashCode(double dbl) {
- return Double.hashCode(dbl);
- }
-
- /**
- * Return the same value as {@link Float#hashCode(float)}}.
- *
- * @deprecated as of Spring Framework 5.0, in favor of the native JDK 8 variant
- */
- @Deprecated
- public static int hashCode(float flt) {
- return Float.hashCode(flt);
- }
-
- /**
- * Return the same value as {@link Long#hashCode(long)}}.
- *
- * @deprecated as of Spring Framework 5.0, in favor of the native JDK 8 variant
- */
- @Deprecated
- public static int hashCode(long lng) {
- return Long.hashCode(lng);
- }
-
-
- //---------------------------------------------------------------------
- // Convenience methods for toString output
- //---------------------------------------------------------------------
-
- /**
- * Return a String representation of an object's overall identity.
- *
- * @param obj the object (may be {@code null})
- *
- * @return the object's identity as String representation,
- * or an empty String if the object was {@code null}
- */
- public static String identityToString(Object obj) {
- if (obj == null) {
- return EMPTY_STRING;
- }
- return obj.getClass().getName() + "@" + getIdentityHexString(obj);
- }
-
- /**
- * Return a hex String form of an object's identity hash code.
- *
- * @param obj the object
- *
- * @return the object's identity code in hex notation
- */
- public static String getIdentityHexString(Object obj) {
- return Integer.toHexString(System.identityHashCode(obj));
- }
-
- /**
- * Return a content-based String representation if {@code obj} is
- * not {@code null}; otherwise returns an empty String.
- * Differs from {@link #nullSafeToString(Object)} in that it returns
- * an empty String rather than "null" for a {@code null} value.
- *
- * @param obj the object to build a display String for
- *
- * @return a display String representation of {@code obj}
- * @see #nullSafeToString(Object)
- */
- public static String getDisplayString(Object obj) {
- if (obj == null) {
- return EMPTY_STRING;
- }
- return nullSafeToString(obj);
- }
-
- /**
- * Return a String representation of the specified Object.
- * Builds a String representation of the contents in case of an array.
- * Returns {@code "null"} if {@code obj} is {@code null}.
- *
- * @param obj the object to build a String representation for
- *
- * @return a String representation of {@code obj}
- */
- public static String nullSafeToString(Object obj) {
- if (obj == null) {
- return NULL_STRING;
- }
- if (obj instanceof String) {
- return (String) obj;
- }
- if (obj instanceof Object[]) {
- return nullSafeToString((Object[]) obj);
- }
- if (obj instanceof boolean[]) {
- return nullSafeToString((boolean[]) obj);
- }
- if (obj instanceof byte[]) {
- return nullSafeToString((byte[]) obj);
- }
- if (obj instanceof char[]) {
- return nullSafeToString((char[]) obj);
- }
- if (obj instanceof double[]) {
- return nullSafeToString((double[]) obj);
- }
- if (obj instanceof float[]) {
- return nullSafeToString((float[]) obj);
- }
- if (obj instanceof int[]) {
- return nullSafeToString((int[]) obj);
- }
- if (obj instanceof long[]) {
- return nullSafeToString((long[]) obj);
- }
- if (obj instanceof short[]) {
- return nullSafeToString((short[]) obj);
- }
- String str = obj.toString();
- return (str != null ? str : EMPTY_STRING);
- }
-
- /**
- * Return a String representation of the contents of the specified array.
- * The String representation consists of a list of the array's elements,
- * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
- * by the characters {@code ", "} (a comma followed by a space). Returns
- * {@code "null"} if {@code array} is {@code null}.
- *
- * @param array the array to build a String representation for
- *
- * @return a String representation of {@code array}
- */
- public static String nullSafeToString(Object[] array) {
- if (array == null) {
- return NULL_STRING;
- }
- int length = array.length;
- if (length == 0) {
- return EMPTY_ARRAY;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- if (i == 0) {
- sb.append(ARRAY_START);
- } else {
- sb.append(ARRAY_ELEMENT_SEPARATOR);
- }
- sb.append(String.valueOf(array[i]));
- }
- sb.append(ARRAY_END);
- return sb.toString();
- }
-
- /**
- * Return a String representation of the contents of the specified array.
- * The String representation consists of a list of the array's elements,
- * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
- * by the characters {@code ", "} (a comma followed by a space). Returns
- * {@code "null"} if {@code array} is {@code null}.
- *
- * @param array the array to build a String representation for
- *
- * @return a String representation of {@code array}
- */
- public static String nullSafeToString(boolean[] array) {
- if (array == null) {
- return NULL_STRING;
- }
- int length = array.length;
- if (length == 0) {
- return EMPTY_ARRAY;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- if (i == 0) {
- sb.append(ARRAY_START);
- } else {
- sb.append(ARRAY_ELEMENT_SEPARATOR);
- }
-
- sb.append(array[i]);
- }
- sb.append(ARRAY_END);
- return sb.toString();
- }
-
- /**
- * Return a String representation of the contents of the specified array.
- * The String representation consists of a list of the array's elements,
- * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
- * by the characters {@code ", "} (a comma followed by a space). Returns
- * {@code "null"} if {@code array} is {@code null}.
- *
- * @param array the array to build a String representation for
- *
- * @return a String representation of {@code array}
- */
- public static String nullSafeToString(byte[] array) {
- if (array == null) {
- return NULL_STRING;
- }
- int length = array.length;
- if (length == 0) {
- return EMPTY_ARRAY;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- if (i == 0) {
- sb.append(ARRAY_START);
- } else {
- sb.append(ARRAY_ELEMENT_SEPARATOR);
- }
- sb.append(array[i]);
- }
- sb.append(ARRAY_END);
- return sb.toString();
- }
-
- /**
- * Return a String representation of the contents of the specified array.
- * The String representation consists of a list of the array's elements,
- * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
- * by the characters {@code ", "} (a comma followed by a space). Returns
- * {@code "null"} if {@code array} is {@code null}.
- *
- * @param array the array to build a String representation for
- *
- * @return a String representation of {@code array}
- */
- public static String nullSafeToString(char[] array) {
- if (array == null) {
- return NULL_STRING;
- }
- int length = array.length;
- if (length == 0) {
- return EMPTY_ARRAY;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- if (i == 0) {
- sb.append(ARRAY_START);
- } else {
- sb.append(ARRAY_ELEMENT_SEPARATOR);
- }
- sb.append("'").append(array[i]).append("'");
- }
- sb.append(ARRAY_END);
- return sb.toString();
- }
-
- /**
- * Return a String representation of the contents of the specified array.
- * The String representation consists of a list of the array's elements,
- * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
- * by the characters {@code ", "} (a comma followed by a space). Returns
- * {@code "null"} if {@code array} is {@code null}.
- *
- * @param array the array to build a String representation for
- *
- * @return a String representation of {@code array}
- */
- public static String nullSafeToString(double[] array) {
- if (array == null) {
- return NULL_STRING;
- }
- int length = array.length;
- if (length == 0) {
- return EMPTY_ARRAY;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- if (i == 0) {
- sb.append(ARRAY_START);
- } else {
- sb.append(ARRAY_ELEMENT_SEPARATOR);
- }
-
- sb.append(array[i]);
- }
- sb.append(ARRAY_END);
- return sb.toString();
- }
-
- /**
- * Return a String representation of the contents of the specified array.
- * The String representation consists of a list of the array's elements,
- * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
- * by the characters {@code ", "} (a comma followed by a space). Returns
- * {@code "null"} if {@code array} is {@code null}.
- *
- * @param array the array to build a String representation for
- *
- * @return a String representation of {@code array}
- */
- public static String nullSafeToString(float[] array) {
- if (array == null) {
- return NULL_STRING;
- }
- int length = array.length;
- if (length == 0) {
- return EMPTY_ARRAY;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- if (i == 0) {
- sb.append(ARRAY_START);
- } else {
- sb.append(ARRAY_ELEMENT_SEPARATOR);
- }
-
- sb.append(array[i]);
- }
- sb.append(ARRAY_END);
- return sb.toString();
- }
-
- /**
- * Return a String representation of the contents of the specified array.
- * The String representation consists of a list of the array's elements,
- * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
- * by the characters {@code ", "} (a comma followed by a space). Returns
- * {@code "null"} if {@code array} is {@code null}.
- *
- * @param array the array to build a String representation for
- *
- * @return a String representation of {@code array}
- */
- public static String nullSafeToString(int[] array) {
- if (array == null) {
- return NULL_STRING;
- }
- int length = array.length;
- if (length == 0) {
- return EMPTY_ARRAY;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- if (i == 0) {
- sb.append(ARRAY_START);
- } else {
- sb.append(ARRAY_ELEMENT_SEPARATOR);
- }
- sb.append(array[i]);
- }
- sb.append(ARRAY_END);
- return sb.toString();
- }
-
- /**
- * Return a String representation of the contents of the specified array.
- * The String representation consists of a list of the array's elements,
- * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
- * by the characters {@code ", "} (a comma followed by a space). Returns
- * {@code "null"} if {@code array} is {@code null}.
- *
- * @param array the array to build a String representation for
- *
- * @return a String representation of {@code array}
- */
- public static String nullSafeToString(long[] array) {
- if (array == null) {
- return NULL_STRING;
- }
- int length = array.length;
- if (length == 0) {
- return EMPTY_ARRAY;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- if (i == 0) {
- sb.append(ARRAY_START);
- } else {
- sb.append(ARRAY_ELEMENT_SEPARATOR);
- }
- sb.append(array[i]);
- }
- sb.append(ARRAY_END);
- return sb.toString();
- }
-
- /**
- * Return a String representation of the contents of the specified array.
- * The String representation consists of a list of the array's elements,
- * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
- * by the characters {@code ", "} (a comma followed by a space). Returns
- * {@code "null"} if {@code array} is {@code null}.
- *
- * @param array the array to build a String representation for
- *
- * @return a String representation of {@code array}
- */
- public static String nullSafeToString(short[] array) {
- if (array == null) {
- return NULL_STRING;
- }
- int length = array.length;
- if (length == 0) {
- return EMPTY_ARRAY;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- if (i == 0) {
- sb.append(ARRAY_START);
- } else {
- sb.append(ARRAY_ELEMENT_SEPARATOR);
- }
- sb.append(array[i]);
- }
- sb.append(ARRAY_END);
- return sb.toString();
- }
-
- /**
- * Determine the class name for the given object.
- * Returns {@code "null"} if {@code obj} is {@code null}.
- *
- * @param obj the object to introspect (may be {@code null})
- *
- * @return the corresponding class name
- */
- public static String nullSafeClassName(Object obj) {
- return (obj != null ? obj.getClass().getName() : NULL_STRING);
- }
-
-}
diff --git a/src/main/java/com/antkorwin/xsync/springframework/util/ReflectionUtils.java b/src/main/java/com/antkorwin/xsync/springframework/util/ReflectionUtils.java
deleted file mode 100644
index cc8b952..0000000
--- a/src/main/java/com/antkorwin/xsync/springframework/util/ReflectionUtils.java
+++ /dev/null
@@ -1,893 +0,0 @@
-/*
- * Copyright 2002-2018 the original author or authors.
- *
- * Licensed 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 com.antkorwin.xsync.springframework.util;
-
-
-import java.lang.reflect.*;
-import java.sql.SQLException;
-import java.util.*;
-
-/**
- * Simple utility class for working with the reflection API and handling
- * reflection exceptions.
- *
- * Only intended for internal use.
- *
- * @author Juergen Hoeller
- * @author Rob Harrop
- * @author Rod Johnson
- * @author Costin Leau
- * @author Sam Brannen
- * @author Chris Beams
- * @since 1.2.2
- */
-public abstract class ReflectionUtils {
-
- /**
- * Pre-built FieldFilter that matches all non-static, non-final fields.
- */
- public static final FieldFilter COPYABLE_FIELDS =
- field -> !(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()));
- /**
- * Pre-built MethodFilter that matches all non-bridge methods.
- */
- public static final MethodFilter NON_BRIDGED_METHODS =
- (method -> !method.isBridge());
- /**
- * Pre-built MethodFilter that matches all non-bridge non-synthetic methods
- * which are not declared on {@code java.lang.Object}.
- */
- public static final MethodFilter USER_DECLARED_METHODS =
- (method -> (!method.isBridge() && !method.isSynthetic() && method.getDeclaringClass() != Object.class));
- /**
- * Naming prefix for CGLIB-renamed methods.
- *
- * @see #isCglibRenamedMethod
- */
- private static final String CGLIB_RENAMED_METHOD_PREFIX = "CGLIB$";
- private static final Method[] NO_METHODS = {};
- private static final Field[] NO_FIELDS = {};
- /**
- * Cache for {@link Class#getDeclaredMethods()} plus equivalent default methods
- * from Java 8 based interfaces, allowing for fast iteration.
- */
- private static final Map Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}.
- *
- * @param field the field to set
- * @param target the target object on which to set the field
- * @param value the value to set (may be {@code null})
- */
- public static void setField(Field field, Object target, Object value) {
- try {
- field.set(target, value);
- } catch (IllegalAccessException ex) {
- handleReflectionException(ex);
- throw new IllegalStateException(
- "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage());
- }
- }
-
- /**
- * Handle the given reflection exception. Should only be called if no
- * checked exception is expected to be thrown by the target method.
- * Throws the underlying RuntimeException or Error in case of an
- * InvocationTargetException with such a root cause. Throws an
- * IllegalStateException with an appropriate message or
- * UndeclaredThrowableException otherwise.
- *
- * @param ex the reflection exception to handle
- */
- public static void handleReflectionException(Exception ex) {
- if (ex instanceof NoSuchMethodException) {
- throw new IllegalStateException("Method not found: " + ex.getMessage());
- }
- if (ex instanceof IllegalAccessException) {
- throw new IllegalStateException("Could not access method: " + ex.getMessage());
- }
- if (ex instanceof InvocationTargetException) {
- handleInvocationTargetException((InvocationTargetException) ex);
- }
- if (ex instanceof RuntimeException) {
- throw (RuntimeException) ex;
- }
- throw new UndeclaredThrowableException(ex);
- }
-
- /**
- * Handle the given invocation target exception. Should only be called if no
- * checked exception is expected to be thrown by the target method.
- * Throws the underlying RuntimeException or Error in case of such a root
- * cause. Throws an UndeclaredThrowableException otherwise.
- *
- * @param ex the invocation target exception to handle
- */
- public static void handleInvocationTargetException(InvocationTargetException ex) {
- rethrowRuntimeException(ex.getTargetException());
- }
-
- /**
- * Rethrow the given {@link Throwable exception}, which is presumably the
- * target exception of an {@link InvocationTargetException}.
- * Should only be called if no checked exception is expected to be thrown
- * by the target method.
- * Rethrows the underlying exception cast to a {@link RuntimeException} or
- * {@link Error} if appropriate; otherwise, throws an
- * {@link UndeclaredThrowableException}.
- *
- * @param ex the exception to rethrow
- *
- * @throws RuntimeException the rethrown exception
- */
- public static void rethrowRuntimeException(Throwable ex) {
- if (ex instanceof RuntimeException) {
- throw (RuntimeException) ex;
- }
- if (ex instanceof Error) {
- throw (Error) ex;
- }
- throw new UndeclaredThrowableException(ex);
- }
-
- /**
- * Get the field represented by the supplied {@link Field field object} on the
- * specified {@link Object target object}. In accordance with {@link Field#get(Object)}
- * semantics, the returned value is automatically wrapped if the underlying field
- * has a primitive type.
- * Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}.
- *
- * @param field the field to get
- * @param target the target object from which to get the field
- *
- * @return the field's current value
- */
- public static Object getField(Field field, Object target) {
- try {
- return field.get(target);
- } catch (IllegalAccessException ex) {
- handleReflectionException(ex);
- throw new IllegalStateException(
- "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage());
- }
- }
-
- /**
- * Attempt to find a {@link Method} on the supplied class with the supplied name
- * and no parameters. Searches all superclasses up to {@code Object}.
- * Returns {@code null} if no {@link Method} can be found.
- *
- * @param clazz the class to introspect
- * @param name the name of the method
- *
- * @return the Method object, or {@code null} if none found
- */
- public static Method findMethod(Class> clazz, String name) {
- return findMethod(clazz, name, new Class>[0]);
- }
-
- /**
- * Attempt to find a {@link Method} on the supplied class with the supplied name
- * and parameter types. Searches all superclasses up to {@code Object}.
- * Returns {@code null} if no {@link Method} can be found.
- *
- * @param clazz the class to introspect
- * @param name the name of the method
- * @param paramTypes the parameter types of the method
- * (may be {@code null} to indicate any signature)
- *
- * @return the Method object, or {@code null} if none found
- */
- public static Method findMethod(Class> clazz, String name, Class>... paramTypes) {
- Assert.notNull(clazz, "Class must not be null");
- Assert.notNull(name, "Method name must not be null");
- Class> searchType = clazz;
- while (searchType != null) {
- Method[] methods = (searchType.isInterface() ? searchType.getMethods() : getDeclaredMethods(searchType));
- for (Method method : methods) {
- if (name.equals(method.getName()) &&
- (paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) {
- return method;
- }
- }
- searchType = searchType.getSuperclass();
- }
- return null;
- }
-
- /**
- * This variant retrieves {@link Class#getDeclaredMethods()} from a local cache
- * in order to avoid the JVM's SecurityManager check and defensive array copying.
- * In addition, it also includes Java 8 default methods from locally implemented
- * interfaces, since those are effectively to be treated just like declared methods.
- *
- * @param clazz the class to introspect
- *
- * @return the cached array of methods
- * @throws IllegalStateException if introspection fails
- * @see Class#getDeclaredMethods()
- */
- private static Method[] getDeclaredMethods(Class> clazz) {
- Assert.notNull(clazz, "Class must not be null");
- Method[] result = declaredMethodsCache.get(clazz);
- if (result == null) {
- try {
- Method[] declaredMethods = clazz.getDeclaredMethods();
- List Thrown exceptions are handled via a call to {@link #handleReflectionException}.
- *
- * @param method the method to invoke
- * @param target the target object to invoke the method on
- *
- * @return the invocation result, if any
- * @see #invokeMethod(Method, Object, Object[])
- */
- public static Object invokeMethod(Method method, Object target) {
- return invokeMethod(method, target, new Object[0]);
- }
-
- /**
- * Invoke the specified {@link Method} against the supplied target object with the
- * supplied arguments. The target object can be {@code null} when invoking a
- * static {@link Method}.
- * Thrown exceptions are handled via a call to {@link #handleReflectionException}.
- *
- * @param method the method to invoke
- * @param target the target object to invoke the method on
- * @param args the invocation arguments (may be {@code null})
- *
- * @return the invocation result, if any
- */
- public static Object invokeMethod(Method method, Object target, Object... args) {
- try {
- return method.invoke(target, args);
- } catch (Exception ex) {
- handleReflectionException(ex);
- }
- throw new IllegalStateException("Should never get here");
- }
-
- /**
- * Invoke the specified JDBC API {@link Method} against the supplied target
- * object with no arguments.
- *
- * @param method the method to invoke
- * @param target the target object to invoke the method on
- *
- * @return the invocation result, if any
- * @throws SQLException the JDBC API SQLException to rethrow (if any)
- * @see #invokeJdbcMethod(Method, Object, Object[])
- */
- public static Object invokeJdbcMethod(Method method, Object target) throws SQLException {
- return invokeJdbcMethod(method, target, new Object[0]);
- }
-
- /**
- * Invoke the specified JDBC API {@link Method} against the supplied target
- * object with the supplied arguments.
- *
- * @param method the method to invoke
- * @param target the target object to invoke the method on
- * @param args the invocation arguments (may be {@code null})
- *
- * @return the invocation result, if any
- * @throws SQLException the JDBC API SQLException to rethrow (if any)
- * @see #invokeMethod(Method, Object, Object[])
- */
- public static Object invokeJdbcMethod(Method method, Object target, Object... args)
- throws SQLException {
- try {
- return method.invoke(target, args);
- } catch (IllegalAccessException ex) {
- handleReflectionException(ex);
- } catch (InvocationTargetException ex) {
- if (ex.getTargetException() instanceof SQLException) {
- throw (SQLException) ex.getTargetException();
- }
- handleInvocationTargetException(ex);
- }
- throw new IllegalStateException("Should never get here");
- }
-
- /**
- * Rethrow the given {@link Throwable exception}, which is presumably the
- * target exception of an {@link InvocationTargetException}.
- * Should only be called if no checked exception is expected to be thrown
- * by the target method.
- * Rethrows the underlying exception cast to an {@link Exception} or
- * {@link Error} if appropriate; otherwise, throws an
- * {@link UndeclaredThrowableException}.
- *
- * @param ex the exception to rethrow
- *
- * @throws Exception the rethrown exception (in case of a checked exception)
- */
- public static void rethrowException(Throwable ex) throws Exception {
- if (ex instanceof Exception) {
- throw (Exception) ex;
- }
- if (ex instanceof Error) {
- throw (Error) ex;
- }
- throw new UndeclaredThrowableException(ex);
- }
-
- /**
- * Determine whether the given method explicitly declares the given
- * exception or one of its superclasses, which means that an exception
- * of that type can be propagated as-is within a reflective invocation.
- *
- * @param method the declaring method
- * @param exceptionType the exception to throw
- *
- * @return {@code true} if the exception can be thrown as-is;
- * {@code false} if it needs to be wrapped
- */
- public static boolean declaresException(Method method, Class> exceptionType) {
- Assert.notNull(method, "Method must not be null");
- Class>[] declaredExceptions = method.getExceptionTypes();
- for (Class> declaredException : declaredExceptions) {
- if (declaredException.isAssignableFrom(exceptionType)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Determine whether the given field is a "public static final" constant.
- *
- * @param field the field to check
- */
- public static boolean isPublicStaticFinal(Field field) {
- int modifiers = field.getModifiers();
- return (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers));
- }
-
- /**
- * Determine whether the given method is an "equals" method.
- *
- * @see Object#equals(Object)
- */
- public static boolean isEqualsMethod(Method method) {
- if (method == null || !method.getName().equals("equals")) {
- return false;
- }
- Class>[] paramTypes = method.getParameterTypes();
- return (paramTypes.length == 1 && paramTypes[0] == Object.class);
- }
-
- /**
- * Determine whether the given method is a "hashCode" method.
- *
- * @see Object#hashCode()
- */
- public static boolean isHashCodeMethod(Method method) {
- return (method != null && method.getName().equals("hashCode") && method.getParameterCount() == 0);
- }
-
- /**
- * Determine whether the given method is a "toString" method.
- *
- * @see Object#toString()
- */
- public static boolean isToStringMethod(Method method) {
- return (method != null && method.getName().equals("toString") && method.getParameterCount() == 0);
- }
-
- /**
- * Determine whether the given method is originally declared by {@link Object}.
- */
- public static boolean isObjectMethod(Method method) {
- if (method == null) {
- return false;
- }
- try {
- Object.class.getDeclaredMethod(method.getName(), method.getParameterTypes());
- return true;
- } catch (Exception ex) {
- return false;
- }
- }
-
- /**
- * Determine whether the given method is a CGLIB 'renamed' method,
- * following the pattern "CGLIB$methodName$0".
- *
- * @param renamedMethod the method to check
- *
- * @see org.springframework.cglib.proxy.Enhancer#rename
- */
- public static boolean isCglibRenamedMethod(Method renamedMethod) {
- String name = renamedMethod.getName();
- if (name.startsWith(CGLIB_RENAMED_METHOD_PREFIX)) {
- int i = name.length() - 1;
- while (i >= 0 && Character.isDigit(name.charAt(i))) {
- i--;
- }
- return ((i > CGLIB_RENAMED_METHOD_PREFIX.length()) &&
- (i < name.length() - 1) && name.charAt(i) == '$');
- }
- return false;
- }
-
- /**
- * Make the given method accessible, explicitly setting it accessible if
- * necessary. The {@code setAccessible(true)} method is only called
- * when actually necessary, to avoid unnecessary conflicts with a JVM
- * SecurityManager (if active).
- *
- * @param method the method to make accessible
- *
- * @see Method#setAccessible
- */
- @SuppressWarnings("deprecation") // on JDK 9
- public static void makeAccessible(Method method) {
- if ((!Modifier.isPublic(method.getModifiers()) ||
- !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {
- method.setAccessible(true);
- }
- }
-
- /**
- * Obtain an accessible constructor for the given class and parameters.
- *
- * @param clazz the clazz to check
- * @param parameterTypes the parameter types of the desired constructor
- *
- * @return the constructor reference
- * @throws NoSuchMethodException if no such constructor exists
- * @since 5.0
- */
- public static The same named method occurring on subclass and superclass will appear
- * twice, unless excluded by a {@link MethodFilter}.
- *
- * @param clazz the class to introspect
- * @param mc the callback to invoke for each method
- *
- * @throws IllegalStateException if introspection fails
- * @see #doWithMethods(Class, MethodCallback, MethodFilter)
- */
- public static void doWithMethods(Class> clazz, MethodCallback mc) {
- doWithMethods(clazz, mc, null);
- }
-
- /**
- * Perform the given callback operation on all matching methods of the given
- * class and superclasses (or given interface and super-interfaces).
- * The same named method occurring on subclass and superclass will appear
- * twice, unless excluded by the specified {@link MethodFilter}.
- *
- * @param clazz the class to introspect
- * @param mc the callback to invoke for each method
- * @param mf the filter that determines the methods to apply the callback to
- *
- * @throws IllegalStateException if introspection fails
- */
- public static void doWithMethods(Class> clazz, MethodCallback mc, MethodFilter mf) {
- // Keep backing up the inheritance hierarchy.
- Method[] methods = getDeclaredMethods(clazz);
- for (Method method : methods) {
- if (mf != null && !mf.matches(method)) {
- continue;
- }
- try {
- mc.doWith(method);
- } catch (IllegalAccessException ex) {
- throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
- }
- }
- if (clazz.getSuperclass() != null) {
- doWithMethods(clazz.getSuperclass(), mc, mf);
- } else if (clazz.isInterface()) {
- for (Class> superIfc : clazz.getInterfaces()) {
- doWithMethods(superIfc, mc, mf);
- }
- }
- }
-
- /**
- * Get all declared methods on the leaf class and all superclasses.
- * Leaf class methods are included first.
- *
- * @param leafClass the class to introspect
- *
- * @throws IllegalStateException if introspection fails
- */
- public static Method[] getAllDeclaredMethods(Class> leafClass) {
- final List
- * Mainly for internal use within the framework; consider
- * Apache's Commons Lang
- * for a more comprehensive suite of {@code String} utilities.
- *
- * This class delivers some simple functionality that should really be
- * provided by the core Java {@link String} and {@link StringBuilder}
- * classes. It also provides easy-to-use methods to convert between
- * delimited strings, such as CSV strings, and collections and arrays.
- *
- * @author Rod Johnson
- * @author Juergen Hoeller
- * @author Keith Donald
- * @author Rob Harrop
- * @author Rick Evans
- * @author Arjen Poutsma
- * @author Sam Brannen
- * @author Brian Clozel
- * @since 16 April 2001
- */
-public abstract class StringUtils {
-
- private static final String FOLDER_SEPARATOR = "/";
-
- private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
-
- private static final String TOP_PATH = "..";
-
- private static final String CURRENT_PATH = ".";
-
- private static final char EXTENSION_SEPARATOR = '.';
-
-
- //---------------------------------------------------------------------
- // General convenience methods for working with Strings
- //---------------------------------------------------------------------
-
- /**
- * Check whether the given {@code String} is empty.
- * This method accepts any Object as an argument, comparing it to
- * {@code null} and the empty String. As a consequence, this method
- * will never return {@code true} for a non-null non-String object.
- * The Object signature is useful for general attribute handling code
- * that commonly deals with Strings but generally has to iterate over
- * Objects since attributes may e.g. be primitive value objects as well.
- *
- * @param str the candidate String
- *
- * @since 3.2.1
- */
- public static boolean isEmpty(Object str) {
- return (str == null || "".equals(str));
- }
-
- /**
- * Check whether the given {@code CharSequence} contains actual text.
- * More specifically, this method returns {@code true} if the
- * {@code CharSequence} is not {@code null}, its length is greater than
- * 0, and it contains at least one non-whitespace character.
- * Note: this method returns {@code true} for a {@code CharSequence}
- * that purely consists of whitespace.
- * Note: this method returns {@code true} for a {@code String} that
- * purely consists of whitespace.
- *
- * @param str the {@code String} to check (may be {@code null})
- *
- * @return {@code true} if the {@code String} is not {@code null} and has length
- * @see #hasLength(CharSequence)
- * @see #hasText(String)
- */
- public static boolean hasLength(String str) {
- return (str != null && !str.isEmpty());
- }
-
- /**
- * Trim all whitespace from the given {@code String}:
- * leading, trailing, and in between characters.
- *
- * @param str the {@code String} to check
- *
- * @return the trimmed {@code String}
- * @see Character#isWhitespace
- */
- public static String trimAllWhitespace(String str) {
- if (!hasLength(str)) {
- return str;
- }
-
- int len = str.length();
- StringBuilder sb = new StringBuilder(str.length());
- for (int i = 0; i < len; i++) {
- char c = str.charAt(i);
- if (!Character.isWhitespace(c)) {
- sb.append(c);
- }
- }
- return sb.toString();
- }
-
- /**
- * Trim trailing whitespace from the given {@code String}.
- *
- * @param str the {@code String} to check
- *
- * @return the trimmed {@code String}
- * @see Character#isWhitespace
- */
- public static String trimTrailingWhitespace(String str) {
- if (!hasLength(str)) {
- return str;
- }
-
- StringBuilder sb = new StringBuilder(str);
- while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) {
- sb.deleteCharAt(sb.length() - 1);
- }
- return sb.toString();
- }
-
- /**
- * Trim all occurrences of the supplied trailing character from the given {@code String}.
- *
- * @param str the {@code String} to check
- * @param trailingCharacter the trailing character to be trimmed
- *
- * @return the trimmed {@code String}
- */
- public static String trimTrailingCharacter(String str, char trailingCharacter) {
- if (!hasLength(str)) {
- return str;
- }
-
- StringBuilder sb = new StringBuilder(str);
- while (sb.length() > 0 && sb.charAt(sb.length() - 1) == trailingCharacter) {
- sb.deleteCharAt(sb.length() - 1);
- }
- return sb.toString();
- }
-
- /**
- * Test if the given {@code String} starts with the specified prefix,
- * ignoring upper/lower case.
- *
- * @param str the {@code String} to check
- * @param prefix the prefix to look for
- *
- * @see String#startsWith
- */
- public static boolean startsWithIgnoreCase(String str, String prefix) {
- return (str != null && prefix != null && str.length() >= prefix.length() &&
- str.regionMatches(true, 0, prefix, 0, prefix.length()));
- }
-
- /**
- * Test if the given {@code String} ends with the specified suffix,
- * ignoring upper/lower case.
- *
- * @param str the {@code String} to check
- * @param suffix the suffix to look for
- *
- * @see String#endsWith
- */
- public static boolean endsWithIgnoreCase(String str, String suffix) {
- return (str != null && suffix != null && str.length() >= suffix.length() &&
- str.regionMatches(true, str.length() - suffix.length(), suffix, 0, suffix.length()));
- }
-
- /**
- * Test whether the given string matches the given substring
- * at the given index.
- *
- * @param str the original string (or StringBuilder)
- * @param index the index in the original string to start matching against
- * @param substring the substring to match at the given index
- */
- public static boolean substringMatch(CharSequence str, int index, CharSequence substring) {
- if (index + substring.length() > str.length()) {
- return false;
- }
- for (int i = 0; i < substring.length(); i++) {
- if (str.charAt(index + i) != substring.charAt(i)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Count the occurrences of the substring {@code sub} in string {@code str}.
- *
- * @param str string to search in
- * @param sub string to search for
- */
- public static int countOccurrencesOf(String str, String sub) {
- if (!hasLength(str) || !hasLength(sub)) {
- return 0;
- }
-
- int count = 0;
- int pos = 0;
- int idx;
- while ((idx = str.indexOf(sub, pos)) != -1) {
- ++count;
- pos = idx + sub.length();
- }
- return count;
- }
-
- /**
- * Delete all occurrences of the given substring.
- *
- * @param inString the original {@code String}
- * @param pattern the pattern to delete all occurrences of
- *
- * @return the resulting {@code String}
- */
- public static String delete(String inString, String pattern) {
- return replace(inString, pattern, "");
- }
-
- /**
- * Replace all occurrences of a substring within a string with another string.
- *
- * @param inString {@code String} to examine
- * @param oldPattern {@code String} to replace
- * @param newPattern {@code String} to insert
- *
- * @return a {@code String} with the replacements
- */
- public static String replace(String inString, String oldPattern, String newPattern) {
- if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) {
- return inString;
- }
- int index = inString.indexOf(oldPattern);
- if (index == -1) {
- // no occurrence -> can return input as-is
- return inString;
- }
-
- int capacity = inString.length();
- if (newPattern.length() > oldPattern.length()) {
- capacity += 16;
- }
- StringBuilder sb = new StringBuilder(capacity);
-
- int pos = 0; // our position in the old string
- int patLen = oldPattern.length();
- while (index >= 0) {
- sb.append(inString.substring(pos, index));
- sb.append(newPattern);
- pos = index + patLen;
- index = inString.indexOf(oldPattern, pos);
- }
-
- // append any characters to the right of a match
- sb.append(inString.substring(pos));
- return sb.toString();
- }
-
- /**
- * Turn the given Object into a {@code String} with single quotes
- * if it is a {@code String}; keeping the Object as-is else.
- *
- * @param obj the input Object (e.g. "myString")
- *
- * @return the quoted {@code String} (e.g. "'myString'"),
- * or the input object as-is if not a {@code String}
- */
- public static Object quoteIfString(Object obj) {
- return (obj instanceof String ? quote((String) obj) : obj);
- }
-
- /**
- * Quote the given {@code String} with single quotes.
- *
- * @param str the input {@code String} (e.g. "myString")
- *
- * @return the quoted {@code String} (e.g. "'myString'"),
- * or {@code null} if the input was {@code null}
- */
- public static String quote(String str) {
- return (str != null ? "'" + str + "'" : null);
- }
-
- /**
- * Unqualify a string qualified by a '.' dot character. For example,
- * "this.name.is.qualified", returns "qualified".
- *
- * @param qualifiedName the qualified name
- */
- public static String unqualify(String qualifiedName) {
- return unqualify(qualifiedName, '.');
- }
-
- /**
- * Unqualify a string qualified by a separator character. For example,
- * "this:name:is:qualified" returns "qualified" if using a ':' separator.
- *
- * @param qualifiedName the qualified name
- * @param separator the separator
- */
- public static String unqualify(String qualifiedName, char separator) {
- return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1);
- }
-
-
- //---------------------------------------------------------------------
- // Convenience methods for working with formatted Strings
- //---------------------------------------------------------------------
-
- /**
- * Capitalize a {@code String}, changing the first letter to
- * upper case as per {@link Character#toUpperCase(char)}.
- * No other letters are changed.
- *
- * @param str the {@code String} to capitalize
- *
- * @return the capitalized {@code String}
- */
- public static String capitalize(String str) {
- return changeFirstCharacterCase(str, true);
- }
-
- private static String changeFirstCharacterCase(String str, boolean capitalize) {
- if (!hasLength(str)) {
- return str;
- }
-
- char baseChar = str.charAt(0);
- char updatedChar;
- if (capitalize) {
- updatedChar = Character.toUpperCase(baseChar);
- } else {
- updatedChar = Character.toLowerCase(baseChar);
- }
- if (baseChar == updatedChar) {
- return str;
- }
-
- char[] chars = str.toCharArray();
- chars[0] = updatedChar;
- return new String(chars, 0, chars.length);
- }
-
- /**
- * Uncapitalize a {@code String}, changing the first letter to
- * lower case as per {@link Character#toLowerCase(char)}.
- * No other letters are changed.
- *
- * @param str the {@code String} to uncapitalize
- *
- * @return the uncapitalized {@code String}
- */
- public static String uncapitalize(String str) {
- return changeFirstCharacterCase(str, false);
- }
-
- /**
- * Extract the filename from the given Java resource path,
- * e.g. {@code "mypath/myfile.txt" -> "myfile.txt"}.
- *
- * @param path the file path (may be {@code null})
- *
- * @return the extracted filename, or {@code null} if none
- */
- public static String getFilename(String path) {
- if (path == null) {
- return null;
- }
-
- int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
- return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path);
- }
-
- /**
- * Extract the filename extension from the given Java resource path,
- * e.g. "mypath/myfile.txt" -> "txt".
- *
- * @param path the file path (may be {@code null})
- *
- * @return the extracted filename extension, or {@code null} if none
- */
- public static String getFilenameExtension(String path) {
- if (path == null) {
- return null;
- }
-
- int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
- if (extIndex == -1) {
- return null;
- }
-
- int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR);
- if (folderIndex > extIndex) {
- return null;
- }
-
- return path.substring(extIndex + 1);
- }
-
- /**
- * Strip the filename extension from the given Java resource path,
- * e.g. "mypath/myfile.txt" -> "mypath/myfile".
- *
- * @param path the file path
- *
- * @return the path with stripped filename extension
- */
- public static String stripFilenameExtension(String path) {
- int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
- if (extIndex == -1) {
- return path;
- }
-
- int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR);
- if (folderIndex > extIndex) {
- return path;
- }
-
- return path.substring(0, extIndex);
- }
-
- /**
- * Apply the given relative path to the given Java resource path,
- * assuming standard Java folder separation (i.e. "/" separators).
- *
- * @param path the path to start from (usually a full file path)
- * @param relativePath the relative path to apply
- * (relative to the full file path above)
- *
- * @return the full file path that results from applying the relative path
- */
- public static String applyRelativePath(String path, String relativePath) {
- int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
- if (separatorIndex != -1) {
- String newPath = path.substring(0, separatorIndex);
- if (!relativePath.startsWith(FOLDER_SEPARATOR)) {
- newPath += FOLDER_SEPARATOR;
- }
- return newPath + relativePath;
- } else {
- return relativePath;
- }
- }
-
- /**
- * Compare two paths after normalization of them.
- *
- * @param path1 first path for comparison
- * @param path2 second path for comparison
- *
- * @return whether the two paths are equivalent after normalization
- */
- public static boolean pathEquals(String path1, String path2) {
- return cleanPath(path1).equals(cleanPath(path2));
- }
-
- /**
- * Normalize the path by suppressing sequences like "path/.." and
- * inner simple dots.
- * The result is convenient for path comparison. For other uses,
- * notice that Windows separators ("\") are replaced by simple slashes.
- *
- * @param path the original path
- *
- * @return the normalized path
- */
- public static String cleanPath(String path) {
- if (!hasLength(path)) {
- return path;
- }
- String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR);
-
- // Strip prefix from path to analyze, to not treat it as part of the
- // first path element. This is necessary to correctly parse paths like
- // "file:core/../core/io/Resource.class", where the ".." should just
- // strip the first "core" directory while keeping the "file:" prefix.
- int prefixIndex = pathToUse.indexOf(':');
- String prefix = "";
- if (prefixIndex != -1) {
- prefix = pathToUse.substring(0, prefixIndex + 1);
- if (prefix.contains("/")) {
- prefix = "";
- } else {
- pathToUse = pathToUse.substring(prefixIndex + 1);
- }
- }
- if (pathToUse.startsWith(FOLDER_SEPARATOR)) {
- prefix = prefix + FOLDER_SEPARATOR;
- pathToUse = pathToUse.substring(1);
- }
-
- String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR);
- List A single {@code delimiter} may consist of more than one character,
- * but it will still be considered as a single delimiter string, rather
- * than as bunch of potential delimiter characters, in contrast to
- * {@link #tokenizeToStringArray}.
- *
- * @param str the input {@code String}
- * @param delimiter the delimiter between elements (this is a single delimiter,
- * rather than a bunch individual delimiter characters)
- *
- * @return an array of the tokens in the list
- * @see #tokenizeToStringArray
- */
- public static String[] delimitedListToStringArray(String str, String delimiter) {
- return delimitedListToStringArray(str, delimiter, null);
- }
-
- /**
- * Convert a {@code Collection} into a delimited {@code String} (e.g. CSV).
- * Useful for {@code toString()} implementations.
- *
- * @param coll the {@code Collection} to convert
- * @param delim the delimiter to use (typically a ",")
- *
- * @return the delimited {@code String}
- */
- public static String collectionToDelimitedString(Collection> coll, String delim) {
- return collectionToDelimitedString(coll, delim, "", "");
- }
-
- /**
- * Take a {@code String} that is a delimited list and convert it into
- * a {@code String} array.
- * A single {@code delimiter} may consist of more than one character,
- * but it will still be considered as a single delimiter string, rather
- * than as bunch of potential delimiter characters, in contrast to
- * {@link #tokenizeToStringArray}.
- *
- * @param str the input {@code String}
- * @param delimiter the delimiter between elements (this is a single delimiter,
- * rather than a bunch individual delimiter characters)
- * @param charsToDelete a set of characters to delete; useful for deleting unwanted
- * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a {@code String}
- *
- * @return an array of the tokens in the list
- * @see #tokenizeToStringArray
- */
- public static String[] delimitedListToStringArray(
- String str, String delimiter, String charsToDelete) {
-
- if (str == null) {
- return new String[0];
- }
- if (delimiter == null) {
- return new String[]{str};
- }
-
- List Useful for {@code toString()} implementations.
- *
- * @param coll the {@code Collection} to convert
- * @param delim the delimiter to use (typically a ",")
- * @param prefix the {@code String} to start each element with
- * @param suffix the {@code String} to end each element with
- *
- * @return the delimited {@code String}
- */
- public static String collectionToDelimitedString(
- Collection> coll, String delim, String prefix, String suffix) {
-
- if (CollectionUtils.isEmpty(coll)) {
- return "";
- }
-
- StringBuilder sb = new StringBuilder();
- Iterator> it = coll.iterator();
- while (it.hasNext()) {
- sb.append(prefix).append(it.next()).append(suffix);
- if (it.hasNext()) {
- sb.append(delim);
- }
- }
- return sb.toString();
- }
-
- /**
- * Delete any character in a given {@code String}.
- *
- * @param inString the original {@code String}
- * @param charsToDelete a set of characters to delete.
- * E.g. "az\n" will delete 'a's, 'z's and new lines.
- *
- * @return the resulting {@code String}
- */
- public static String deleteAny(String inString, String charsToDelete) {
- if (!hasLength(inString) || !hasLength(charsToDelete)) {
- return inString;
- }
-
- StringBuilder sb = new StringBuilder(inString.length());
- for (int i = 0; i < inString.length(); i++) {
- char c = inString.charAt(i);
- if (charsToDelete.indexOf(c) == -1) {
- sb.append(c);
- }
- }
- return sb.toString();
- }
-
- /**
- * Copy the given {@code Collection} into a {@code String} array.
- * The {@code Collection} must contain {@code String} elements only.
- *
- * @param collection the {@code Collection} to copy
- *
- * @return the {@code String} array
- */
- public static String[] toStringArray(Collection The given {@code delimiters} string can consist of any number of
- * delimiter characters. Each of those characters can be used to separate
- * tokens. A delimiter is always a single character; for multi-character
- * delimiters, consider using {@link #delimitedListToStringArray}.
- *
- * @param str the {@code String} to tokenize
- * @param delimiters the delimiter characters, assembled as a {@code String}
- * (each of the characters is individually considered as a delimiter)
- * @param trimTokens trim the tokens via {@link String#trim()}
- * @param ignoreEmptyTokens omit empty tokens from the result array
- * (only applies to tokens that are empty after trimming; StringTokenizer
- * will not consider subsequent delimiters as token in the first place).
- *
- * @return an array of the tokens
- * @see StringTokenizer
- * @see String#trim()
- * @see #delimitedListToStringArray
- */
- public static String[] tokenizeToStringArray(
- String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
-
- if (str == null) {
- return new String[0];
- }
-
- StringTokenizer st = new StringTokenizer(str, delimiters);
- List This is the inverse operation of {@link Locale#toString Locale's toString}.
- *
- * @param localeString the locale {@code String}: following {@code Locale's}
- * {@code toString()} format ("en", "en_UK", etc), also accepting spaces as
- * separators (as an alternative to underscores)
- * Note: This variant does not accept the BCP 47 language tag format.
- * Please use {@link #parseLocale} for lenient parsing of both formats.
- *
- * @return a corresponding {@code Locale} instance, or {@code null} if none
- * @throws IllegalArgumentException in case of an invalid locale specification
- */
- public static Locale parseLocaleString(String localeString) {
- return parseLocaleTokens(localeString, tokenizeLocaleSource(localeString));
- }
-
- /**
- * Determine the RFC 3066 compliant language tag,
- * as used for the HTTP "Accept-Language" header.
- *
- * @param locale the Locale to transform to a language tag
- *
- * @return the RFC 3066 compliant language tag as {@code String}
- * @deprecated as of 5.0.4, in favor of {@link Locale#toLanguageTag()}
- */
- @Deprecated
- public static String toLanguageTag(Locale locale) {
- return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : "");
- }
-
- /**
- * Check whether the given {@code String} contains actual text.
- * More specifically, this method returns {@code true} if the
- * {@code String} is not {@code null}, its length is greater than 0,
- * and it contains at least one non-whitespace character.
- *
- * @param str the {@code String} to check (may be {@code null})
- *
- * @return {@code true} if the {@code String} is not {@code null}, its
- * length is greater than 0, and it does not contain whitespace only
- * @see #hasText(CharSequence)
- */
- public static boolean hasText(String str) {
- return (str != null && !str.isEmpty() && containsText(str));
- }
-
- /**
- * Parse the given {@code timeZoneString} value into a {@link TimeZone}.
- *
- * @param timeZoneString the time zone {@code String}, following {@link TimeZone#getTimeZone(String)}
- * but throwing {@link IllegalArgumentException} in case of an invalid time zone specification
- *
- * @return a corresponding {@link TimeZone} instance
- * @throws IllegalArgumentException in case of an invalid time zone specification
- */
- public static TimeZone parseTimeZoneString(String timeZoneString) {
- TimeZone timeZone = TimeZone.getTimeZone(timeZoneString);
- if ("GMT".equals(timeZone.getID()) && !timeZoneString.startsWith("GMT")) {
- // We don't want that GMT fallback...
- throw new IllegalArgumentException("Invalid time zone specification '" + timeZoneString + "'");
- }
- return timeZone;
- }
-
- /**
- * Append the given {@code String} to the given {@code String} array,
- * returning a new array consisting of the input array contents plus
- * the given {@code String}.
- *
- * @param array the array to append to (can be {@code null})
- * @param str the {@code String} to append
- *
- * @return the new array (never {@code null})
- */
- public static String[] addStringToArray(String[] array, String str) {
- if (ObjectUtils.isEmpty(array)) {
- return new String[]{str};
- }
-
- String[] newArr = new String[array.length + 1];
- System.arraycopy(array, 0, newArr, 0, array.length);
- newArr[array.length] = str;
- return newArr;
- }
-
- /**
- * Concatenate the given {@code String} arrays into one,
- * with overlapping array elements included twice.
- * The order of elements in the original arrays is preserved.
- *
- * @param array1 the first array (can be {@code null})
- * @param array2 the second array (can be {@code null})
- *
- * @return the new array ({@code null} if both given arrays were {@code null})
- */
- public static String[] concatenateStringArrays(String[] array1, String[] array2) {
- if (ObjectUtils.isEmpty(array1)) {
- return array2;
- }
- if (ObjectUtils.isEmpty(array2)) {
- return array1;
- }
-
- String[] newArr = new String[array1.length + array2.length];
- System.arraycopy(array1, 0, newArr, 0, array1.length);
- System.arraycopy(array2, 0, newArr, array1.length, array2.length);
- return newArr;
- }
-
- /**
- * Merge the given {@code String} arrays into one, with overlapping
- * array elements only included once.
- * The order of elements in the original arrays is preserved
- * (with the exception of overlapping elements, which are only
- * included on their first occurrence).
- *
- * @param array1 the first array (can be {@code null})
- * @param array2 the second array (can be {@code null})
- *
- * @return the new array ({@code null} if both given arrays were {@code null})
- * @deprecated as of 4.3.15, in favor of manual merging via {@link LinkedHashSet}
- * (with every entry included at most once, even entries within the first array)
- */
- @Deprecated
- public static String[] mergeStringArrays(String[] array1, String[] array2) {
- if (ObjectUtils.isEmpty(array1)) {
- return array2;
- }
- if (ObjectUtils.isEmpty(array2)) {
- return array1;
- }
-
- List As of 4.2, it preserves the original order, as it uses a {@link LinkedHashSet}.
- *
- * @param array the {@code String} array
- *
- * @return an array without duplicates, in natural sort order
- */
- public static String[] removeDuplicateStrings(String[] array) {
- if (ObjectUtils.isEmpty(array)) {
- return array;
- }
-
- Set Will trim both the key and value before adding them to the {@code Properties}.
- *
- * @param array the array to process
- * @param delimiter to split each element using (typically the equals symbol)
- *
- * @return a {@code Properties} instance representing the array contents,
- * or {@code null} if the array to process was {@code null} or empty
- */
- public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) {
- return splitArrayElementsIntoProperties(array, delimiter, null);
- }
-
- /**
- * Take an array of strings and split each element based on the given delimiter.
- * A {@code Properties} instance is then generated, with the left of the
- * delimiter providing the key, and the right of the delimiter providing the value.
- * Will trim both the key and value before adding them to the
- * {@code Properties} instance.
- *
- * @param array the array to process
- * @param delimiter to split each element using (typically the equals symbol)
- * @param charsToDelete one or more characters to remove from each element
- * prior to attempting the split operation (typically the quotation mark
- * symbol), or {@code null} if no removal should occur
- *
- * @return a {@code Properties} instance representing the array contents,
- * or {@code null} if the array to process was {@code null} or empty
- */
- public static Properties splitArrayElementsIntoProperties(
- String[] array, String delimiter, String charsToDelete) {
-
- if (ObjectUtils.isEmpty(array)) {
- return null;
- }
-
- Properties result = new Properties();
- for (String element : array) {
- if (charsToDelete != null) {
- element = deleteAny(element, charsToDelete);
- }
- String[] splittedElement = split(element, delimiter);
- if (splittedElement == null) {
- continue;
- }
- result.setProperty(splittedElement[0].trim(), splittedElement[1].trim());
- }
- return result;
- }
-
- /**
- * Split a {@code String} at the first occurrence of the delimiter.
- * Does not include the delimiter in the result.
- *
- * @param toSplit the string to split
- * @param delimiter to split the string up with
- *
- * @return a two element array with index 0 being before the delimiter, and
- * index 1 being after the delimiter (neither element includes the delimiter);
- * or {@code null} if the delimiter wasn't found in the given input {@code String}
- */
- public static String[] split(String toSplit, String delimiter) {
- if (!hasLength(toSplit) || !hasLength(delimiter)) {
- return null;
- }
- int offset = toSplit.indexOf(delimiter);
- if (offset < 0) {
- return null;
- }
-
- String beforeDelimiter = toSplit.substring(0, offset);
- String afterDelimiter = toSplit.substring(offset + delimiter.length());
- return new String[]{beforeDelimiter, afterDelimiter};
- }
-
- /**
- * Tokenize the given {@code String} into a {@code String} array via a
- * {@link StringTokenizer}.
- * Trims tokens and omits empty tokens.
- * The given {@code delimiters} string can consist of any number of
- * delimiter characters. Each of those characters can be used to separate
- * tokens. A delimiter is always a single character; for multi-character
- * delimiters, consider using {@link #delimitedListToStringArray}.
- *
- * @param str the {@code String} to tokenize
- * @param delimiters the delimiter characters, assembled as a {@code String}
- * (each of the characters is individually considered as a delimiter)
- *
- * @return an array of the tokens
- * @see StringTokenizer
- * @see String#trim()
- * @see #delimitedListToStringArray
- */
- public static String[] tokenizeToStringArray(String str, String delimiters) {
- return tokenizeToStringArray(str, delimiters, true, true);
- }
-
- /**
- * Convert a comma delimited list (e.g., a row from a CSV file) into a set.
- * Note that this will suppress duplicates, and as of 4.2, the elements in
- * the returned set will preserve the original order in a {@link LinkedHashSet}.
- *
- * @param str the input {@code String}
- *
- * @return a set of {@code String} entries in the list
- * @see #removeDuplicateStrings(String[])
- */
- public static Set Useful for {@code toString()} implementations.
- *
- * @param coll the {@code Collection} to convert
- *
- * @return the delimited {@code String}
- */
- public static String collectionToCommaDelimitedString(Collection> coll) {
- return collectionToDelimitedString(coll, ",");
- }
-
- /**
- * Convert a {@code String} array into a comma delimited {@code String}
- * (i.e., CSV).
- * Useful for {@code toString()} implementations.
- *
- * @param arr the array to display
- *
- * @return the delimited {@code String}
- */
- public static String arrayToCommaDelimitedString(Object[] arr) {
- return arrayToDelimitedString(arr, ",");
- }
-
- /**
- * Convert a {@code String} array into a delimited {@code String} (e.g. CSV).
- * Useful for {@code toString()} implementations.
- *
- * @param arr the array to display
- * @param delim the delimiter to use (typically a ",")
- *
- * @return the delimited {@code String}
- */
- public static String arrayToDelimitedString(Object[] arr, String delim) {
- if (ObjectUtils.isEmpty(arr)) {
- return "";
- }
- if (arr.length == 1) {
- return ObjectUtils.nullSafeToString(arr[0]);
- }
-
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < arr.length; i++) {
- if (i > 0) {
- sb.append(delim);
- }
- sb.append(arr[i]);
- }
- return sb.toString();
- }
-
-}
diff --git a/src/test/java/com/antkorwin/xsync/XMutexFactoryTest.java b/src/test/java/com/antkorwin/xsync/XMutexFactoryTest.java
index 627edcd..55f00ac 100644
--- a/src/test/java/com/antkorwin/xsync/XMutexFactoryTest.java
+++ b/src/test/java/com/antkorwin/xsync/XMutexFactoryTest.java
@@ -2,9 +2,10 @@
import com.antkorwin.commonutils.concurrent.ConcurrentSet;
import com.antkorwin.commonutils.gc.GcUtils;
-import com.antkorwin.xsync.springframework.util.ConcurrentReferenceHashMap;
+
import org.assertj.core.api.Assertions;
import org.junit.Test;
+import org.springframework.util.ConcurrentReferenceHashMap;
import java.util.*;
import java.util.concurrent.TimeUnit;
@@ -23,7 +24,7 @@
public class XMutexFactoryTest {
private static final int TIMEOUT_FOR_PREVENTION_OF_DEADLOCK = 30000;
- private static final int NUMBER_OF_MUTEXES = 100000;
+ private static final int NUMBER_OF_MUTEXES = 100_000;
private static final int NUMBER_OF_ITERATIONS = NUMBER_OF_MUTEXES * 100;
private static final String ID_STRING = "c117c526-606e-41b6-8197-1a6ba779f69b";
@@ -34,7 +35,7 @@ public void testGetSameMutexFromTwoDifferentInstanceOfEqualsKeys() {
UUID firstId = UUID.fromString(ID_STRING);
UUID secondId = UUID.fromString(ID_STRING);
// Check precondition
- Assertions.assertThat(firstId != secondId).isTrue();
+ Assertions.assertThat(firstId).isNotSameAs(secondId);
Assertions.assertThat(firstId).isEqualTo(secondId);
// Act
@@ -45,7 +46,7 @@ public void testGetSameMutexFromTwoDifferentInstanceOfEqualsKeys() {
Assertions.assertThat(firstMutex).isNotNull();
Assertions.assertThat(secondMutex).isNotNull();
Assertions.assertThat(firstMutex).isEqualTo(secondMutex);
- Assertions.assertThat(firstMutex == secondMutex).isTrue();
+ Assertions.assertThat(firstMutex).isSameAs(secondMutex);
}
@Test
@@ -134,7 +135,7 @@ public void testALotOfHashCodes() {
// because the GC can delete a unused references:
resultReferences.add(mutex);
// Assert
- Assertions.assertThat(mutex == firstMutex).isTrue();
+ Assertions.assertThat(mutex).isSameAs(firstMutex);
}
// Assertions
diff --git a/src/test/java/com/antkorwin/xsync/XMutexTest.java b/src/test/java/com/antkorwin/xsync/XMutexTest.java
index 6a94b24..4e33c0b 100755
--- a/src/test/java/com/antkorwin/xsync/XMutexTest.java
+++ b/src/test/java/com/antkorwin/xsync/XMutexTest.java
@@ -24,8 +24,9 @@ public void testMutexEquals() {
XMutex> values() {
- return this.map.values();
- }
-
- @Override
- public Set
- *
- *
- * StringUtils.hasText(null) = false
- * StringUtils.hasText("") = false
- * StringUtils.hasText(" ") = false
- * StringUtils.hasText("12345") = true
- * StringUtils.hasText(" 12345 ") = true
- *
- *
- * @param str the {@code CharSequence} to check (may be {@code null})
- *
- * @return {@code true} if the {@code CharSequence} is not {@code null},
- * its length is greater than 0, and it does not contain whitespace only
- * @see Character#isWhitespace
- */
- public static boolean hasText(CharSequence str) {
- return (str != null && str.length() > 0 && containsText(str));
- }
-
- private static boolean containsText(CharSequence str) {
- int strLen = str.length();
- for (int i = 0; i < strLen; i++) {
- if (!Character.isWhitespace(str.charAt(i))) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Check whether the given {@code String} contains any whitespace characters.
- *
- * @param str the {@code String} to check (may be {@code null})
- *
- * @return {@code true} if the {@code String} is not empty and
- * contains at least 1 whitespace character
- * @see #containsWhitespace(CharSequence)
- */
- public static boolean containsWhitespace(String str) {
- return containsWhitespace((CharSequence) str);
- }
-
- /**
- * Check whether the given {@code CharSequence} contains any whitespace characters.
- *
- * @param str the {@code CharSequence} to check (may be {@code null})
- *
- * @return {@code true} if the {@code CharSequence} is not empty and
- * contains at least 1 whitespace character
- * @see Character#isWhitespace
- */
- public static boolean containsWhitespace(CharSequence str) {
- if (!hasLength(str)) {
- return false;
- }
-
- int strLen = str.length();
- for (int i = 0; i < strLen; i++) {
- if (Character.isWhitespace(str.charAt(i))) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Check that the given {@code CharSequence} is neither {@code null} nor
- * of length 0.
- *
- * StringUtils.hasLength(null) = false
- * StringUtils.hasLength("") = false
- * StringUtils.hasLength(" ") = true
- * StringUtils.hasLength("Hello") = true
- *
- *
- * @param str the {@code CharSequence} to check (may be {@code null})
- *
- * @return {@code true} if the {@code CharSequence} is not {@code null} and has length
- * @see #hasText(String)
- */
- public static boolean hasLength(CharSequence str) {
- return (str != null && str.length() > 0);
- }
-
- /**
- * Trim leading and trailing whitespace from the given {@code String}.
- *
- * @param str the {@code String} to check
- *
- * @return the trimmed {@code String}
- * @see Character#isWhitespace
- */
- public static String trimWhitespace(String str) {
- if (!hasLength(str)) {
- return str;
- }
-
- int beginIndex = 0;
- int endIndex = str.length() - 1;
-
- while (beginIndex <= endIndex && Character.isWhitespace(str.charAt(beginIndex))) {
- beginIndex++;
- }
-
- while (endIndex > beginIndex && Character.isWhitespace(str.charAt(endIndex))) {
- endIndex--;
- }
-
- return str.substring(beginIndex, endIndex + 1);
- }
-
- /**
- * Check that the given {@code String} is neither {@code null} nor of length 0.
- *
- *
- *
- * @param source the encoded String
- * @param charset the character set
- *
- * @return the decoded value
- * @throws IllegalArgumentException when the given source contains invalid encoded sequences
- * @see java.net.URLDecoder#decode(String, String)
- * @since 5.0
- */
- public static String uriDecode(String source, Charset charset) {
- int length = source.length();
- if (length == 0) {
- return source;
- }
- Assert.notNull(charset, "Charset must not be null");
-
- ByteArrayOutputStream bos = new ByteArrayOutputStream(length);
- boolean changed = false;
- for (int i = 0; i < length; i++) {
- int ch = source.charAt(i);
- if (ch == '%') {
- if (i + 2 < length) {
- char hex1 = source.charAt(i + 1);
- char hex2 = source.charAt(i + 2);
- int u = Character.digit(hex1, 16);
- int l = Character.digit(hex2, 16);
- if (u == -1 || l == -1) {
- throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
- }
- bos.write((char) ((u << 4) + l));
- i += 2;
- changed = true;
- } else {
- throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
- }
- } else {
- bos.write(ch);
- }
- }
- return (changed ? new String(bos.toByteArray(), charset) : source);
- }
-
- /**
- * Parse the given {@code String} value into a {@link Locale}, accepting
- * the {@link Locale#toString} format as well as BCP 47 language tags.
- *
- * @param localeValue the locale value: following either {@code Locale's}
- * {@code toString()} format ("en", "en_UK", etc), also accepting spaces as
- * separators (as an alternative to underscores), or BCP 47 (e.g. "en-UK")
- * as specified by {@link Locale#forLanguageTag} on Java 7+
- *
- * @return a corresponding {@code Locale} instance, or {@code null} if none
- * @throws IllegalArgumentException in case of an invalid locale specification
- * @see #parseLocaleString
- * @see Locale#forLanguageTag
- * @since 5.0.4
- */
- public static Locale parseLocale(String localeValue) {
- String[] tokens = tokenizeLocaleSource(localeValue);
- if (tokens.length == 1) {
- return Locale.forLanguageTag(localeValue);
- }
- return parseLocaleTokens(localeValue, tokens);
- }
-
- private static String[] tokenizeLocaleSource(String localeSource) {
- return tokenizeToStringArray(localeSource, "_ ", false, false);
- }
-
- private static Locale parseLocaleTokens(String localeString, String[] tokens) {
- String language = (tokens.length > 0 ? tokens[0] : "");
- String country = (tokens.length > 1 ? tokens[1] : "");
- validateLocalePart(language);
- validateLocalePart(country);
-
- String variant = "";
- if (tokens.length > 2) {
- // There is definitely a variant, and it is everything after the country
- // code sans the separator between the country code and the variant.
- int endIndexOfCountryCode = localeString.indexOf(country, language.length()) + country.length();
- // Strip off any leading '_' and whitespace, what's left is the variant.
- variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode));
- if (variant.startsWith("_")) {
- variant = trimLeadingCharacter(variant, '_');
- }
- }
- return (language.length() > 0 ? new Locale(language, country, variant) : null);
- }
-
- /**
- * Tokenize the given {@code String} into a {@code String} array via a
- * {@link StringTokenizer}.
- *