org.apache.juneau.internal.ClassUtils Maven / Gradle / Ivy
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
// * with the License. You may obtain a copy of the License at *
// * *
// * http://www.apache.org/licenses/LICENSE-2.0 *
// * *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
package org.apache.juneau.internal;
import static org.apache.juneau.internal.ClassFlags.*;
import static org.apache.juneau.internal.CollectionUtils.*;
import java.io.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.*;
import org.apache.juneau.*;
import org.apache.juneau.utils.*;
/**
* Class-related utility methods.
*/
public final class ClassUtils {
private static final Map,ConstructorCacheEntry> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>();
/**
* Given the specified list of objects, return readable names for the class types of the objects.
*
* @param o The objects.
* @return An array of readable class type strings.
*/
public static ObjectList getReadableClassNames(Object[] o) {
ObjectList l = new ObjectList();
for (int i = 0; i < o.length; i++)
l.add(o[i] == null ? "null" : getReadableClassName(o[i].getClass()));
return l;
}
/**
* Shortcut for calling getReadableClassName (c.getName())
*
* @param c The class.
* @return A readable class type name, or null if parameter is null .
*/
public static String getReadableClassName(Class> c) {
if (c == null)
return null;
return getReadableClassName(c.getName());
}
/**
* Shortcut for calling getReadableClassName (c.getClass().getName())
*
* @param o The object whose class we want to render.
* @return A readable class type name, or null if parameter is null .
*/
public static String getReadableClassNameForObject(Object o) {
if (o == null)
return null;
return getReadableClassName(o.getClass().getName());
}
/**
* Converts the specified class name to a readable form when class name is a special construct like "[[Z" .
*
* Example:
*
* getReadableClassName ("java.lang.Object" ); // Returns "java.lang.Object"
* getReadableClassName ("boolean" ); // Returns "boolean"
* getReadableClassName ("[Z" ); // Returns "boolean[]"
* getReadableClassName ("[[Z" ); // Returns "boolean[][]"
* getReadableClassName ("[Ljava.lang.Object;" ); // Returns "java.lang.Object[]"
* getReadableClassName (null ); // Returns null
*
*
* @param className The class name.
* @return A readable class type name, or null if parameter is null .
*/
public static String getReadableClassName(String className) {
if (className == null)
return null;
if (! StringUtils.startsWith(className, '['))
return className;
int depth = 0;
for (int i = 0; i < className.length(); i++) {
if (className.charAt(i) == '[')
depth++;
else
break;
}
char type = className.charAt(depth);
String c;
switch (type) {
case 'Z': c = "boolean"; break;
case 'B': c = "byte"; break;
case 'C': c = "char"; break;
case 'D': c = "double"; break;
case 'F': c = "float"; break;
case 'I': c = "int"; break;
case 'J': c = "long"; break;
case 'S': c = "short"; break;
default: c = className.substring(depth+1, className.length()-1);
}
StringBuilder sb = new StringBuilder(c.length() + 2*depth).append(c);
for (int i = 0; i < depth; i++)
sb.append("[]");
return sb.toString();
}
/**
* Converts the string generated by {@link #getReadableClassName(Class)} back into a {@link Class}.
*
*
* Generics are stripped from the string since they cannot be converted to a class.
*
* @param cl The classloader to use to load the class.
* @param name The readable class name.
* @return The class object.
* @throws ClassNotFoundException
*/
public static Class> getClassFromReadableName(ClassLoader cl, String name) throws ClassNotFoundException {
return cl.loadClass(name);
}
/**
* Returns true if parent
is a parent class of child
.
*
* @param parent The parent class.
* @param child The child class.
* @param strict If true returns false if the classes are the same.
* @return true if parent
is a parent class of child
.
*/
public static boolean isParentClass(Class> parent, Class> child, boolean strict) {
return parent.isAssignableFrom(child) && ((!strict) || ! parent.equals(child));
}
/**
* Returns true if parent
is a parent class or the same as child
.
*
* @param parent The parent class.
* @param child The child class.
* @return true if parent
is a parent class or the same as child
.
*/
public static boolean isParentClass(Class> parent, Class> child) {
return isParentClass(parent, child, false);
}
/**
* Returns true if parent
is a parent class or the same as child
.
*
* @param parent The parent class.
* @param child The child class.
* @return true if parent
is a parent class or the same as child
.
*/
public static boolean isParentClass(Class> parent, Type child) {
if (child instanceof Class)
return isParentClass(parent, (Class>)child);
return false;
}
/**
* Returns the signature of the specified method.
*
*
* For no-arg methods, the signature will be a simple string such as "toString" .
* For methods with one or more args, the arguments will be fully-qualified class names (e.g.
* "append(java.util.StringBuilder,boolean)" )
*
* @param m The methods to get the signature on.
* @return The methods signature.
*/
public static String getMethodSignature(Method m) {
StringBuilder sb = new StringBuilder(m.getName());
Class>[] pt = m.getParameterTypes();
if (pt.length > 0) {
sb.append('(');
for (int i = 0; i < pt.length; i++) {
if (i > 0)
sb.append(',');
sb.append(getReadableClassName(pt[i]));
}
sb.append(')');
}
return sb.toString();
}
private static final Map, Class>>
pmap1 = new HashMap<>(),
pmap2 = new HashMap<>();
static {
pmap1.put(boolean.class, Boolean.class);
pmap1.put(byte.class, Byte.class);
pmap1.put(short.class, Short.class);
pmap1.put(char.class, Character.class);
pmap1.put(int.class, Integer.class);
pmap1.put(long.class, Long.class);
pmap1.put(float.class, Float.class);
pmap1.put(double.class, Double.class);
pmap2.put(Boolean.class, boolean.class);
pmap2.put(Byte.class, byte.class);
pmap2.put(Short.class, short.class);
pmap2.put(Character.class, char.class);
pmap2.put(Integer.class, int.class);
pmap2.put(Long.class, long.class);
pmap2.put(Float.class, float.class);
pmap2.put(Double.class, double.class);
}
/**
* Returns true if the {@link #getPrimitiveWrapper(Class)} class returns a value for the specified class.
*
* @param c The class.
* @return true if the {@link #getPrimitiveWrapper(Class)} class returns a value for the specified class.
*/
public static boolean hasPrimitiveWrapper(Class> c) {
return pmap1.containsKey(c);
}
/**
* If the specified class is a primitive (e.g. int .class
) returns it's wrapper class
* (e.g. Integer.class
).
*
* @param c The class.
* @return The wrapper class, or null if class is not a primitive.
*/
public static Class> getPrimitiveWrapper(Class> c) {
return pmap1.get(c);
}
/**
* If the specified class is a primitive wrapper (e.g. Integer .class
) returns it's
* primitive class (e.g. int.class
).
*
* @param c The class.
* @return The primitive class, or null if class is not a primitive wrapper.
*/
public static Class> getPrimitiveForWrapper(Class> c) {
return pmap2.get(c);
}
/**
* If the specified class is a primitive (e.g. int .class
) returns it's wrapper class
* (e.g. Integer.class
).
*
* @param c The class.
* @return The wrapper class if it's primitive, or the same class if class is not a primitive.
*/
public static Class> getWrapperIfPrimitive(Class> c) {
if (! c.isPrimitive())
return c;
return pmap1.get(c);
}
/**
* Returns true if all specified flags are applicable to the specified class.
*
* @param x The class to test.
* @param flags The flags to test for.
* @return true if all specified flags are applicable to the specified class.
*/
public static boolean isAll(Class> x, ClassFlags...flags) {
for (ClassFlags f : flags) {
switch (f) {
case DEPRECATED:
if (isNotDeprecated(x))
return false;
break;
case NOT_DEPRECATED:
if (isDeprecated(x))
return false;
break;
case PUBLIC:
if (isNotPublic(x))
return false;
break;
case NOT_PUBLIC:
if (isPublic(x))
return false;
break;
case STATIC:
if (isNotStatic(x))
return false;
break;
case NOT_STATIC:
if (isStatic(x))
return false;
break;
case ABSTRACT:
if (isNotAbstract(x))
return false;
break;
case NOT_ABSTRACT:
if (isAbstract(x))
return false;
break;
case HAS_ARGS:
case HAS_NO_ARGS:
case TRANSIENT:
case NOT_TRANSIENT:
default:
break;
}
}
return true;
}
/**
* Returns true if all specified flags are applicable to the specified method.
*
* @param x The method to test.
* @param flags The flags to test for.
* @return true if all specified flags are applicable to the specified method.
*/
public static boolean isAll(Method x, ClassFlags...flags) {
for (ClassFlags f : flags) {
switch (f) {
case DEPRECATED:
if (isNotDeprecated(x))
return false;
break;
case NOT_DEPRECATED:
if (isDeprecated(x))
return false;
break;
case HAS_ARGS:
if (hasNoArgs(x))
return false;
break;
case HAS_NO_ARGS:
if (hasArgs(x))
return false;
break;
case PUBLIC:
if (isNotPublic(x))
return false;
break;
case NOT_PUBLIC:
if (isPublic(x))
return false;
break;
case STATIC:
if (isNotStatic(x))
return false;
break;
case NOT_STATIC:
if (isStatic(x))
return false;
break;
case ABSTRACT:
if (isNotAbstract(x))
return false;
break;
case NOT_ABSTRACT:
if (isAbstract(x))
return false;
break;
case TRANSIENT:
case NOT_TRANSIENT:
default:
break;
}
}
return true;
}
/**
* Returns true if all specified flags are applicable to the specified constructor.
*
* @param x The constructor to test.
* @param flags The flags to test for.
* @return true if all specified flags are applicable to the specified constructor.
*/
public static boolean isAll(Constructor> x, ClassFlags...flags) {
for (ClassFlags f : flags) {
switch (f) {
case DEPRECATED:
if (isNotDeprecated(x))
return false;
break;
case NOT_DEPRECATED:
if (isDeprecated(x))
return false;
break;
case HAS_ARGS:
if (hasNoArgs(x))
return false;
break;
case HAS_NO_ARGS:
if (hasArgs(x))
return false;
break;
case PUBLIC:
if (isNotPublic(x))
return false;
break;
case NOT_PUBLIC:
if (isPublic(x))
return false;
break;
case STATIC:
case NOT_STATIC:
case ABSTRACT:
case NOT_ABSTRACT:
case TRANSIENT:
case NOT_TRANSIENT:
default:
break;
}
}
return true;
}
/**
* Returns true if all specified flags are applicable to the specified field.
*
* @param x The field to test.
* @param flags The flags to test for.
* @return true if all specified flags are applicable to the specified field.
*/
public static boolean isAll(Field x, ClassFlags...flags) {
for (ClassFlags f : flags) {
switch (f) {
case DEPRECATED:
if (isNotDeprecated(x))
return false;
break;
case NOT_DEPRECATED:
if (isDeprecated(x))
return false;
break;
case HAS_ARGS:
break;
case HAS_NO_ARGS:
break;
case PUBLIC:
if (isNotPublic(x))
return false;
break;
case NOT_PUBLIC:
if (isPublic(x))
return false;
break;
case STATIC:
if (isNotStatic(x))
return false;
break;
case NOT_STATIC:
if (isStatic(x))
return false;
break;
case TRANSIENT:
if (isNotTransient(x))
return false;
break;
case NOT_TRANSIENT:
if (isTransient(x))
return false;
break;
case ABSTRACT:
case NOT_ABSTRACT:
default:
break;
}
}
return true;
}
/**
* Returns true if all specified flags are applicable to the specified class.
*
* @param x The class to test.
* @param flags The flags to test for.
* @return true if all specified flags are applicable to the specified class.
*/
public static boolean isAny(Class> x, ClassFlags...flags) {
for (ClassFlags f : flags) {
switch (f) {
case DEPRECATED:
if (isDeprecated(x))
return true;
break;
case NOT_DEPRECATED:
if (isNotDeprecated(x))
return true;
break;
case PUBLIC:
if (isPublic(x))
return true;
break;
case NOT_PUBLIC:
if (isNotPublic(x))
return true;
break;
case STATIC:
if (isStatic(x))
return true;
break;
case NOT_STATIC:
if (isNotStatic(x))
return true;
break;
case ABSTRACT:
if (isAbstract(x))
return true;
break;
case NOT_ABSTRACT:
if (isNotAbstract(x))
return true;
break;
case TRANSIENT:
case NOT_TRANSIENT:
case HAS_ARGS:
case HAS_NO_ARGS:
default:
break;
}
}
return false;
}
/**
* Returns true if all specified flags are applicable to the specified method.
*
* @param x The method to test.
* @param flags The flags to test for.
* @return true if all specified flags are applicable to the specified method.
*/
public static boolean isAny(Method x, ClassFlags...flags) {
for (ClassFlags f : flags) {
switch (f) {
case DEPRECATED:
if (isDeprecated(x))
return true;
break;
case NOT_DEPRECATED:
if (isNotDeprecated(x))
return true;
break;
case HAS_ARGS:
if (hasArgs(x))
return true;
break;
case HAS_NO_ARGS:
if (hasNoArgs(x))
return true;
break;
case PUBLIC:
if (isPublic(x))
return true;
break;
case NOT_PUBLIC:
if (isNotPublic(x))
return true;
break;
case STATIC:
if (isStatic(x))
return true;
break;
case NOT_STATIC:
if (isNotStatic(x))
return true;
break;
case ABSTRACT:
if (isAbstract(x))
return true;
break;
case NOT_ABSTRACT:
if (isNotAbstract(x))
return true;
break;
case TRANSIENT:
case NOT_TRANSIENT:
default:
break;
}
}
return false;
}
/**
* Returns true if all specified flags are applicable to the specified constructor.
*
* @param x The constructor to test.
* @param flags The flags to test for.
* @return true if all specified flags are applicable to the specified constructor.
*/
public static boolean isAny(Constructor> x, ClassFlags...flags) {
for (ClassFlags f : flags) {
switch (f) {
case DEPRECATED:
if (isDeprecated(x))
return true;
break;
case NOT_DEPRECATED:
if (isNotDeprecated(x))
return true;
break;
case HAS_ARGS:
if (hasArgs(x))
return true;
break;
case HAS_NO_ARGS:
if (hasNoArgs(x))
return true;
break;
case PUBLIC:
if (isPublic(x))
return true;
break;
case NOT_PUBLIC:
if (isNotPublic(x))
return true;
break;
case STATIC:
case NOT_STATIC:
case ABSTRACT:
case NOT_ABSTRACT:
case TRANSIENT:
case NOT_TRANSIENT:
default:
break;
}
}
return false;
}
/**
* Returns true if all specified flags are applicable to the specified field.
*
* @param x The field to test.
* @param flags The flags to test for.
* @return true if all specified flags are applicable to the specified field.
*/
public static boolean isAny(Field x, ClassFlags...flags) {
for (ClassFlags f : flags) {
switch (f) {
case DEPRECATED:
if (isDeprecated(x))
return true;
break;
case NOT_DEPRECATED:
if (isNotDeprecated(x))
return true;
break;
case PUBLIC:
if (isPublic(x))
return true;
break;
case NOT_PUBLIC:
if (isNotPublic(x))
return true;
break;
case STATIC:
if (isStatic(x))
return true;
break;
case NOT_STATIC:
if (isNotStatic(x))
return true;
break;
case TRANSIENT:
if (isTransient(x))
return true;
break;
case NOT_TRANSIENT:
if (isNotTransient(x))
return true;
break;
case HAS_ARGS:
case HAS_NO_ARGS:
case ABSTRACT:
case NOT_ABSTRACT:
default:
break;
}
}
return false;
}
/**
* Returns true if the specified method has the specified arguments.
*
* @param x The method to test.
* @param args The arguments to test for.
* @return true if the specified method has the specified arguments in the exact order.
*/
public static boolean hasArgs(Method x, Class>...args) {
Class>[] pt = x.getParameterTypes();
if (pt.length == args.length) {
for (int i = 0; i < pt.length; i++)
if (! pt[i].equals(args[i]))
return false;
return true;
}
return false;
}
/**
* Returns true if the specified constructor has the specified arguments.
*
* @param x The constructor to test.
* @param args The arguments to test for.
* @return true if the specified constructor has the specified arguments in the exact order.
*/
public static boolean hasArgs(Constructor> x, Class>...args) {
Class>[] pt = x.getParameterTypes();
if (pt.length == args.length) {
for (int i = 0; i < pt.length; i++)
if (! pt[i].equals(args[i]))
return false;
return true;
}
return false;
}
/**
* Returns true if the specified constructor has one or more arguments.
*
* @param x The method to test.
* @return true if the specified constructor has one or more arguments.
*/
public static boolean hasArgs(Constructor> x) {
return x.getParameterTypes().length > 0;
}
/**
* Returns true if the specified constructor has zero arguments.
*
* @param x The method to test.
* @return true if the specified constructor has zero arguments.
*/
public static boolean hasNoArgs(Constructor> x) {
return x.getParameterTypes().length == 0;
}
/**
* Returns true if the specified constructor has the specified number of arguments.
*
* @param x The method to test.
* @param number The number of expected arguments.
* @return true if the specified method has the specified number of arguments.
*/
public static boolean hasNumArgs(Method x, int number) {
return x.getParameterTypes().length == number;
}
/**
* Returns true if the specified constructor has the specified number of arguments.
*
* @param x The constructor to test.
* @param number The number of expected arguments.
* @return true if the specified constructor has the specified number of arguments.
*/
public static boolean hasNumArgs(Constructor> x, int number) {
return x.getParameterTypes().length == number;
}
/**
* Returns true if the specified method has at most only the specified arguments in any order.
*
* @param x The method to test.
* @param args The arguments to test for.
* @return true if the specified method has at most only the specified arguments in any order.
*/
public static boolean hasFuzzyArgs(Method x, Class>...args) {
return fuzzyArgsMatch(x.getParameterTypes(), args) != -1;
}
/**
* Returns true if the specified constructor has at most only the specified arguments in any order.
*
* @param x The constructor to test.
* @param args The arguments to test for.
* @return true if the specified constructor has at most only the specified arguments in any order.
*/
public static boolean hasFuzzyArgs(Constructor> x, Class>...args) {
return fuzzyArgsMatch(x.getParameterTypes(), args) != -1;
}
/**
* Returns true if the specified class has the {@link Deprecated @Deprecated} annotation on it.
*
* @param c The class.
* @return true if the specified class has the {@link Deprecated @Deprecated} annotation on it.
*/
public static boolean isDeprecated(Class> c) {
return c.isAnnotationPresent(Deprecated.class);
}
/**
* Returns true if the specified method has the {@link Deprecated @Deprecated} annotation on it.
*
* @param m The method.
* @return true if the specified method has the {@link Deprecated @Deprecated} annotation on it.
*/
public static boolean isDeprecated(Method m) {
return m.isAnnotationPresent(Deprecated.class);
}
/**
* Returns true if the specified constructor has the {@link Deprecated @Deprecated} annotation on it.
*
* @param c The constructor.
* @return true if the specified constructor has the {@link Deprecated @Deprecated} annotation on it.
*/
public static boolean isDeprecated(Constructor> c) {
return c.isAnnotationPresent(Deprecated.class);
}
/**
* Returns true if the specified field has the {@link Deprecated @Deprecated} annotation on it.
*
* @param f The field.
* @return true if the specified field has the {@link Deprecated @Deprecated} annotation on it.
*/
public static boolean isDeprecated(Field f) {
return f.isAnnotationPresent(Deprecated.class);
}
/**
* Returns true if the specified class doesn't have the {@link Deprecated @Deprecated} annotation on it.
*
* @param c The class.
* @return true if the specified class doesn't have the {@link Deprecated @Deprecated} annotation on it.
*/
public static boolean isNotDeprecated(Class> c) {
return ! c.isAnnotationPresent(Deprecated.class);
}
/**
* Returns true if the specified method doesn't have the {@link Deprecated @Deprecated} annotation on it.
*
* @param m The method.
* @return true if the specified method doesn't have the {@link Deprecated @Deprecated} annotation on it.
*/
public static boolean isNotDeprecated(Method m) {
return ! m.isAnnotationPresent(Deprecated.class);
}
/**
* Returns true if the specified constructor doesn't have the {@link Deprecated @Deprecated} annotation on it.
*
* @param c The constructor.
* @return true if the specified constructor doesn't have the {@link Deprecated @Deprecated} annotation on it.
*/
public static boolean isNotDeprecated(Constructor> c) {
return ! c.isAnnotationPresent(Deprecated.class);
}
/**
* Returns true if the specified field doesn't have the {@link Deprecated @Deprecated} annotation on it.
*
* @param f The field.
* @return true if the specified field doesn't have the {@link Deprecated @Deprecated} annotation on it.
*/
public static boolean isNotDeprecated(Field f) {
return ! f.isAnnotationPresent(Deprecated.class);
}
/**
* Returns true if the specified class is public.
*
* @param c The class.
* @return true if the specified class is public.
*/
public static boolean isPublic(Class> c) {
return Modifier.isPublic(c.getModifiers());
}
/**
* Returns true if the specified class is not public.
*
* @param c The class.
* @return true if the specified class is not public.
*/
public static boolean isNotPublic(Class> c) {
return ! Modifier.isPublic(c.getModifiers());
}
/**
* Returns true if the specified class is public.
*
* @param c The class.
* @return true if the specified class is public.
*/
public static boolean isStatic(Class> c) {
return Modifier.isStatic(c.getModifiers());
}
/**
* Returns true if the specified class is not static.
*
* @param c The class.
* @return true if the specified class is not static.
*/
public static boolean isNotStatic(Class> c) {
return ! Modifier.isStatic(c.getModifiers());
}
/**
* Returns true if the specified class is abstract.
*
* @param c The class.
* @return true if the specified class is abstract.
*/
public static boolean isAbstract(Class> c) {
return Modifier.isAbstract(c.getModifiers());
}
/**
* Returns true if the specified class is not abstract.
*
* @param c The class.
* @return true if the specified class is not abstract.
*/
public static boolean isNotAbstract(Class> c) {
return ! Modifier.isAbstract(c.getModifiers());
}
/**
* Returns true if the specified method is abstract.
*
* @param m The method.
* @return true if the specified method is abstract.
*/
public static boolean isAbstract(Method m) {
return Modifier.isAbstract(m.getModifiers());
}
/**
* Returns true if the specified method is not abstract.
*
* @param m The method.
* @return true if the specified method is not abstract.
*/
public static boolean isNotAbstract(Method m) {
return ! Modifier.isAbstract(m.getModifiers());
}
/**
* Returns true if the specified method is public.
*
* @param m The method.
* @return true if the specified method is public.
*/
public static boolean isPublic(Method m) {
return Modifier.isPublic(m.getModifiers());
}
/**
* Returns true if the specified method is not public.
*
* @param m The method.
* @return true if the specified method is not public.
*/
public static boolean isNotPublic(Method m) {
return ! Modifier.isPublic(m.getModifiers());
}
/**
* Returns true if the specified field is public.
*
* @param f The field.
* @return true if the specified field is public.
*/
public static boolean isPublic(Field f) {
return Modifier.isPublic(f.getModifiers());
}
/**
* Returns true if the specified field is not public.
*
* @param f The field.
* @return true if the specified field is not public.
*/
public static boolean isNotPublic(Field f) {
return ! Modifier.isPublic(f.getModifiers());
}
/**
* Returns true if the specified method is static.
*
* @param m The method.
* @return true if the specified method is static.
*/
public static boolean isStatic(Method m) {
return Modifier.isStatic(m.getModifiers());
}
/**
* Returns true if the specified method is not static.
*
* @param m The method.
* @return true if the specified method is not static.
*/
public static boolean isNotStatic(Method m) {
return ! Modifier.isStatic(m.getModifiers());
}
/**
* Returns true if the specified field is static.
*
* @param f The field.
* @return true if the specified field is static.
*/
public static boolean isStatic(Field f) {
return Modifier.isStatic(f.getModifiers());
}
/**
* Returns true if the specified field is not static.
*
* @param f The field.
* @return true if the specified field is not static.
*/
public static boolean isNotStatic(Field f) {
return ! Modifier.isStatic(f.getModifiers());
}
/**
* Returns true if the specified constructor is public.
*
* @param c The constructor.
* @return true if the specified constructor is public.
*/
public static boolean isPublic(Constructor> c) {
return Modifier.isPublic(c.getModifiers());
}
/**
* Returns true if the specified constructor is not public.
*
* @param c The constructor.
* @return true if the specified constructor is not public.
*/
public static boolean isNotPublic(Constructor> c) {
return ! Modifier.isPublic(c.getModifiers());
}
/**
* Returns true if the specified field is transient.
*
* @param f The field.
* @return true if the specified field is transient.
*/
public static boolean isTransient(Field f) {
return Modifier.isTransient(f.getModifiers());
}
/**
* Returns true if the specified field is not transient.
*
* @param f The field.
* @return true if the specified field is not transient.
*/
public static boolean isNotTransient(Field f) {
return ! Modifier.isTransient(f.getModifiers());
}
/**
* Returns true if the specified method has one or more arguments.
*
* @param x The method to test.
* @return true if the specified method has one or more arguments.
*/
public static boolean hasArgs(Method x) {
return x.getParameterTypes().length > 0;
}
/**
* Returns true if the specified method has zero arguments.
*
* @param x The method to test.
* @return true if the specified method has zero arguments.
*/
public static boolean hasNoArgs(Method x) {
return x.getParameterTypes().length == 0;
}
/**
* Returns true if the specified method has the specified name.
*
* @param m The method to test.
* @param name The name to test for.
* @return true if the specified method has the specified name.
*/
public static boolean hasName(Method m, String name) {
return m.getName().equals(name);
}
/**
* Returns true if the specified method has the specified return type.
*
* @param m The method to test.
* @param c The return type to test for.
* @return true if the specified method has the specified return type.
*/
public static boolean hasReturnType(Method m, Class> c) {
return m.getReturnType() == c;
}
/**
* Returns true if the specified method has the specified parent return type.
*
* @param m The method to test.
* @param c The return type to test for.
* @return true if the specified method has the specified parent return type.
*/
public static boolean hasReturnTypeParent(Method m, Class> c) {
return isParentClass(c, m.getReturnType());
}
/**
* Returns the specified annotation on the specified method.
*
*
* Similar to {@link Method#getAnnotation(Class)}, but searches up the parent hierarchy for the annotation
* defined on parent classes and interfaces.
*
*
* Normally, annotations defined on methods of parent classes and interfaces are not inherited by the child methods.
* This utility method gets around that limitation by searching the class hierarchy for the "same" method
* (i.e. the same name and arguments).
*
* @param a The annotation to search for.
* @param m The method to search.
* @return The annotation, or null if it wasn't found.
*/
public static T getMethodAnnotation(Class a, Method m) {
return getMethodAnnotation(a, m.getDeclaringClass(), m);
}
/**
* Returns the specified annotation on the specified method.
*
*
* Similar to {@link Method#getAnnotation(Class)}, but searches up the parent hierarchy for the annotation defined
* on parent classes and interfaces.
*
*
* Normally, annotations defined on methods of parent classes and interfaces are not inherited by the child methods.
* This utility method gets around that limitation by searching the class hierarchy for the "same" method
* (i.e. the same name and arguments).
*
* @param a The annotation to search for.
* @param c
* The child class to start searching from.
* Note that it can be a descendant class of the actual declaring class of the method passed in.
* This allows you to find annotations on methods overridden by the method passed in.
* @param method The method to search.
* @return The annotation, or null if it wasn't found.
*/
public static T getMethodAnnotation(Class a, Class> c, Method method) {
for (Method m : c.getDeclaredMethods()) {
if (isSameMethod(method, m)) {
T t = m.getAnnotation(a);
if (t != null)
return t;
}
}
Class> pc = c.getSuperclass();
if (pc != null) {
T t = getMethodAnnotation(a, pc, method);
if (t != null)
return t;
}
for (Class> ic : c.getInterfaces()) {
T t = getMethodAnnotation(a, ic, method);
if (t != null)
return t;
}
return null;
}
/**
* Given a specific method, finds all declared methods with the same name and arguments on all
* superclasses and interfaces.
*
* @param m The method to find matches against.
* @return All matching methods including the input method itself.
*/
public static List findMatchingMethods(Method m) {
return findMatchingMethods(new ArrayList(), m);
}
private static List findMatchingMethods(List l, Method m) {
l.add(m);
Class> c = m.getDeclaringClass();
Class> pc = c.getSuperclass();
if (pc != null)
for (Method m2 : pc.getDeclaredMethods())
if (isSameMethod(m, m2))
findMatchingMethods(l, m2);
for (Class> ic : c.getInterfaces())
for (Method m2 : ic.getDeclaredMethods())
if (isSameMethod(m, m2))
findMatchingMethods(l, m2);
return l;
}
private static boolean isSameMethod(Method m1, Method m2) {
return m1.getName().equals(m2.getName()) && Arrays.equals(m1.getParameterTypes(), m2.getParameterTypes());
}
/**
* Locates the no-arg constructor for the specified class.
*
*
* Constructor must match the visibility requirements specified by parameter 'v'.
* If class is abstract, always returns null .
* Note that this also returns the 1-arg constructor for non-static member classes.
*
* @param c The class from which to locate the no-arg constructor.
* @param v The minimum visibility.
* @return The constructor, or null if no no-arg constructor exists with the required visibility.
*/
@SuppressWarnings({"rawtypes","unchecked"})
public static final Constructor findNoArgConstructor(Class c, Visibility v) {
int mod = c.getModifiers();
if (Modifier.isAbstract(mod))
return null;
boolean isMemberClass = c.isMemberClass() && ! isStatic(c);
for (Constructor cc : c.getConstructors()) {
mod = cc.getModifiers();
if (hasNumArgs(cc, isMemberClass ? 1 : 0) && v.isVisible(mod) && isNotDeprecated(cc))
return v.transform(cc);
}
return null;
}
/**
* Finds the real parameter type of the specified class.
*
* @param c The class containing the parameters (e.g. PojoSwap<T,S>)
* @param index The zero-based index of the parameter to resolve.
* @param oc The class we're trying to resolve the parameter type for.
* @return The resolved real class.
*/
public static Class> resolveParameterType(Class> c, int index, Class> oc) {
// We need to make up a mapping of type names.
Map typeMap = new HashMap<>();
while (c != oc.getSuperclass()) {
extractTypes(typeMap, oc);
oc = oc.getSuperclass();
}
Type gsc = oc.getGenericSuperclass();
// Not actually a parameterized type.
if (! (gsc instanceof ParameterizedType))
return Object.class;
ParameterizedType opt = (ParameterizedType)gsc;
Type actualType = opt.getActualTypeArguments()[index];
if (typeMap.containsKey(actualType))
actualType = typeMap.get(actualType);
if (actualType instanceof Class) {
return (Class>)actualType;
} else if (actualType instanceof GenericArrayType) {
Class> cmpntType = (Class>)((GenericArrayType)actualType).getGenericComponentType();
return Array.newInstance(cmpntType, 0).getClass();
} else if (actualType instanceof TypeVariable) {
TypeVariable> typeVariable = (TypeVariable>)actualType;
List> nestedOuterTypes = new LinkedList<>();
for (Class> ec = oc.getEnclosingClass(); ec != null; ec = ec.getEnclosingClass()) {
try {
Class> outerClass = oc.getClass();
nestedOuterTypes.add(outerClass);
Map outerTypeMap = new HashMap<>();
extractTypes(outerTypeMap, outerClass);
for (Map.Entry entry : outerTypeMap.entrySet()) {
Type key = entry.getKey(), value = entry.getValue();
if (key instanceof TypeVariable) {
TypeVariable> keyType = (TypeVariable>)key;
if (keyType.getName().equals(typeVariable.getName()) && isInnerClass(keyType.getGenericDeclaration(), typeVariable.getGenericDeclaration())) {
if (value instanceof Class)
return (Class>)value;
typeVariable = (TypeVariable>)entry.getValue();
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
throw new FormattedRuntimeException("Could not resolve type: {0}", actualType);
} else {
throw new FormattedRuntimeException("Invalid type found in resolveParameterType: {0}", actualType);
}
}
/**
* Invokes the specified method using fuzzy-arg matching.
*
*
* Arguments will be matched to the parameters based on the parameter types.
*
Arguments can be in any order.
*
Extra arguments will be ignored.
*
Missing arguments will be left null .
*
*
* Note that this only works for methods that have distinguishable argument types.
*
It's not going to work on methods with generic argument types like Object
*
* @param m The method being called.
* @param pojo
* The POJO the method is being called on.
*
Can be null for static methods.
* @param args
* The arguments to pass to the method.
* @return
* The results of the method invocation.
* @throws Exception
*/
public static Object invokeMethodFuzzy(Method m, Object pojo, Object...args) throws Exception {
return m.invoke(pojo, getMatchingArgs(m.getParameterTypes(), args));
}
/**
* Invokes the specified constructor using fuzzy-arg matching.
*
*
* Arguments will be matched to the parameters based on the parameter types.
*
Arguments can be in any order.
*
Extra arguments will be ignored.
*
Missing arguments will be left null .
*
*
* Note that this only works for constructors that have distinguishable argument types.
*
It's not going to work on constructors with generic argument types like Object
*
* @param c The constructor being called.
* @param args
* The arguments to pass to the constructor.
* @return
* The results of the method invocation.
* @throws Exception
*/
public static T invokeConstructorFuzzy(Constructor c, Object...args) throws Exception {
return c.newInstance(getMatchingArgs(c.getParameterTypes(), args));
}
private static boolean isInnerClass(GenericDeclaration od, GenericDeclaration id) {
if (od instanceof Class && id instanceof Class) {
Class> oc = (Class>)od;
Class> ic = (Class>)id;
while ((ic = ic.getEnclosingClass()) != null)
if (ic == oc)
return true;
}
return false;
}
private static void extractTypes(Map typeMap, Class> c) {
Type gs = c.getGenericSuperclass();
if (gs instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)gs;
Type[] typeParameters = ((Class>)pt.getRawType()).getTypeParameters();
Type[] actualTypeArguments = pt.getActualTypeArguments();
for (int i = 0; i < typeParameters.length; i++) {
if (typeMap.containsKey(actualTypeArguments[i]))
actualTypeArguments[i] = typeMap.get(actualTypeArguments[i]);
typeMap.put(typeParameters[i], actualTypeArguments[i]);
}
}
}
/**
* Finds a public method with the specified parameters.
*
* @param c The class to look for the method.
* @param name The method name.
* @param returnType
* The return type of the method.
* Can be a super type of the actual return type.
* For example, if the actual return type is CharSequence
, then Object
will match but
* String
will not.
* @param argTypes
* The argument types of the method.
* Can be subtypes of the actual parameter types.
* For example, if the parameter type is CharSequence
, then String
will match but
* Object
will not.
* @return The matched method, or null if no match was found.
*/
public static Method findPublicMethod(Class> c, String name, Class> returnType, Class>...argTypes) {
for (Method m : c.getMethods()) {
if (isPublic(m) && hasName(m, name) && hasReturnTypeParent(m, returnType) && argsMatch(m.getParameterTypes(), argTypes))
return m;
}
return null;
}
/**
* Finds a public constructor with the specified parameters without throwing an exception.
*
* @param c The class to search for a constructor.
* @param fuzzyArgs
* Use fuzzy-arg matching.
* Find a constructor that best matches the specified args.
* @param argTypes
* The argument types in the constructor.
* Can be subtypes of the actual constructor argument types.
* @return The matching constructor, or null if constructor could not be found.
*/
public static Constructor findPublicConstructor(Class c, boolean fuzzyArgs, Class>...argTypes) {
return findConstructor(c, Visibility.PUBLIC, fuzzyArgs, argTypes);
}
/**
* Finds a constructor with the specified parameters without throwing an exception.
*
* @param c The class to search for a constructor.
* @param vis The minimum visibility.
* @param fuzzyArgs
* Use fuzzy-arg matching.
* Find a constructor that best matches the specified args.
* @param argTypes
* The argument types in the constructor.
* Can be subtypes of the actual constructor argument types.
* @return The matching constructor, or null if constructor could not be found.
*/
@SuppressWarnings("unchecked")
public static Constructor findConstructor(Class c, Visibility vis, boolean fuzzyArgs, Class>...argTypes) {
ConstructorCacheEntry cce = CONSTRUCTOR_CACHE.get(c);
if (cce != null && argsMatch(cce.paramTypes, argTypes) && cce.isVisible(vis))
return (Constructor)cce.constructor;
if (fuzzyArgs) {
int bestCount = -1;
Constructor> bestMatch = null;
for (Constructor> n : c.getDeclaredConstructors()) {
if (vis.isVisible(n)) {
int m = fuzzyArgsMatch(n.getParameterTypes(), argTypes);
if (m > bestCount) {
bestCount = m;
bestMatch = n;
}
}
}
if (bestCount >= 0)
CONSTRUCTOR_CACHE.put(c, new ConstructorCacheEntry(c, bestMatch));
return (Constructor)bestMatch;
}
final boolean isMemberClass = c.isMemberClass() && ! isStatic(c);
for (Constructor> n : c.getConstructors()) {
Class>[] paramTypes = n.getParameterTypes();
if (isMemberClass)
paramTypes = Arrays.copyOfRange(paramTypes, 1, paramTypes.length);
if (argsMatch(paramTypes, argTypes) && vis.isVisible(n)) {
CONSTRUCTOR_CACHE.put(c, new ConstructorCacheEntry(c, n));
return (Constructor)n;
}
}
return null;
}
private static final class ConstructorCacheEntry {
final Constructor> constructor;
final Class>[] paramTypes;
ConstructorCacheEntry(Class> forClass, Constructor> constructor) {
this.constructor = constructor;
this.paramTypes = constructor.getParameterTypes();
}
boolean isVisible(Visibility vis) {
return vis.isVisible(constructor);
}
}
/**
* Returns true if the specified argument types are valid for the specified parameter types.
*
* @param paramTypes The parameters types specified on a method.
* @param argTypes The class types of the arguments being passed to the method.
* @return true if the arguments match the parameters.
*/
public static boolean argsMatch(Class>[] paramTypes, Class>[] argTypes) {
if (paramTypes.length == argTypes.length) {
for (int i = 0; i < paramTypes.length; i++)
if (! isParentClass(paramTypes[i], argTypes[i]))
return false;
return true;
}
return false;
}
/**
* Returns a number representing the number of arguments that match the specified parameters.
*
* @param paramTypes The parameters types specified on a method.
* @param argTypes The class types of the arguments being passed to the method.
* @return The number of matching arguments, or -1
a parameter was found that isn't in the list of args.
*/
public static int fuzzyArgsMatch(Class>[] paramTypes, Class>... argTypes) {
int matches = 0;
outer: for (Class> p : paramTypes) {
p = getWrapperIfPrimitive(p);
for (Class> a : argTypes) {
if (isParentClass(p, a)) {
matches++;
continue outer;
}
}
return -1;
}
return matches;
}
/**
* Finds the public constructor that can take in the specified arguments.
*
* @param c The class we're trying to construct.
* @param args The arguments we want to pass into the constructor.
* @return
* The constructor, or null if a public constructor could not be found that takes in the specified
* arguments.
*/
public static Constructor findPublicConstructor(Class c, Object...args) {
return findPublicConstructor(c, false, getClasses(args));
}
/**
* Finds the public constructor that can take in the specified arguments.
*
* @param c The class we're trying to construct.
* @param args The argument types we want to pass into the constructor.
* @return
* The constructor, or null if a public constructor could not be found that takes in the specified
* arguments.
*/
public static Constructor findPublicConstructor(Class c, Class>...args) {
return findPublicConstructor(c, false, args);
}
/**
* Finds the public constructor that can take in the specified arguments.
*
* @param c The class we're trying to construct.
* @param fuzzyArgs
* Use fuzzy-arg matching.
* Find a constructor that best matches the specified args.
* @param args The arguments we want to pass into the constructor.
* @return
* The constructor, or null if a public constructor could not be found that takes in the specified
* arguments.
*/
public static Constructor findPublicConstructor(Class c, boolean fuzzyArgs, Object...args) {
return findPublicConstructor(c, fuzzyArgs, getClasses(args));
}
/**
* Returns the class types for the specified arguments.
*
* @param args The objects we're getting the classes of.
* @return The classes of the arguments.
*/
public static Class>[] getClasses(Object...args) {
Class>[] pt = new Class>[args.length];
for (int i = 0; i < args.length; i++)
pt[i] = args[i] == null ? null : args[i].getClass();
return pt;
}
/**
* Returns a {@link MethodInfo} bean that describes the specified method.
*
* @param m The method to describe.
* @return The bean with information about the method.
*/
public static MethodInfo getMethodInfo(Method m) {
return new MethodInfo(m);
}
/**
* Returns {@link MethodInfo} beans that describe the specified methods.
*
* @param m The methods to describe.
* @return The beans with information about the methods.
*/
public static MethodInfo[] getMethodInfo(Collection m) {
MethodInfo[] mi = new MethodInfo[m.size()];
int i = 0;
for (Method mm : m)
mi[i++] = getMethodInfo(mm);
return mi;
}
/**
* Simple bean that shows the name, parameter types, and return type of a method.
*/
@SuppressWarnings("javadoc")
public static class MethodInfo {
public final String methodName;
public final String[] parameterTypes;
public final String returnType;
MethodInfo(Method m) {
methodName = m.getName();
Type[] pt = m.getGenericParameterTypes();
parameterTypes = new String[pt.length];
for (int i = 0; i < pt.length; i++)
parameterTypes[i] = BeanContext.DEFAULT.getClassMeta(pt[i]).toString();
returnType = BeanContext.DEFAULT.getClassMeta(m.getGenericReturnType()).toString();
}
}
/**
* Creates an instance of the specified class.
*
* @param c
* The class to cast to.
* @param c2
* The class to instantiate.
* Can also be an instance of the class.
* @return
* The new class instance, or null if the class was null or is abstract or an interface.
* @throws
* RuntimeException if constructor could not be found or called.
*/
public static T newInstance(Class c, Object c2) {
return newInstanceFromOuter(null, c, c2, false);
}
/**
* Creates an instance of the specified class.
*
* @param c
* The class to cast to.
* @param c2
* The class to instantiate.
* Can also be an instance of the class.
* @param fuzzyArgs
* Use fuzzy constructor arg matching.
*
When true , constructor args can be in any order and extra args are ignored.
*
No-arg constructors are also used if no other constructors are found.
* @param args
* The arguments to pass to the constructor.
* @return
* The new class instance, or null if the class was null or is abstract or an interface.
* @throws
* RuntimeException if constructor could not be found or called.
*/
public static T newInstance(Class c, Object c2, boolean fuzzyArgs, Object...args) {
return newInstanceFromOuter(null, c, c2, fuzzyArgs, args);
}
/**
* Creates an instance of the specified class from within the context of another object.
*
* @param outer
* The outer object.
* Can be null .
* @param c
* The class to cast to.
* @param c2
* The class to instantiate.
* Can also be an instance of the class.
* @param fuzzyArgs
* Use fuzzy constructor arg matching.
*
When true , constructor args can be in any order and extra args are ignored.
*
No-arg constructors are also used if no other constructors are found.
* @param args
* The arguments to pass to the constructor.
* @return
* The new class instance, or null if the class was null or is abstract or an interface.
* @throws
* RuntimeException if constructor could not be found or called.
*/
@SuppressWarnings("unchecked")
public static T newInstanceFromOuter(Object outer, Class c, Object c2, boolean fuzzyArgs, Object...args) {
if (c2 == null)
return null;
if (c2 instanceof Class) {
try {
Class> c3 = (Class>)c2;
if (c3.isInterface() || isAbstract(c3))
return null;
// First look for an exact match.
Constructor> con = findPublicConstructor(c3, false, args);
if (con != null)
return (T)con.newInstance(args);
// Next look for an exact match including the outer.
if (outer != null) {
args = new AList<>().append(outer).appendAll(args).toArray();
con = findPublicConstructor(c3, false, args);
if (con != null)
return (T)con.newInstance(args);
}
// Finally use fuzzy matching.
if (fuzzyArgs) {
con = findPublicConstructor(c3, true, args);
if (con != null)
return (T)con.newInstance(getMatchingArgs(con.getParameterTypes(), args));
}
throw new FormattedRuntimeException("Could not instantiate class {0}/{1}. Constructor not found.", c.getName(), c2);
} catch (Exception e) {
throw new FormattedRuntimeException(e, "Could not instantiate class {0}", c.getName());
}
} else if (isParentClass(c, c2.getClass())) {
return (T)c2;
} else {
throw new FormattedRuntimeException("Object of type {0} found but was expecting {1}.", c2.getClass(), c.getClass());
}
}
/**
* Matches arguments to a list of parameter types.
*
*
* Extra parameters are ignored.
*
Missing parameters are left null.
*
* @param paramTypes The parameter types.
* @param args The arguments to match to the parameter types.
* @return
* An array of parameters.
*/
public static Object[] getMatchingArgs(Class>[] paramTypes, Object... args) {
Object[] params = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
Class> pt = getWrapperIfPrimitive(paramTypes[i]);
for (int j = 0; j < args.length; j++) {
if (isParentClass(pt, args[j].getClass())) {
params[i] = args[j];
break;
}
}
}
return params;
}
/**
* Returns all the fields in the specified class and all parent classes.
*
*
* Fields are ordered in either parent-to-child, or child-to-parent order, then alphabetically.
*
* @param c The class to get all fields on.
* @param parentFirst Order them in parent-class-to-child-class order, otherwise child-class-to-parent-class order.
* @return An iterable of all fields in the specified class.
*/
@SuppressWarnings("rawtypes")
public static Iterable getAllFields(final Class c, final boolean parentFirst) {
return new Iterable() {
@Override
public Iterator iterator() {
return new Iterator(){
final Iterator> classIterator = getParentClasses(c, parentFirst, false);
Field[] fields = classIterator.hasNext() ? sort(classIterator.next().getDeclaredFields()) : new Field[0];
int fIndex = 0;
Field next;
@Override
public boolean hasNext() {
prime();
return next != null;
}
private void prime() {
if (next == null) {
while (fIndex >= fields.length) {
if (classIterator.hasNext()) {
fields = sort(classIterator.next().getDeclaredFields());
fIndex = 0;
} else {
fIndex = -1;
}
}
if (fIndex != -1)
next = fields[fIndex++];
}
}
@Override
public Field next() {
prime();
Field f = next;
next = null;
return f;
}
@Override
public void remove() {
}
};
}
};
}
/**
* Returns all the methods in the specified class and all parent classes.
*
*
* Methods are ordered in either parent-to-child, or child-to-parent order, then alphabetically.
*
* @param c The class to get all methods on.
* @param parentFirst Order them in parent-class-to-child-class order, otherwise child-class-to-parent-class order.
* @return An iterable of all methods in the specified class.
*/
@SuppressWarnings("rawtypes")
public static Iterable getAllMethods(final Class c, final boolean parentFirst) {
return new Iterable() {
@Override
public Iterator iterator() {
return new Iterator(){
final Iterator> classIterator = getParentClasses(c, parentFirst, true);
Method[] methods = classIterator.hasNext() ? sort(classIterator.next().getDeclaredMethods()) : new Method[0];
int mIndex = 0;
Method next;
@Override
public boolean hasNext() {
prime();
return next != null;
}
private void prime() {
if (next == null) {
while (mIndex >= methods.length) {
if (classIterator.hasNext()) {
methods = sort(classIterator.next().getDeclaredMethods());
mIndex = 0;
} else {
mIndex = -1;
}
}
if (mIndex != -1)
next = methods[mIndex++];
}
}
@Override
public Method next() {
prime();
Method m = next;
next = null;
return m;
}
@Override
public void remove() {
}
};
}
};
}
private static Comparator METHOD_COMPARATOR = new Comparator() {
@Override
public int compare(Method o1, Method o2) {
int i = o1.getName().compareTo(o2.getName());
if (i == 0) {
i = o1.getParameterTypes().length - o2.getParameterTypes().length;
if (i == 0) {
for (int j = 0; j < o1.getParameterTypes().length && i == 0; j++) {
i = o1.getParameterTypes()[j].getName().compareTo(o2.getParameterTypes()[j].getName());
}
}
}
return i;
}
};
/**
* Sorts methods in alphabetical order.
*
* @param m The methods to sort.
* @return The same array, but with elements sorted.
*/
public static Method[] sort(Method[] m) {
Arrays.sort(m, METHOD_COMPARATOR);
return m;
}
private static Comparator FIELD_COMPARATOR = new Comparator() {
@Override
public int compare(Field o1, Field o2) {
return o1.getName().compareTo(o2.getName());
}
};
/**
* Sorts methods in alphabetical order.
*
* @param m The methods to sort.
* @return The same array, but with elements sorted.
*/
public static Field[] sort(Field[] m) {
Arrays.sort(m, FIELD_COMPARATOR);
return m;
}
/**
* Returns a list of all the parent classes of the specified class including the class itself.
*
* @param c The class to retrieve the parent classes.
* @param parentFirst In parent-to-child order, otherwise child-to-parent.
* @param includeInterfaces Include interfaces.
* @return An iterator of parent classes in the class hierarchy.
*/
public static Iterator> getParentClasses(final Class> c, boolean parentFirst, boolean includeInterfaces) {
List> l = getParentClasses(new ArrayList>(), c, parentFirst, includeInterfaces);
return l.iterator();
}
private static List> getParentClasses(List> l, Class> c, boolean parentFirst, boolean includeInterfaces) {
if (parentFirst) {
if (includeInterfaces)
for (Class> i : c.getInterfaces())
l.add(i);
if (c.getSuperclass() != Object.class && c.getSuperclass() != null)
getParentClasses(l, c.getSuperclass(), parentFirst, includeInterfaces);
l.add(c);
} else {
l.add(c);
if (c.getSuperclass() != Object.class && c.getSuperclass() != null)
getParentClasses(l, c.getSuperclass(), parentFirst, includeInterfaces);
if (includeInterfaces)
for (Class> i : c.getInterfaces())
l.add(i);
}
return l;
}
/**
* Returns the default value for the specified primitive class.
*
* @param primitiveClass The primitive class to get the default value for.
* @return The default value, or null if the specified class is not a primitive class.
*/
public static Object getPrimitiveDefault(Class> primitiveClass) {
return primitiveDefaultMap.get(primitiveClass);
}
private static final Map,Object> primitiveDefaultMap = Collections.unmodifiableMap(
new AMap,Object>()
.append(Boolean.TYPE, false)
.append(Character.TYPE, (char)0)
.append(Short.TYPE, (short)0)
.append(Integer.TYPE, 0)
.append(Long.TYPE, 0l)
.append(Float.TYPE, 0f)
.append(Double.TYPE, 0d)
.append(Byte.TYPE, (byte)0)
.append(Boolean.class, false)
.append(Character.class, (char)0)
.append(Short.class, (short)0)
.append(Integer.class, 0)
.append(Long.class, 0l)
.append(Float.class, 0f)
.append(Double.class, 0d)
.append(Byte.class, (byte)0)
);
/**
* Returns a readable representation of the specified method.
*
*
* The format of the string is "full-qualified-class.method-name(parameter-simple-class-names)" .
*
* @param m The method to stringify.
* @return The stringified method.
*/
public static String toString(Method m) {
StringBuilder sb = new StringBuilder(m.getDeclaringClass().getName() + "." + m.getName() + "(");
for (int i = 0; i < m.getParameterTypes().length; i++) {
if (i > 0)
sb.append(",");
sb.append(m.getParameterTypes()[i].getSimpleName());
}
sb.append(")");
return sb.toString();
}
/**
* Returns a readable representation of the specified field.
*
*
* The format of the string is "full-qualified-class.field-name" .
*
* @param f The field to stringify.
* @return The stringified field.
*/
public static String toString(Field f) {
return f.getDeclaringClass().getName() + "." + f.getName();
}
/**
* Throws an {@link IllegalArgumentException} if the parameters on the method are not in the specified list provided.
*
* @param m The method to test.
* @param args The valid class types (exact) for the arguments.
* @throws FormattedIllegalArgumentException If any of the parameters on the method weren't in the list.
*/
public static void assertArgsOfType(Method m, Class>...args) throws FormattedIllegalArgumentException {
for (Class> c1 : m.getParameterTypes()) {
boolean foundMatch = false;
for (Class> c2 : args)
if (c1 == c2)
foundMatch = true;
if (! foundMatch)
throw new FormattedIllegalArgumentException("Invalid argument of type {0} passed in method {1}. Only arguments of type {2} are allowed.", c1, m, args);
}
}
/**
* Finds the public static "fromString" method on the specified class.
*
*
* Looks for the following method names:
*
* fromString
* fromValue
* valueOf
* parse
* parseString
* forName
* forString
*
*
* @param c The class to find the method on.
* @return The static method, or null if it couldn't be found.
*/
public static Method findPublicFromStringMethod(Class> c) {
for (String methodName : new String[]{"create","fromString","fromValue","valueOf","parse","parseString","forName","forString"})
for (Method m : c.getMethods())
if (isAll(m, STATIC, PUBLIC, NOT_DEPRECATED) && hasName(m, methodName) && hasReturnType(m, c) && hasArgs(m, String.class))
return m;
return null;
}
/**
* Find the public static creator method on the specified class.
*
* @param oc The created type.
* @param ic The argument type.
* @param name The method name.
* @return The static method, or null if it couldn't be found.
*/
public static Method findPublicStaticCreateMethod(Class> oc, Class> ic, String name) {
for (Method m : oc.getMethods())
if (isAll(m, STATIC, PUBLIC, NOT_DEPRECATED) && hasName(m, name) && hasReturnType(m, oc) && hasArgs(m, ic))
return m;
return null;
}
/**
* Constructs a new instance of the specified class from the specified string.
*
*
* Class must be one of the following:
*
* - Have a public constructor that takes in a single
String
argument.
* - Have a static
fromString(String)
(or related) method.
*
See {@link #findPublicFromStringMethod(Class)} for the list of possible static method names.
* - Be an
enum
.
*
*
* @param c The class.
* @param s The string to create the instance from.
* @return A new object instance, or null if a method for converting the string to an object could not be found.
*/
public static T fromString(Class c, String s) {
Transform t = TransformCache.get(String.class, c);
return t == null ? null : t.transform(s);
}
/**
* Converts an object to a string.
*
*
* Normally, this is just going to call toString()
on the object.
* However, the {@link Locale} and {@link TimeZone} objects are treated special so that the returned value
* works with the {@link #fromString(Class, String)} method.
*
* @param o The object to convert to a string.
* @return The stringified object, or null if the object was null .
*/
@SuppressWarnings({ "unchecked" })
public static String toString(Object o) {
if (o == null)
return null;
Transform