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

org.drools.wiring.api.util.ClassUtils Maven / Gradle / Ivy

Go to download

This module defines an API for wiring classloaders and other services used in Drools.

There is a newer version: 9.44.0.Final
Show newest version
/*
 * Copyright 2010 Red Hat, Inc. and/or its affiliates.
 *
 * 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 org.drools.wiring.api.util;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.kie.api.definition.type.Modifies;
import org.kie.internal.utils.ClassLoaderUtil;

public abstract class ClassUtils {
    private static final ProtectionDomain  PROTECTION_DOMAIN;

    public static final boolean IS_ANDROID;

    private static final Map> classes = Collections.synchronizedMap( new HashMap() );

    private static final Map> constructors = Collections.synchronizedMap( new HashMap() );

    private static final String STAR    = "*";

    private static final Map abbreviationMap;

    private static final Map> primitiveNameToType;

    protected ClassUtils() { }

    static {
        final Map m = new HashMap<>();
        m.put("int", "I");
        m.put("boolean", "Z");
        m.put("float", "F");
        m.put("long", "J");
        m.put("short", "S");
        m.put("byte", "B");
        m.put("double", "D");
        m.put("char", "C");
        m.put("void", "V");
        abbreviationMap = Collections.unmodifiableMap(m);

        final Map> m2 = new HashMap<>();
        m2.put("int", int.class);
        m2.put("boolean", boolean.class);
        m2.put("float", float.class);
        m2.put("long", long.class);
        m2.put("short", short.class);
        m2.put("byte", byte.class);
        m2.put("double", double.class);
        m2.put("char", char.class);
        primitiveNameToType = Collections.unmodifiableMap(m2);
    }

    static {
        PROTECTION_DOMAIN = (ProtectionDomain) AccessController.doPrivileged((PrivilegedAction) ClassLoaderUtil.class::getProtectionDomain);

        // determine if we are running on Android
        boolean isAndroid;
        try {
            isAndroid = loadClass("org.drools.android.DroolsAndroidContext", null) != null &&
                    loadClass("android.os.Build", null) != null &&
                    loadClass("dalvik.system.DexPathList", null) != null;
        } catch (Exception e) {
            isAndroid = false;
        }
        IS_ANDROID = isAndroid;
    }
    
    public static boolean areNullSafeEquals(Object obj1, Object obj2) {
        return obj1 == null ? obj2 == null : obj1.equals(obj2);
    }

    /**
     * Please do not use - internal
     * org/my/Class.xxx -> org.my.Class
     */
    public static String convertResourceToClassName(final String pResourceName) {
        return stripExtension(pResourceName).replace('/', '.');
    }

    /**
     * Please do not use - internal
     * org.my.Class -> org/my/Class.class
     */
    public static String convertClassToResourcePath(final Class cls) {
        return convertClassToResourcePath(cls.getName());
    }

    public static String convertClassToResourcePath(final String pName) {
        return pName.replace( '.',
                              '/' ) + ".class";
    }

    /**
     * Please do not use - internal
     * org/my/Class.xxx -> org/my/Class
     */
    public static String stripExtension(final String pResourceName) {
        final int i = pResourceName.lastIndexOf('.');
        return pResourceName.substring( 0, i );
    }

    public static String relative(final File base,
                                  final File file) {
        final int rootLength = base.getAbsolutePath().length();
        final String absFileName = file.getAbsolutePath();
        return absFileName.substring(rootLength + 1);
    }

    public static String canonicalName(Class clazz) {
        StringBuilder name = new StringBuilder();

        if ( clazz.isArray() ) {
            name.append( canonicalName( clazz.getComponentType() ) );
            name.append( "[]" );
        } else if ( clazz.getDeclaringClass() == null ) {
            name.append( clazz.getName() );
        } else {
            name.append( canonicalName( clazz.getDeclaringClass() ) );
            name.append( "." );
            name.append( clazz.getName().substring( clazz.getDeclaringClass().getName().length() + 1 ) );
        }

        return name.toString();
    }

    /**
     * This method will attempt to load the specified Class. It uses
     * a syncrhonized HashMap to cache the reflection Class lookup.
     */
    public static Class loadClass(String className,
                                     ClassLoader classLoader) {
        Class cls = classes.get(className );
        if ( cls == null ) {
            try {
                cls = Class.forName( className );
            } catch ( Exception e ) {
                //swallow
            }

            //ConfFileFinder
            if ( cls == null && classLoader != null ) {
                try {
                    cls = classLoader.loadClass( className );
                } catch ( Exception e ) {
                    //swallow
                }
            }

            if ( cls == null ) {
                try {
                    cls = ClassUtils.class.getClassLoader().loadClass( className );
                } catch ( Exception e ) {
                    //swallow
                }
            }

            if ( cls == null ) {
                try {
                    cls = Thread.currentThread().getContextClassLoader().loadClass( className );
                } catch ( Exception e ) {
                    //swallow
                }
            }

            if ( cls == null ) {
                try {
                    cls = ClassLoader.getSystemClassLoader().loadClass( className );
                } catch ( Exception e ) {
                    //swallow
                }
            }

            if ( cls != null ) {
                classes.put( className, cls );
            } else {
                throw new RuntimeException( "Unable to load class '" + className + "'" );
            }
        }
        return cls;
    }

    public static Object instantiateObject(String className) {
        return instantiateObject(className,
                (ClassLoader)null);
    }

    /**
     * This method will attempt to create an instance of the specified Class. It uses
     * a syncrhonized HashMap to cache the reflection Class lookup.
     */
    public static Object instantiateObject(String className,
                                           ClassLoader classLoader) {
        Object object;
        try {
            object = loadClass(className, classLoader).newInstance();
        } catch ( Throwable e ) {
            throw new RuntimeException( "Unable to instantiate object for class '" + className + "'",
                                        e );
        }
        return object;
    }

    /**
     * This method will attempt to create an instance of the specified Class. It uses
     * a synchronized HashMap to cache the reflection Class lookup.  It will execute the default
     * constructor with the passed in arguments
     * @param className the name of the class
     * @param args  arguments to default constructor
     */
    public static Object instantiateObject(String className,
                                           ClassLoader classLoader, Object...args) {
        Constructor c = constructors.computeIfAbsent(className, n -> loadClass(n, classLoader).getConstructors()[0]);

        Object object;
        try {
            object = c.newInstance(args);
        } catch ( Throwable e ) {
            throw new RuntimeException( "Unable to instantiate object for class '" + className +
                    "' with constructor " + c, e );
        }
        return object;
    }

    /**
     * This method will attempt to create an instance of the specified Class. It uses
     * a synchronized HashMap to cache the reflection Class lookup.  It will execute the default
     * constructor with the passed in arguments
     * @param className teh name of the class
     * @param args  arguments to default constructor
     */
    public static Object instantiateObject(String className, Object...args) {
        return instantiateObject(className, null, args);
    }

    /**
     * Populates the import style pattern map from give comma delimited string
     */
    public static void addImportStylePatterns(Map patterns,
                                              String str) {
        if ( str == null || "".equals( str.trim() ) ) {
            return;
        }

        String[] items = str.split( " " );
        for (String item : items) {
            String qualifiedNamespace = item.substring(0,
                    item.lastIndexOf('.')).trim();
            String name = item.substring(item.lastIndexOf('.') + 1).trim();
            Object object = patterns.get(qualifiedNamespace);
            if (object == null) {
                if (STAR.equals(name)) {
                    patterns.put(qualifiedNamespace,
                            STAR);
                } else {
                    // create a new list and add it
                    List list = new ArrayList<>();
                    list.add(name);
                    patterns.put(qualifiedNamespace, list);
                }
            } else if (name.equals(STAR)) {
                // if its a STAR now add it anyway, we don't care if it was a STAR or a List before
                patterns.put(qualifiedNamespace, STAR);
            } else {
                // its a list so add it if it doesn't already exist
                List list = (List) object;
                if (!list.contains(name)) {
                    list.add(name);
                }
            }
        }
    }

    /**
     * Determines if a given full qualified class name matches any import style patterns.
     */
    public static boolean isMatched(Map patterns,
                                    String className) {
        // Array [] object class names are "[x", where x is the first letter of the array type
        // -> NO '.' in class name, thus!
        // see http://download.oracle.com/javase/6/docs/api/java/lang/Class.html#getName%28%29
        String qualifiedNamespace = className;
        String name = className;
        if( className.indexOf('.') > 0 ) { 
            qualifiedNamespace = className.substring( 0, className.lastIndexOf( '.' ) ).trim();
            name = className.substring( className.lastIndexOf( '.' ) + 1 ).trim();
        }
        else if( className.indexOf('[') == 0 ) { 
           qualifiedNamespace = className.substring(0, className.lastIndexOf('[') );
        }
        Object object = patterns.get( qualifiedNamespace );
        if ( object == null ) {
            return true;
        } else if ( STAR.equals( object ) ) {
            return false;
        } else if ( patterns.containsKey( "*" ) ) {
            // for now we assume if the name space is * then we have a catchall *.* pattern
            return true;
        } else {
            List list = (List) object;
            return !list.contains( name );
        }
    }

    /**
     * Extracts the package name from the given class object
     */
    public static String getPackage(Class cls) {
        // cls.getPackage() sometimes returns null, in which case fall back to string massaging.
        Package pkg = cls.isArray() ? cls.getComponentType().getPackage() : cls.getPackage();
        if ( pkg == null ) {
            int dotPos;
            int dolPos = cls.getName().indexOf( '$' );
            if ( dolPos > 0 ) {
                // we have nested classes, so adjust dotpos to before first $
                dotPos = cls.getName().substring( 0, dolPos ).lastIndexOf( '.' );
            } else {
                dotPos = cls.getName().lastIndexOf( '.' );
            }
                
            if ( dotPos > 0 ) {
                return cls.getName().substring( 0,
                                                dotPos );
            } else {
                // must be default package.
                return "";
            }
        } else {
            return pkg.getName();
        }
    }

    public static Class findClass(String name, Collection availableImports, ClassLoader cl) {
        Class clazz = null;
        for (String imp : availableImports) {
            if (imp.endsWith(".*")) {
                imp = imp.substring(0, imp.length()-2);
            }
            String className = imp.endsWith(name) ? imp : imp + "." + name;
            clazz = findClass(className, cl);
            if (clazz != null) {
                break;
            }
        }
        return clazz;
    }

    public static Class findClass(String className, ClassLoader cl) {
        try {
            return Class.forName(className, false, cl);
        } catch (ClassNotFoundException e) {
            int lastDot = className.lastIndexOf('.');
            className = className.substring(0, lastDot) + "$" + className.substring(lastDot+1);
            try {
                return Class.forName(className, false, cl);
            } catch (ClassNotFoundException e1) { }
        }
        return null;
    }

    public static List getAccessibleProperties( Class clazz ) {
        Set props = new TreeSet<>();
        for (Method m : clazz.getMethods()) {
            if (m.getParameterTypes().length == 0) {
                String propName = getter2property(m.getName());
                if (propName != null && !propName.equals( "class" )) {
                    props.add( new PropertyInClass( propName, m.getDeclaringClass() ) );
                }
            }

            processModifiesAnnotation(clazz, props, m);
        }

        for (Field f : clazz.getFields()) {
            if ( Modifier.isPublic( f.getModifiers() ) && !Modifier.isStatic( f.getModifiers() ) ) {
                props.add( new PropertyInClass( f.getName(), f.getDeclaringClass() ) );
            }
        }

        List accessibleProperties = new ArrayList<>();
        for ( PropertyInClass setter : props ) {
            accessibleProperties.add(setter.setter);
        }
        return accessibleProperties;
    }

    public static Field getField(Class clazz, String field) {
        try {
            return clazz.getDeclaredField( field );
        } catch (NoSuchFieldException e) {
            return clazz.getSuperclass() != null ? getField(clazz.getSuperclass(), field) : null;
        }
    }

    public static Method getAccessor(Class clazz, String field) {
        return Stream.>of( () -> "get" + ucFirst(field), () -> field, () -> "is" + ucFirst(field), () -> "get" + field, () -> "is" + field )
                .map( f -> getMethod(clazz, f.get()) ).filter( Optional::isPresent ).findFirst().flatMap( Function.identity() ).orElse( null );
    }

    public static Method getSetter(Class clazz, String field, Class... parameterTypes) {
        return Stream.>of(
                () -> "set" + ucFirst(field),
                () -> field,
                () -> "set" + field
        )
                .map( f -> getMethod(clazz, f.get(), parameterTypes) )
                .filter( Optional::isPresent )
                .findFirst()
                .flatMap( Function.identity() )
                .orElse( null );
    }

    // Don't use this method. You should probably use org.drools.core.util.MethodUtils
    private static Optional getMethod(Class clazz, String name, Class... parameterTypes) {
        try {
            return Optional.of( clazz.getMethod(name, parameterTypes) );
        } catch (NoSuchMethodException e) {
            return Optional.empty();
        }
    }

    public static String ucFirst(final String s) {
        if (s == null) {
            return null;
        }

        if (s.length() == 1) {
            return s.toUpperCase();
        }

        return Character.isLowerCase(s.charAt( 0 )) ? Character.toUpperCase( s.charAt( 0 ) ) + s.substring( 1 ) : s;
    }

    private static Optional getMethod(Class clazz, String name) {
        try {
            return Optional.of( clazz.getMethod(name) );
        } catch (NoSuchMethodException e) {
            return Optional.empty();
        }
    }

    public static Class extractGenericType(Class clazz, final String methodName) {
        Method method = ClassUtils.getAccessor(clazz, methodName);
        if (method == null) {
            throw new RuntimeException(String.format("Unknown accessor %s on %s", methodName, clazz));
        }

        java.lang.reflect.Type returnType = method.getGenericReturnType();

        if(returnType instanceof ParameterizedType){
            ParameterizedType type = (ParameterizedType) returnType;
            java.lang.reflect.Type[] typeArguments = type.getActualTypeArguments();
            if (typeArguments.length > 0) {
                return (Class) typeArguments[0];
            }
        }
        throw new RuntimeException("No generic type");
    }

    private static void processModifiesAnnotation( Class clazz, Set props, Method m ) {
        Modifies modifies = m.getAnnotation( Modifies.class );
        if (modifies != null) {
            for (String prop : modifies.value()) {
                prop = prop.trim();
                try {
                    Field field = clazz.getField(prop);
                    props.add( new PropertyInClass( field.getName(), field.getDeclaringClass() ) );
                } catch (NoSuchFieldException e) {
                    String getter = "get" + prop.substring(0, 1).toUpperCase() + prop.substring(1);
                    try {
                        Method method = clazz.getMethod(getter);
                        props.add( new PropertyInClass( prop, method.getDeclaringClass() ) );
                    } catch (NoSuchMethodException e1) {
                        getter = "is" + prop.substring(0, 1).toUpperCase() + prop.substring(1);
                        try {
                            Method method = clazz.getMethod(getter);
                            props.add( new PropertyInClass( prop, method.getDeclaringClass() ) );
                        } catch (NoSuchMethodException e2) {
                            throw new RuntimeException(e2);
                        }
                    }
                }
            }
        }
    }

    public static boolean isTypeCompatibleWithArgumentType( Class actual, Class formal ) {
        if ( actual.isPrimitive() && formal.isPrimitive() ) {
            return isConvertible( actual, formal );
        } else if ( actual.isPrimitive() ) {
            return isConvertible( actual, convertToPrimitiveType( formal ) );
        } else if ( formal.isPrimitive() ) {
            return isConvertible( convertToPrimitiveType( actual ), formal );
        } else {
            return formal.isAssignableFrom( actual );
        }
    }

    public static boolean isAssignable( Class type, Object obj ) {
        return type.isInstance( obj ) || (type.isPrimitive() && convertFromPrimitiveType( type ).isInstance( obj ));
    }

    public static boolean isConvertible( Class srcPrimitive, Class tgtPrimitive ) {
        if ( Boolean.TYPE.equals( srcPrimitive ) ) {
            return Boolean.TYPE.equals( tgtPrimitive );
        } else if ( Byte.TYPE.equals( srcPrimitive ) ) {
            return Byte.TYPE.equals( tgtPrimitive )
                   || Short.TYPE.equals( tgtPrimitive )
                   || Integer.TYPE.equals( tgtPrimitive )
                   || Long.TYPE.equals( tgtPrimitive )
                   || Float.TYPE.equals( tgtPrimitive )
                   || Double.TYPE.equals( tgtPrimitive );
        } else if ( Character.TYPE.equals( srcPrimitive ) ) {
            return Character.TYPE.equals( tgtPrimitive )
                   || Integer.TYPE.equals( tgtPrimitive )
                   || Long.TYPE.equals( tgtPrimitive )
                   || Float.TYPE.equals( tgtPrimitive )
                   || Double.TYPE.equals( tgtPrimitive );
        } else if ( Double.TYPE.equals( srcPrimitive ) ) {
            return Double.TYPE.equals( tgtPrimitive );
        } else if ( Float.TYPE.equals( srcPrimitive ) ) {
            return Float.TYPE.equals( tgtPrimitive )
                   || Double.TYPE.equals( tgtPrimitive );
        } else if ( Integer.TYPE.equals( srcPrimitive ) ) {
            return Integer.TYPE.equals( tgtPrimitive )
                   || Long.TYPE.equals( tgtPrimitive )
                   || Float.TYPE.equals( tgtPrimitive )
                   || Double.TYPE.equals( tgtPrimitive );
        } else if ( Long.TYPE.equals( srcPrimitive ) ) {
            return Long.TYPE.equals( tgtPrimitive )
                   || Float.TYPE.equals( tgtPrimitive )
                   || Double.TYPE.equals( tgtPrimitive );
        } else if ( Short.TYPE.equals( srcPrimitive ) ) {
            return Short.TYPE.equals( tgtPrimitive )
                   || Integer.TYPE.equals( tgtPrimitive )
                   || Long.TYPE.equals( tgtPrimitive )
                   || Float.TYPE.equals( tgtPrimitive )
                   || Double.TYPE.equals( tgtPrimitive );
        }
        return false;
    }

    public static boolean isIterable(Class clazz) {
        return Iterable.class.isAssignableFrom( clazz ) || clazz.isArray();
    }

    public static boolean isFinal(Class clazz) {
        return Modifier.isFinal( clazz.getModifiers() );
    }
    
    public static boolean isInterface(Class clazz) {
        return Modifier.isInterface( clazz.getModifiers() );
    }

    private static class PropertyInClass implements Comparable {
        private final String setter;
        private final Class clazz;

        private PropertyInClass( String setter, Class clazz ) {
            this.setter = setter;
            this.clazz = clazz;
        }

        public int compareTo(Object o) {
            PropertyInClass other = (PropertyInClass) o;
            if (clazz == other.clazz) {
                return setter.compareTo(other.setter);
            }
            return clazz.isAssignableFrom(other.clazz) ? -1 : 1;
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof PropertyInClass)) {
                return false;
            }
            PropertyInClass other = (PropertyInClass) obj;
            return clazz == other.clazz && setter.equals(other.setter);
        }

        @Override
        public int hashCode() {
            return 29 * clazz.hashCode() + 31 * setter.hashCode();
        }
    }

    public static String getter2property(String methodName) {
        if (methodName.startsWith("get") && methodName.length() > 3) {
            return Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
        }
        if (methodName.startsWith("is") && methodName.length() > 2) {
            return Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3);
        }
        return null;
    }

    public static String setter2property(String methodName) {
        if (!methodName.startsWith("set") || methodName.length() < 4) {
            return null;
        }
        return Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
    }

    public static Class convertFromPrimitiveType(Class type) {
        if (!type.isPrimitive()) {
            return type;
        }
        if (type == int.class) {
            return Integer.class;
        }
        if (type == long.class) {
            return Long.class;
        }
        if (type == float.class) {
            return Float.class;
        }
        if (type == double.class) {
            return Double.class;
        }
        if (type == short.class) {
            return Short.class;
        }
        if (type == byte.class) {
            return Byte.class;
        }
        if (type == char.class) {
            return Character.class;
        }
        if (type == boolean.class) {
            return Boolean.class;
        }
        throw new RuntimeException("Class not convertible from primitive: " + type.getName());
    }

    public static Class convertToPrimitiveType(Class type) {
        if (type.isPrimitive()) {
            return type;
        }
        if (type == Integer.class) {
            return int.class;
        }
        if (type == Long.class) {
            return long.class;
        }
        if (type == Float.class) {
            return float.class;
        }
        if (type == Double.class) {
            return double.class;
        }
        if (type == Short.class) {
            return short.class;
        }
        if (type == Byte.class) {
            return byte.class;
        }
        if (type == Character.class) {
            return char.class;
        }
        if (type == Boolean.class) {
            return boolean.class;
        }
        if (type == BigInteger.class) {
            return long.class;
        }
        if (type == BigDecimal.class) {
            return double.class;
        }
        if (type == Number.class) {
            return double.class;
        }
        throw new RuntimeException("Class not convertible to primitive: " + type.getName());
    }

    public static Class convertPrimitiveNameToType( String typeName ) {
        return primitiveNameToType.get(typeName);
    }

    public static Set> getAllImplementedInterfaceNames( Class klass ) {
        Set> interfaces = new HashSet<>();
        while( klass != null ) {
            Class[] localInterfaces = klass.getInterfaces();
            for ( Class intf : localInterfaces ) {
                interfaces.add( intf );
                exploreSuperInterfaces( intf, interfaces );
            }
            klass = klass.getSuperclass();
        }
        return interfaces;
    }

    private static void exploreSuperInterfaces( Class intf, Set> traitInterfaces ) {
        for ( Class sup : intf.getInterfaces() ) {
            traitInterfaces.add( sup );
            exploreSuperInterfaces( sup, traitInterfaces );
        }
    }

    public static Set> getMinimalImplementedInterfaceNames( Class klass ) {
        Set> interfaces = new HashSet<>();
        while( klass != null ) {
            Class[] localInterfaces = klass.getInterfaces();
            for ( Class intf : localInterfaces ) {
                boolean subsumed = false;
                for ( Class i : new ArrayList<>(interfaces) ) {
                    if ( intf.isAssignableFrom( i ) ) {
                        subsumed = true;
                        break;
                    } else if ( i.isAssignableFrom( intf ) ) {
                        interfaces.remove( i );
                    }
                }
                if ( subsumed ) {
                    continue;
                }
                interfaces.add( intf );
            }
            klass = klass.getSuperclass();
        }
        return interfaces;
    }

    public static boolean isCaseSenstiveOS() {
        String os =  System.getProperty("os.name").toUpperCase();
        return os.contains( "WINDOWS" ) || os.contains( "MAC OS X" );
    }

    public static boolean isWindows() {
        String os =  System.getProperty("os.name");
        return os.toUpperCase().contains( "WINDOWS" );
    }

    public static boolean isOSX() {
        String os =  System.getProperty("os.name");
        return os.toUpperCase().contains( "MAC OS X" );
    }

    public static boolean isJboss() {
        return System.getProperty("jboss.server.name") != null;
    }

    /**
     * Checks if running on Android operating system
     */
    public static boolean isAndroid() {
        return IS_ANDROID;
    }

    public static Class findCommonSuperClass(Class c1, Class c2) {
        if (c1 == null) {
            return c2;
        }
        if (c2 == null) {
            return c1;
        }
        if (c1.isAssignableFrom( c2 )) {
            return c1;
        }
        if (c2.isAssignableFrom( c1 )) {
            return c2;
        }
        for (Class parent = c1.getSuperclass(); parent != null; parent = parent.getSuperclass()) {
            if (parent.isAssignableFrom(c2)) {
                return parent;
            }
        }
        return c1;
    }

    public static Class getClassFromName(String className) throws ClassNotFoundException {
        return getClassFromName( className, true, ClassUtils.class.getClassLoader() );
    }

    public static Class getClassFromName(String className, boolean initialize, ClassLoader classLoader) throws ClassNotFoundException {
        try {
            Class clazz;
            if (abbreviationMap.containsKey(className)) {
                final String clsName = "[" + abbreviationMap.get(className);
                clazz = Class.forName(clsName, initialize, classLoader).getComponentType();
            } else {
                clazz = Class.forName(toCanonicalName( className ), initialize, classLoader);
            }
            return clazz;
        } catch (final ClassNotFoundException ex) {
            // allow path separators (.) as inner class name separators
            final int lastDotIndex = className.lastIndexOf('.');

            if (lastDotIndex != -1) {
                try {
                    return getClassFromName( className.substring( 0, lastDotIndex ) + '$' + className.substring( lastDotIndex + 1 ),
                                             initialize, classLoader);
                } catch (final ClassNotFoundException ex2) { // NOPMD
                    // ignore exception
                }
            }

            throw ex;
        }
    }

    private static String toCanonicalName(String className) {
        if (className == null) {
            throw new NullPointerException("className must not be null.");
        } else if (className.endsWith("[]")) {
            final StringBuilder classNameBuffer = new StringBuilder();
            while (className.endsWith("[]")) {
                className = className.substring(0, className.length() - 2);
                classNameBuffer.append("[");
            }
            final String abbreviation = abbreviationMap.get(className);
            if (abbreviation != null) {
                classNameBuffer.append(abbreviation);
            } else {
                classNameBuffer.append("L").append(className).append(";");
            }
            className = classNameBuffer.toString();
        }
        return className;
    }

    public static Class safeLoadClass(ClassLoader cl, String name) {
        try {
            return cl.loadClass( name );
        }
        catch ( final ClassNotFoundException | NoClassDefFoundError cnfe ) {
            // class doesn't exist
            // potential mis-match induced by Mac/OSX
        }
        return null;
    }

    public static String getSimpleName(Class c) {
        return getCanonicalSimpleName( c, '$' );
    }

    public static String getCanonicalSimpleName(Class c) {
        return getCanonicalSimpleName( c, '.' );
    }

    public static String getCanonicalSimpleName(Class c, char separator) {
        Class enclosingClass = c.getEnclosingClass();
        return enclosingClass != null ?
               getCanonicalSimpleName(enclosingClass) + separator + c.getSimpleName() :
               c.getSimpleName();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy