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

org.datanucleus.util.ClassUtils Maven / Gradle / Ivy

Go to download

DataNucleus Core provides the primary components of a heterogenous Java persistence solution. It supports persistence API's being layered on top of the core functionality.

There is a newer version: 6.0.7
Show newest version
/**********************************************************************
Copyright (c) 2004 Andy Jefferson and others. All rights reserved. 
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. 


Contributors:
    ...
**********************************************************************/
package org.datanucleus.util;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.datanucleus.ClassConstants;
import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.ClassNameConstants;
import org.datanucleus.exceptions.ClassNotResolvedException;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;

/**
 * Utilities for handling classes.
 * These are to supplement the methods provided by the Class object.
 */
public class ClassUtils
{
    /** caching for constructors - using caching, the perf is at least doubled **/
    protected static final Map constructorsCache = new SoftValueMap();

    /**
     * Accessor for a new instance of an object.
     * Uses reflection to generate the instance using the passed constructor parameter arguments.
     * Caches the constructor used to improve performance for later invocation.
     * @param type Type of object (the class).
     * @param parameterTypes Classes of params for the constructor
     * @param parameters The parameters for the constructor
     * @return The object
     * @throws NucleusException If an error occurs creating the instance
     */
    public static Object newInstance(Class type, Class[] parameterTypes, Object[] parameters)
    {
        Object obj;
        try
        {
            StringBuilder name = new StringBuilder(""+type.getName());
            if (parameterTypes != null)
            {
                for (int i=0;i getClassFilesForDirectory(File dir, boolean normal_classes, boolean inner_classes)
    {
        if (dir == null)
        {
            return null;
        }

        Collection classes=new HashSet();
        File[] files = dir.listFiles();
        if (files != null)
        {
            for (int i=0;i 0)
                    {
                        classes.addAll(child_classes);
                    }
                }
            }
        }

        return classes;
    }

    /**
     * Method to return the files below the specified directory.
     * @param dir The directory
     * @return The files
     */
    public static Collection getFilesForDirectory(File dir)
    {
        if (dir == null)
        {
            return null;
        }

        Collection files = new HashSet();
        File[] dirFiles = dir.listFiles();
        if (dirFiles != null)
        {
            for (int i=0;i 0)
                    {
                        files.addAll(childFiles);
                    }
                }
            }
        }

        return files;
    }

    /**
     * Convenience accessor for the names of all class files in the jar file with the specified name.
     * The returned class names are of the form "org.datanucleus.MyClass".
     * @param jarFileName Name of the jar file
     * @return The class names
     */
    public static String[] getClassNamesForJarFile(String jarFileName)
    {
        try
        {
            JarFile jar = new JarFile(jarFileName);
            return getClassNamesForJarFile(jar);
        }
        catch (IOException ioe)
        {
            NucleusLogger.GENERAL.warn("Error opening the jar file " + jarFileName + " : " + ioe.getMessage());
        }
        return null;
    }

    /**
     * Convenience accessor for the names of all class files in the jar file with the specified URL.
     * The returned class names are of the form "org.datanucleus.MyClass".
     * @param jarFileURL URL for the jar file
     * @return The class names
     */
    public static String[] getClassNamesForJarFile(URL jarFileURL)
    {
        File jarFile = new File(jarFileURL.getFile()); // TODO Check for errors
        try
        {
            JarFile jar = new JarFile(jarFile);
            return getClassNamesForJarFile(jar);
        }
        catch (IOException ioe)
        {
            NucleusLogger.GENERAL.warn("Error opening the jar file " + jarFileURL.getFile() + " : " + ioe.getMessage());
        }
        return null;
    }

    /**
     * Convenience accessor for the names of all class files in the jar file with the specified URL.
     * The returned class names are of the form "org.datanucleus.MyClass".
     * @param jarFileURI URI for the jar file
     * @return The class names
     */
    public static String[] getClassNamesForJarFile(URI jarFileURI)
    {
        try
        {
            return getClassNamesForJarFile(jarFileURI.toURL());
        }
        catch (MalformedURLException mue)
        {
            throw new NucleusException("Error opening the jar file " + jarFileURI, mue);
        }
    }

    /**
     * Convenience method to return the names of classes specified in the jar file.
     * All inner classes are ignored.
     * @param jar Jar file
     * @return The class names
     */
    private static String[] getClassNamesForJarFile(JarFile jar)
    {
        Enumeration jarEntries = jar.entries();
        Set classes = new HashSet();
        while (jarEntries.hasMoreElements())
        {
            String entry = ((JarEntry)jarEntries.nextElement()).getName();
            if (entry.endsWith(".class") && !ClassUtils.isInnerClass(entry))
            {
                String className = entry.substring(0, entry.length()-6); // Omit ".class"
                className = className.replace(File.separatorChar, '.');
                classes.add(className);
            }
        }
        return classes.toArray(new String[classes.size()]);
    }

    /**
     * Convenience accessor for the names of all "package.jdo" files in the jar file with the specified name.
     * @param jarFileName Name of the jar file
     * @return The "package.jdo" file names
     */
    public static String[] getPackageJdoFilesForJarFile(String jarFileName)
    {
        try
        {
            JarFile jar = new JarFile(jarFileName);
            return getFileNamesWithSuffixForJarFile(jar, "package.jdo");
        }
        catch (IOException ioe)
        {
            NucleusLogger.GENERAL.warn("Error opening the jar file " + jarFileName + " : " + ioe.getMessage());
        }
        return null;
    }

    /**
     * Convenience accessor for the names of all "package.jdo" files in the jar file with the specified URL.
     * @param jarFileURL URL for the jar file
     * @return The "package.jdo" file names
     */
    public static String[] getPackageJdoFilesForJarFile(URL jarFileURL)
    {
        File jarFile = new File(jarFileURL.getFile()); // TODO Check for errors
        try
        {
            JarFile jar = new JarFile(jarFile);
            return getFileNamesWithSuffixForJarFile(jar, "package.jdo");
        }
        catch (IOException ioe)
        {
            NucleusLogger.GENERAL.warn("Error opening the jar file " + jarFileURL.getFile() + " : " + ioe.getMessage());
        }
        return null;
    }

    /**
     * Convenience accessor for the names of all "package.jdo" files in the jar file with the specified URL.
     * @param jarFileURI URI for the jar file
     * @return The "package.jdo" file names
     */
    public static String[] getPackageJdoFilesForJarFile(URI jarFileURI)
    {
        URL jarFileURL = null;
        try
        {
            jarFileURL = jarFileURI.toURL();
        }
        catch (MalformedURLException mue)
        {
            throw new NucleusException("JAR file at " + jarFileURI + " not openable. Invalid URL");
        }
        return getPackageJdoFilesForJarFile(jarFileURL);
    }

    /**
     * Convenience method to return the names of files specified in the jar file that end with
     * the specified suffix.
     * @param jar Jar file
     * @param suffix Suffix for the file (can be the filename without the path)
     * @return The fully-qualified names of the files with this suffix in the jar file
     */
    private static String[] getFileNamesWithSuffixForJarFile(JarFile jar, String suffix)
    {
        Enumeration jarEntries = jar.entries();
        Set files = new HashSet();
        while (jarEntries.hasMoreElements())
        {
            String entry = ((JarEntry)jarEntries.nextElement()).getName();
            if (entry.endsWith(suffix))
            {
                files.add(entry);
            }
        }
        return files.toArray(new String[files.size()]);
    }

    /**
     * Convenience method to return the names of classes specified in the directory and below.
     * All inner classes are ignored.
     * @param dir Directory that we should look below (root of classpath)
     * @return The class names
     */
    public static String[] getClassNamesForDirectoryAndBelow(File dir)
    {
        if (dir == null)
        {
            return null;
        }

        Collection classFiles = getClassFilesForDirectory(dir, true, false);
        if (classFiles == null || classFiles.isEmpty())
        {
            return null;
        }

        String[] classNames = new String[classFiles.size()];
        Iterator iter = classFiles.iterator();
        int i = 0;
        while (iter.hasNext())
        {
            String filename = iter.next().getAbsolutePath();

            // Omit root part and trailing ".class"
            String classname = filename.substring(dir.getAbsolutePath().length()+1, filename.length()-6);
            classNames[i++] = classname.replace(File.separatorChar, '.');
        }
        return classNames;
    }

    /**
     * Method to check whether a classname is for an inner class.
     * Currently checks for the presence of $ in the name.
     * @param class_name The class name
     * @return Whether it is an inner class
     */
    public static boolean isInnerClass(String class_name)
    {
        if (class_name == null)
        {
            return false;
        }
        else if (class_name.indexOf('$') >= 0)
        {
            return true;
        }
        return false;
    }

    /**
     * Method to check for a default constructor on a class.
     * Particular relevance for JDO is the requirement for a default
     * constructor on all Persistence-Capable classes. Doesn't check
     * superclasses for the default constructor.
     * @param the_class The class
     * @return Whether it has a default constructor
     **/
    public static boolean hasDefaultConstructor(Class the_class)
    {
        if (the_class == null)
        {
            return false;
        }
        try
        {
            the_class.getDeclaredConstructor();
        }
        catch (Exception e)
        {
            return false;
        }

        return true;
    }

    /**
     * Method to return the superclasses for a class.
     * The superclasses will be ordered.
     * @param the_class The class
     * @return The superclass of this class.
     */
    public static Collection> getSuperclasses(Class the_class)
    {
        List> result = new ArrayList>();
        Class superclass = the_class.getSuperclass();
        while (superclass != null)
        {
            result.add(superclass);
            superclass = superclass.getSuperclass();
        }
        return result;
    }

    /**
     * Method to return the superinterfaces for a class.
     * The superinterfaces will be ordered and unique.
     * @param the_class The class
     * @return The superinterfaces of this class.
     */
    public static Collection> getSuperinterfaces(Class the_class)
    {
        List> result = new ArrayList>();
        collectSuperinterfaces(the_class, result);
        return result;
    }

    private static void collectSuperinterfaces(Class c, List> result)
    {
        // TODO Include interfaces of superclasses? (see ClassUtilsTest.testGetSuperinterfacesViaSuperclass)
//        Class superclass = c.getSuperclass();
//        if (superclass != null)
//        {
//            collectSuperinterfaces(superclass, result);
//        }

        for (Class i : c.getInterfaces())
        {
            if (!result.contains(i))
            {
                result.add(i);
                collectSuperinterfaces(i, result);
            }
        }
    }

    /**
     * Obtain a field from a class or superclasses using reflection.
     * @param cls the class to find the field from
     * @param fieldName the field name to find
     * @return The Field 
     */
    public static Field getFieldForClass(Class cls, String fieldName)
    {
        try
        {
            do
            {
                try
                {
                    return cls.getDeclaredField(fieldName);
                }
                catch (NoSuchFieldException e)
                {
                    cls = cls.getSuperclass();
                }
            }
            while (cls != null);
        }
        catch (Exception e)
        {
            // do nothing
        }
        return null;
    }

    /**
     * Obtain a (Java bean) getter method from a class or superclasses using reflection.
     * Any 'get...' method will take precedence over 'is...' methods.
     * @param cls the class to find the getter from
     * @param beanName the name of the java bean to find the getter for
     * @return The getter Method 
     */
    public static Method getGetterMethodForClass(Class cls, String beanName)
    {
        Method getter = findDeclaredMethodInHeirarchy(cls, getJavaBeanGetterName(beanName, false));
        if (getter == null)
        {
            getter = findDeclaredMethodInHeirarchy(cls, getJavaBeanGetterName(beanName, true));
        }
        return getter;
    }

    /**
     * Obtain a (Java bean) setter method from a class or superclasses using reflection.
     * @param cls the class to find the setter from
     * @param beanName the name of the java bean to find the setter for
     * @param type the type of the java bean to find the setter for
     * @return The setter Method
     */
    public static Method getSetterMethodForClass(Class cls, String beanName, Class type)
    {
        return findDeclaredMethodInHeirarchy(cls, getJavaBeanSetterName(beanName), type);
    }

    private static Method findDeclaredMethodInHeirarchy(Class cls, String methodName, Class... parameterTypes)
    {
        try
        {
            do
            {
                try
                {
                    return cls.getDeclaredMethod(methodName, parameterTypes);
                }
                catch (NoSuchMethodException e)
                {
                    cls = cls.getSuperclass();
                }
            }
            while (cls != null);
        }
        catch (Exception e)
        {
            // do nothing
        }
        return null;
    }

    /**
     * Convenience method to return the object wrapper type for a primitive type name.
     * If the type is not a primitive then just returns the type name
     * @param typeName The primitive type name
     * @return The object wrapper type name for this primitive
     */
    public static String getWrapperTypeNameForPrimitiveTypeName(String typeName)
    {
        if (typeName.equals("boolean"))
        {
            return ClassNameConstants.JAVA_LANG_BOOLEAN;
        }
        else if (typeName.equals("byte"))
        {
            return ClassNameConstants.JAVA_LANG_BYTE;
        }
        else if (typeName.equals("char"))
        {
            return ClassNameConstants.JAVA_LANG_CHARACTER;
        }
        else if (typeName.equals("double"))
        {
            return ClassNameConstants.JAVA_LANG_DOUBLE;
        }
        else if (typeName.equals("float"))
        {
            return ClassNameConstants.JAVA_LANG_FLOAT;
        }
        else if (typeName.equals("int"))
        {
            return ClassNameConstants.JAVA_LANG_INTEGER;
        }
        else if (typeName.equals("long"))
        {
            return ClassNameConstants.JAVA_LANG_LONG;
        }
        else if (typeName.equals("short"))
        {
            return ClassNameConstants.JAVA_LANG_SHORT;
        }
        else
        {
            return typeName;
        }
    }

    /**
     * Convenience method to return the object wrapper type for a primitive type.
     * @param type The primitive type 
     * @return The object wrapper type for this primitive
     */
    public static Class getWrapperTypeForPrimitiveType(Class type)
    {
        if (type == boolean.class)
        {
            return ClassConstants.JAVA_LANG_BOOLEAN;
        }
        else if (type == byte.class)
        {
            return ClassConstants.JAVA_LANG_BYTE;
        }
        else if (type == char.class)
        {
            return ClassConstants.JAVA_LANG_CHARACTER;
        }
        else if (type == double.class)
        {
            return ClassConstants.JAVA_LANG_DOUBLE;
        }
        else if (type == float.class)
        {
            return ClassConstants.JAVA_LANG_FLOAT;
        }
        else if (type == int.class)
        {
            return ClassConstants.JAVA_LANG_INTEGER;
        }
        else if (type == long.class)
        {
            return ClassConstants.JAVA_LANG_LONG;
        }
        else if (type == short.class)
        {
            return ClassConstants.JAVA_LANG_SHORT;
        }
        return null;
    }

    /**
     * Method to return the primitive equivalent of the specified type (if any).
     * Returns null if there is no primitive equivalent.
     * @param type The type
     * @return The primitive equivalent.
     */
    public static Class getPrimitiveTypeForType(Class type)
    {
        if (type == Boolean.class)
        {
            return ClassConstants.BOOLEAN;
        }
        else if (type == Byte.class)
        {
            return ClassConstants.BYTE;
        }
        else if (type == Character.class)
        {
            return ClassConstants.CHAR;
        }
        else if (type == Double.class)
        {
            return ClassConstants.DOUBLE;
        }
        else if (type == Float.class)
        {
            return ClassConstants.FLOAT;
        }
        else if (type == Integer.class)
        {
            return ClassConstants.INT;
        }
        else if (type == Long.class)
        {
            return ClassConstants.LONG;
        }
        else if (type == Short.class)
        {
            return ClassConstants.SHORT;
        }
        else
        {
            return null;
        }
    }

    /**
     * Convenience method to return if the passed type (name) is a primitive wrapper type.
     * @param typeName Name of the type
     * @return Whether it is a primitive wrapper
     */
    public static boolean isPrimitiveWrapperType(String typeName)
    {
        if (typeName.equals(ClassNameConstants.JAVA_LANG_BOOLEAN) ||
            typeName.equals(ClassNameConstants.JAVA_LANG_BYTE) ||
            typeName.equals(ClassNameConstants.JAVA_LANG_CHARACTER) ||
            typeName.equals(ClassNameConstants.JAVA_LANG_DOUBLE) ||
            typeName.equals(ClassNameConstants.JAVA_LANG_FLOAT) ||
            typeName.equals(ClassNameConstants.JAVA_LANG_INTEGER) ||
            typeName.equals(ClassNameConstants.JAVA_LANG_LONG) ||
            typeName.equals(ClassNameConstants.JAVA_LANG_SHORT))
        {
            return true;
        }
        return false;
    }

    /**
     * Convenience method to return if the passed type (name) is a primitive array type.
     * @param typeName Name of the type
     * @return Whether it is a primitive array
     */
    public static boolean isPrimitiveArrayType(String typeName)
    {
        if (typeName.equals(ClassNameConstants.BOOLEAN_ARRAY) ||
            typeName.equals(ClassNameConstants.BYTE_ARRAY) ||
            typeName.equals(ClassNameConstants.CHAR_ARRAY) ||
            typeName.equals(ClassNameConstants.DOUBLE_ARRAY) ||
            typeName.equals(ClassNameConstants.FLOAT_ARRAY) ||
            typeName.equals(ClassNameConstants.INT_ARRAY) ||
            typeName.equals(ClassNameConstants.LONG_ARRAY) ||
            typeName.equals(ClassNameConstants.SHORT_ARRAY))
        {
            return true;
        }
        return false;
    }

    /**
     * Convenience method to return if the passed type (name) is a primitive type.
     * @param typeName Name of the type
     * @return Whether it is a primitive
     */
    public static boolean isPrimitiveType(String typeName)
    {
        if (typeName.equals(ClassNameConstants.BOOLEAN) ||
            typeName.equals(ClassNameConstants.BYTE) ||
            typeName.equals(ClassNameConstants.CHAR) ||
            typeName.equals(ClassNameConstants.DOUBLE) ||
            typeName.equals(ClassNameConstants.FLOAT) ||
            typeName.equals(ClassNameConstants.INT) ||
            typeName.equals(ClassNameConstants.LONG) ||
            typeName.equals(ClassNameConstants.SHORT))
        {
            return true;
        }
        return false;
    }

    /**
     * Convenience method to convert the passed value to an object of the specified type (if possible).
     * If no such conversion is supported will return null. If the required type is a primitive will
     * return an object of the wrapper type.
     * @param value The value
     * @param cls The class
     * @return The converted value (or null)
     */
    public static Object convertValue(Object value, Class cls)
    {
        if (value == null)
        {
            return null;
        }

        Class type = cls;
        if (cls.isPrimitive())
        {
            type = getWrapperTypeForPrimitiveType(cls);
        }
        if (type.isAssignableFrom(value.getClass()))
        {
            // Already in the correct type
            return value;
        }

        if (type == Long.class && value instanceof Number)
        {
            return Long.valueOf(((Number)value).longValue());
        }
        else if (type == Integer.class && value instanceof Number)
        {
            return Integer.valueOf(((Number)value).intValue());
        }
        else if (type == Short.class && value instanceof Number)
        {
            return Short.valueOf(((Number)value).shortValue());
        }
        else if (type == Float.class && value instanceof Number)
        {
            return Float.valueOf(((Number)value).floatValue());
        }
        else if (type == Double.class && value instanceof Number)
        {
            return Double.valueOf(((Number)value).doubleValue());
        }
        else if (type == Boolean.class && value instanceof Long)
        {
            // Convert a Long (0, 1) to Boolean (FALSE, TRUE) and null otherwise
            return (Long)value == 0 ? Boolean.FALSE : ((Long)value == 1 ? Boolean.TRUE : null);
        }
        else if (type == Boolean.class && value instanceof Integer)
        {
            // Convert a Integer (0, 1) to Boolean (FALSE, TRUE) and null otherwise
            return (Integer)value == 0 ? Boolean.FALSE : ((Integer)value == 1 ? Boolean.TRUE : null);
        }
        return null;
    }

    /**
     * Convenience method to return if two types are compatible.
     * Returns true if both types are primitive/wrappers and are of the same type.
     * Returns true if clsName2 is the same or a subclass of cls1.
     * Otherwise returns false;
     * @param cls1 First class
     * @param clsName2 Name of the second class
     * @param clr ClassLoader resolver to use
     * @return Whether they are compatible
     */
    public static boolean typesAreCompatible(Class cls1, String clsName2, ClassLoaderResolver clr)
    {
        if (clr.isAssignableFrom(cls1, clsName2))
        {
            return true;
        }

        // Cater for primitive and primitive wrappers being compatible
        if (cls1.isPrimitive())
        {
            return clr.isAssignableFrom(ClassUtils.getWrapperTypeForPrimitiveType(cls1), clsName2);
        }
        else if (ClassUtils.isPrimitiveWrapperType(cls1.getName()))
        {
            return clr.isAssignableFrom(ClassUtils.getPrimitiveTypeForType(cls1), clsName2);
        }

        return false;
    }

    /**
     * Convenience method to return if two types are compatible.
     * Returns true if both types are primitive/wrappers and are of the same type.
     * Returns true if cls2 is the same or a subclass of cls1.
     * Otherwise returns false;
     * @param cls1 First class
     * @param cls2 Second class
     * @return Whether they are compatible
     */
    public static boolean typesAreCompatible(Class cls1, Class cls2)
    {
        if (cls1.isAssignableFrom(cls2))
        {
            return true;
        }

        // Cater for primitive and primitive wrappers being compatible
        if (cls1.isPrimitive())
        {
            return ClassUtils.getWrapperTypeForPrimitiveType(cls1).isAssignableFrom(cls2);
        }

        return false;
    }

    /**
     * Utility to create the full class name given the package and class name.
     * Some examples 
     * 
     * packageName=test className=Test, returns result=test.Test
     * packageName=test className=test1.Test, returns result=test1.Test
     * packageName=<null> className=Test, returns result=Test
     * packageName=<null> className=test1.Test, returns result=test1.Test
     * 
* @param pkg_name package name. * @param cls_name class name. * @return generated full class name. */ public static String createFullClassName(String pkg_name, String cls_name) { if (StringUtils.isWhitespace(cls_name)) { throw new IllegalArgumentException("Class name not specified"); } else if (StringUtils.isWhitespace(pkg_name)) { return cls_name; } else if (cls_name.indexOf('.') >= 0) { return cls_name; } return pkg_name + "." + cls_name; } /** * Convenience method to return the passed type as a java.lang type wherever possible. * The passed type will be stripped of any package name and will be checked if it is * a known java.lang class. This is used where the user has specified a class name * for a collection or map element/key/value type and meant a java.lang class but didn't * fully qualify it. * @param type The type name * @return The java.lang equivalent (or the input type if not possible) */ public static String getJavaLangClassForType(String type) { // Strip off any package name String baseType = null; if (type.lastIndexOf('.') < 0) { baseType = type; } else { baseType = type.substring(type.lastIndexOf('.')+1); } // Check against our known (supported) java.lang classes if (baseType.equals("String") || baseType.equals("Object") || baseType.equals("Boolean") || baseType.equals("Byte") || baseType.equals("Character") || baseType.equals("Double") || baseType.equals("Float") || baseType.equals("Integer") || baseType.equals("Long") || baseType.equals("Short") || baseType.equals("Number") || baseType.equals("StringBuffer") || baseType.equals("StringBuilder")) { return "java.lang." + baseType; } return type; } /** * Method to check if 2 classes are direct descendents. So one of them is a * superclass of the other. * @param clr ClassLoaderResolver for loading the classes * @param class_name_1 Name of first class * @param class_name_2 Name of second class * @return Whether they are direct descendents. */ public static boolean classesAreDescendents(ClassLoaderResolver clr, String class_name_1, String class_name_2) { Class class_1=clr.classForName(class_name_1); Class class_2=clr.classForName(class_name_2); if (class_1 == null || class_2 == null) { return false; } // Check for direct descendents if (class_1.isAssignableFrom(class_2) || class_2.isAssignableFrom(class_1)) { return true; } return false; } /** * Utility to use Reflection to dump out the details of a class. * Will list all superclasses, interfaces, methods and fields. * Can be used, for example, in checking the methods adding by the * enhancement process. The information is dumped out the GENERAL log. * @param cls The class to dump out to the log */ public static void dumpClassInformation(Class cls) { NucleusLogger.GENERAL.info("----------------------------------------"); NucleusLogger.GENERAL.info("Class Information for class " + cls.getName()); // Superclasses for (Class superclass : ClassUtils.getSuperclasses(cls)) { NucleusLogger.GENERAL.info(" Superclass : " + superclass.getName()); } // TODO Should this be calling ClassUtils.getSuperinterfaces(cls)? // Interfaces Class[] interfaces=cls.getInterfaces(); if (interfaces != null) { for (int i=0;i= 0) { String className = name.substring(name.indexOf('.') + 1); try { Class cls = clr.classForName(className); if (cls != null) { return className; } } catch (ClassNotResolvedException cnre) { } name = className; } return null; } /** * Utility to find the class name of a class given the absolute file name of its class file. * Creates a loader and loads the class directly to find it. * @param fileURL URL for the class file * @return The name of the class * @throws ClassNotFoundException Thrown when the file is not found */ public static String getClassNameForFileURL(final URL fileURL) throws ClassNotFoundException { ClassLoader loader = (ClassLoader) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { return new ClassLoader() { protected Class findClass(String name) throws ClassNotFoundException { // Always load the file InputStream in = null; try { in = new BufferedInputStream(fileURL.openStream()); ByteArrayOutputStream byteStr = new ByteArrayOutputStream(); int byt = -1; while ((byt = in.read()) != -1) { byteStr.write(byt); } byte byteArr[] = byteStr.toByteArray(); return defineClass(null, byteArr, 0, byteArr.length); } catch (final RuntimeException rex) { throw rex; } catch (final Exception ex) { throw new ClassNotFoundException(name); } finally { if (in != null) { try { in.close(); } catch (final IOException ioe) { } } } } }; } }); // TODO This can fail if the specified class implements inner interface see NUCCORE-632 Class cls = loader.loadClass("garbage"); // The passed in name is not of relevance since using URL return (cls != null ? cls.getName() : null); } /** * Utility to return the package name for a class. * Allows for the result of class.getPackage() being null. * @param cls The class * @return The name of its package (or null if no package e.g a primitive) */ public static String getPackageNameForClass(Class cls) { // Check getPackage and use that if specified. if (cls.getPackage() != null) { return cls.getPackage().getName(); } int separator = cls.getName().lastIndexOf('.'); if (separator < 0) { return null; } return cls.getName().substring(0, separator); } /** * Utility to return the class name without the package name for a class. * @param cls The class * @return The name of the class without its package */ public static String getClassNameForClass(Class cls) { // Just strip off all up to the last separator since Class.getPackage is unreliable int separator = cls.getName().lastIndexOf('.'); if (separator < 0) { return cls.getName(); } return cls.getName().substring(separator+1); } /** * Convenience method to attempt to return the class for the provided generic type. * @param genericType The generic type * @param pos The position of the generic arg (in case of multiple) * @return The class (if determinable), or null */ public static Class getClassForGenericType(Type genericType, int pos) { if (genericType instanceof ParameterizedType) { ParameterizedType paramtype = (ParameterizedType)genericType; if (paramtype.getActualTypeArguments().length > pos) { Type argType = paramtype.getActualTypeArguments()[pos]; if (argType instanceof Class) { return (Class) argType; } else if (argType instanceof ParameterizedType) { return (Class) ((ParameterizedType)argType).getRawType(); } else if (argType instanceof GenericArrayType) { // Create array of zero length to get class of array type (is there a better way?) Type cmptType = ((GenericArrayType)argType).getGenericComponentType(); return Array.newInstance((Class)cmptType, 0).getClass(); } } } return null; } /** * Convenience method to extract the element type of a collection when using JDK1.5 generics given the * input field. * @param field The field * @return The name of the element class */ public static String getCollectionElementType(Field field) { Class elementType = getCollectionElementType(field.getType(), field.getGenericType()); return (elementType != null ? elementType.getName() : null); } /** * Convenience method to extract the element type of a collection when using JDK1.5 generics, given * the input method (getter). * @param method The method * @return The name of the element class */ public static String getCollectionElementType(Method method) { Class elementType = getCollectionElementType(method.getReturnType(), method.getGenericReturnType()); return (elementType != null ? elementType.getName() : null); } /** * Convenience method to extract the element type of a collection when using JDK1.5 generics given the * input field. * @param type the field type * @param genericType the generic type * @return The element class */ public static Class getCollectionElementType(Class type, Type genericType) { if (!Collection.class.isAssignableFrom(type)) { return null; } return getClassForGenericType(genericType, 0); } /** * Convenience method to extract the key type of a map when using JDK1.5 generics given the * input field. * @param field The field * @return The name of the key class */ public static String getMapKeyType(Field field) { Class keyType = getMapKeyType(field.getType(), field.getGenericType()); return (keyType != null ? keyType.getName() : null); } /** * Convenience method to extract the key type of a map when using JDK1.5 generics given the * input method. * @param method The method * @return The name of the key class */ public static String getMapKeyType(Method method) { Class keyType = getMapKeyType(method.getReturnType(), method.getGenericReturnType()); return (keyType != null ? keyType.getName() : null); } /** * Convenience method to extract the key type of a map when using JDK1.5 generics given the * input field. * @param type the field type * @param genericType the generic type * @return The name of the key class */ public static Class getMapKeyType(Class type, Type genericType) { if (!Map.class.isAssignableFrom(type)) { return null; } return getClassForGenericType(genericType, 0); } /** * Convenience method to extract the value type of a map when using JDK1.5 generics given the * input field * @param field The field * @return The name of the value class */ public static String getMapValueType(Field field) { Class valueType = getMapValueType(field.getType(), field.getGenericType()); return (valueType != null ? valueType.getName() : null); } /** * Convenience method to extract the value type of a map when using JDK1.5 generics given the * input method. * @param method The method * @return The name of the value class */ public static String getMapValueType(Method method) { Class valueType = getMapValueType(method.getReturnType(), method.getGenericReturnType()); return (valueType != null ? valueType.getName() : null); } /** * Convenience method to extract the value type of a map when using JDK1.5 generics given the * input field * @param type the field type * @param genericType the generic type * @return The name of the value class */ public static Class getMapValueType(Class type, Type genericType) { if (!Map.class.isAssignableFrom(type)) { return null; } return getClassForGenericType(genericType, 1); } /** * Convenience accessor for the modifiers of a field in a class. * @param clr ClassLoader resolver * @param className Name of the class * @param fieldName Name of the field * @return The modifiers */ public static int getModifiersForFieldOfClass(ClassLoaderResolver clr, String className, String fieldName) { try { Class cls = clr.classForName(className); Field fld = cls.getDeclaredField(fieldName); return fld.getModifiers(); } catch (Exception e) { // Class or field not found } return -1; } /** * Method to return whether the passes type is a "reference" type. * A "reference" type is either an interface or an Object, so can be used as a reference to * a persistable object. * @param cls The type * @return Whether it is a reference type */ public static boolean isReferenceType(Class cls) { if (cls == null) { return false; } return cls.isInterface() || cls.getName().equals("java.lang.Object"); } /** * Convenience method to throw a NucleusUserException if the specified class is not loadable * from the ClassLoaderResolver. * @param clr ClassLoader resolver * @param className Name of the class * @param jarName Name of the jar containing the class * @throws NucleusUserException if the class is not found */ public static void assertClassForJarExistsInClasspath(ClassLoaderResolver clr, String className, String jarName) { try { Class cls = clr.classForName(className); if (cls == null) { throw new NucleusUserException(Localiser.msg("001006", className, jarName)); } } catch (Error err) { throw new NucleusUserException(Localiser.msg("001006", className, jarName)); } catch (ClassNotResolvedException cnre) { throw new NucleusUserException(Localiser.msg("001006", className, jarName)); } } /** * Convenience method to return if a String array contains a value. * @param array The String array * @param value The value * @return Whether it is contained */ public static boolean stringArrayContainsValue(String[] array, String value) { if (value == null || array == null) { return false; } for (int i=0;iflags that are in the state passed as argument. * @param flags Array of flags (true or false) * @param state The state to search (true or false) * @return The settings of the flags */ public static int[] getFlagsSetTo(boolean[] flags, boolean state) { int[] temp = new int[flags.length]; int j = 0; for (int i = 0; i < flags.length; i++) { if (flags[i] == state) { temp[j++] = i; } } if (j != 0) { int[] fieldNumbers = new int[j]; System.arraycopy(temp, 0, fieldNumbers, 0, j); return fieldNumbers; } return null; } /** * Returns an array of integers containing the indices of all elements in * flags whose index occurs in indices and whose value is state. * @param flags the boolean array * @param indices The positions in the array * @param state The state that we want to match * @return The positions of flags that are set to this state */ public static int[] getFlagsSetTo(boolean[] flags, int[] indices, boolean state) { if (indices == null) { return null; } int[] temp = new int[indices.length]; int j = 0; for (int i = 0; i < indices.length; i++) { if (flags[indices[i]] == state) { temp[j++] = indices[i]; } } if (j != 0) { int[] fieldNumbers = new int[j]; System.arraycopy(temp, 0, fieldNumbers, 0, j); return fieldNumbers; } return null; } /** * Convenience method to get the value of a bit from an int when we are storing (up to 32) boolean in an int * for memory utilisation purposes. * @param bits The int storing the bits * @param bitIndex The index of this bit * @return The value of this bit (as a boolean) */ public static boolean getBitFromInt(int bits, int bitIndex) { if (bitIndex < 0 || bitIndex > 31) { throw new IllegalArgumentException(); } return (bits & (1 << bitIndex)) != 0; } /** * Convenience method to set a boolean as a bit in the specified int, for memory utilisation purposes. * @param bits The int storing the bits * @param bitIndex The index of this bit * @param flag The boolean value to store * @return The int with this bit set */ public static int setBitInInt(int bits, int bitIndex, boolean flag) { if (bitIndex < 0 || bitIndex > 31) { throw new IllegalArgumentException(); } int mask = 1 << bitIndex; return (bits & ~mask) | (flag ? mask : 0); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy