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

jaxx.compiler.reflect.ClassDescriptorHelper Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-6
Show newest version
/*
 * #%L
 * JAXX :: Compiler
 * *
 * $Id: ClassDescriptorHelper.java 2225 2011-02-19 20:15:00Z tchemit $
 * $HeadURL: http://svn.nuiton.org/svn/jaxx/tags/jaxx-2.5.27/jaxx-compiler/src/main/java/jaxx/compiler/reflect/ClassDescriptorHelper.java $
 * %%
 * Copyright (C) 2008 - 2010 CodeLutin
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

package jaxx.compiler.reflect;

import jaxx.compiler.CompilerException;
import jaxx.compiler.JAXXCompiler;
import jaxx.compiler.JAXXCompilerFile;
import jaxx.compiler.JAXXEngine;
import jaxx.compiler.JAXXFactory;
import jaxx.compiler.reflect.resolvers.ClassDescriptorResolverFromJavaClass;
import jaxx.compiler.reflect.resolvers.ClassDescriptorResolverFromJavaFile;
import jaxx.compiler.reflect.resolvers.ClassDescriptorResolverFromJaxxFile;
import jaxx.runtime.JAXXObject;
import jaxx.runtime.JAXXObjectDescriptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

/**
 * Mirrors the class java.lang.ClassLoader.  JAXX uses ClassDescriptor instead of Class
 * almost everywhere so that it can handle circular dependencies (there can't be a Class object for an uncompiled
 * JAXX or Java source file, and a compiler must be allow references to symbols in uncompiled source files in order to handle
 * circular dependencies).
 * 

* Note : Was previously {@code ClassDescriptorLoader}. * * @author tchemit * @since 2.0.2 */ public class ClassDescriptorHelper { /** Logger */ private static final Log log = LogFactory.getLog(ClassDescriptorHelper.class); /** * Constants to define who load a {@link ClassDescriptor}. *

* This will be usefull in some case (for consturctor for example when some * descriptors are not fully loaded... * * @since 2.4 */ public enum ResolverType { JAVA_CLASS, JAVA_FILE, JAXX_FILE } private static boolean SHOW_LOADING = log.isDebugEnabled(); private static Map descriptors = new HashMap(); private static Map descriptorResolvers; protected static Map getDescriptorResolvers() { if (descriptorResolvers == null) { descriptorResolvers = new EnumMap(ResolverType.class); descriptorResolvers.put(ResolverType.JAVA_CLASS, new ClassDescriptorResolverFromJavaClass()); descriptorResolvers.put(ResolverType.JAVA_FILE, new ClassDescriptorResolverFromJavaFile()); descriptorResolvers.put(ResolverType.JAXX_FILE, new ClassDescriptorResolverFromJaxxFile()); } return descriptorResolvers; } private ClassDescriptorHelper() { // on instance } public static boolean isAssignableFrom(ClassDescriptor classDescriptor, Class awareClass) throws ClassNotFoundException { ClassDescriptor awareDescriptor = getClassDescriptor(awareClass); boolean result = awareDescriptor.isAssignableFrom(classDescriptor); return result; } public static ClassDescriptor getClassDescriptor(String className) throws ClassNotFoundException { ClassDescriptor descriptor = getClassDescriptor(className, Thread.currentThread().getContextClassLoader()); return descriptor; } public static ClassDescriptor getClassDescriptor(Class javaClass) { try { return getClassDescriptor(javaClass.getName(), javaClass.getClassLoader()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } public static URL getURL(ClassLoader classLoader, String className, String clasifier) { String relativePath = className.replaceAll("\\.", "/"); String path = relativePath + "." + clasifier; if (log.isDebugEnabled()) { log.debug("Path to search : " + path); } URL url = classLoader.getResource(path); return url; } public static ClassDescriptor getClassDescriptor( String className, ClassLoader classLoader) throws ClassNotFoundException { if (classLoader == null) { classLoader = ClassDescriptorHelper.class.getClassLoader(); } ClassDescriptor result = descriptors.get(className); if (result != null) { // found in cache if (log.isTraceEnabled()) { log.trace("resolved " + result + " from cache."); } return result; } JAXXEngine engine = JAXXFactory.isEngineRegistred() ? JAXXFactory.getEngine() : null; String relativePathPattern = ".*";// + className + ".*"; // used to ensure that the located resource has the right character cases if (engine != null) { JAXXCompilerFile file = engine.getJAXXCompilerFile(className); if (file != null) { // use the symbole table of this jaxx file on computation if (SHOW_LOADING) { log.info("from JAXXFile " + file.getJaxxFile()); } result = getClassDescriptor0( ResolverType.JAXX_FILE, className, file.getJAXXFileURL(), classLoader ); if (log.isDebugEnabled()) { log.debug("[" + className + "] loaded"); } return result; } } // the class is not in this compile set, try to have it from java // sources or classes. // find the most recently updated source for the class -- Java source, JAXX source, or compiled class file long javaLastModified = -1; URL javaFile = getURL(classLoader, className, "java"); if (javaFile != null && javaFile.toString().startsWith("file:") && javaFile.toString().matches(relativePathPattern)) { javaLastModified = JAXXCompiler.URLtoFile(javaFile).lastModified(); if (log.isTraceEnabled()) { log.trace("[" + className + "] javaFile lastModified " + javaLastModified); } } long classLastModified = -1; URL classFile = getURL(classLoader, className, "class"); if (classFile != null && classFile.toString().startsWith("file:") && classFile.toString().matches(relativePathPattern)) { classLastModified = JAXXCompiler.URLtoFile(classFile).lastModified(); if (log.isTraceEnabled()) { log.trace("[" + className + "] class lastModified " + classLastModified); } } // there is a java source and is the last modified if (javaLastModified != -1 && javaLastModified > classLastModified) { // java file exist and it is the last modified file, so use it if (SHOW_LOADING) { log.info("from JavaFile " + javaFile); } result = getClassDescriptor0( ResolverType.JAVA_FILE, className, javaFile, classLoader ); if (log.isDebugEnabled()) { log.debug("[" + className + "] loaded"); } return result; } // use the class ... if (SHOW_LOADING) { log.info("from class " + className); } result = getClassDescriptor0( ResolverType.JAVA_CLASS, className, classFile, classLoader ); if (log.isDebugEnabled()) { log.debug("[" + className + "] loaded"); } if (result != null) { return result; } // can NOT come here, means could not find result... throw new IllegalStateException( "Can not find descriptor for " + className); } protected static ClassDescriptor getClassDescriptor0( ResolverType resolverType, String className, URL source, ClassLoader classLoader) throws ClassNotFoundException { if (log.isDebugEnabled()) { log.debug("Loading class descriptor for [" + className + "] with " + resolverType); } Map resolvers = getDescriptorResolvers(); ClassDescriptorResolver resolver = resolvers.get(resolverType); resolver.setClassLoader(classLoader); ClassDescriptor result = resolver.resolvDescriptor(className, source); if (result != null) { descriptors.put(className, result); } return result; } public static Class getPrimitiveBoxedClass(String className) { if (className.equals("boolean")) { return Boolean.class; } if (className.equals("byte")) { return Byte.class; } if (className.equals("short")) { return Short.class; } if (className.equals("int")) { return Integer.class; } if (className.equals("long")) { return Long.class; } if (className.equals("float")) { return Float.class; } if (className.equals("double")) { return Double.class; } if (className.equals("char")) { return Character.class; } if (className.equals("void")) { return Void.class; } return null; } public static Class getPrimitiveClass( String className) throws ClassNotFoundException { if (className.equals("boolean")) { return boolean.class; } if (className.equals("byte")) { return byte.class; } if (className.equals("short")) { return short.class; } if (className.equals("int")) { return int.class; } if (className.equals("long")) { return long.class; } if (className.equals("float")) { return float.class; } if (className.equals("double")) { return double.class; } if (className.equals("char")) { return char.class; } if (className.equals("void")) { return void.class; } // detect arrays int arrayCount = 0; while (className.endsWith("[]")) { arrayCount++; className = className.substring(0, className.length() - 2); } Class klass; if (arrayCount > 0) { klass = getPrimitiveClass(className); if (klass == null) { // none primitive array return null; } // must take the boxed class, other it does not works // to make a Class.forName("[Lchar;"); but works // with Class.forName("[LCharacter;"); ... klass = getPrimitiveBoxedClass(className); className = klass.getName(); className = "L" + className + ";"; while (arrayCount > 0) { className = "[" + className; arrayCount--; } //System.out.println("primitive array class "+className); return Class.forName(className); } return null; } public static Class getClass(String className, ClassLoader classLoader) throws ClassNotFoundException { Class klass = getPrimitiveClass(className); if (klass != null) { return klass; } // try an array of none primitive classes int arrayCount = 0; while (className.endsWith("[]")) { arrayCount++; className = className.substring(0, className.length() - 2); } if (arrayCount > 0) { className = "L" + className + ";"; while (arrayCount > 0) { className = "[" + className; arrayCount--; } } try { return classLoader != null ? Class.forName(className, true, classLoader) : Class.forName(className); } catch (ClassNotFoundException e) { // perharps we are in a inner class ? int dotIndex = className.lastIndexOf("."); if (dotIndex > -1) { String parentFQN = className.substring(0, dotIndex); String simpleName = className.substring(dotIndex + 1); try { Class parentClass = classLoader != null ? Class.forName(parentFQN, true, classLoader) : Class.forName(parentFQN); for (Class innerClass : parentClass.getClasses()) { if (simpleName.equals(innerClass.getSimpleName())) { return innerClass; } } } catch (ClassNotFoundException e1) { // no super class,so let the first exception throw... } } throw e; } catch (NoClassDefFoundError e) { throw new ClassNotFoundException(e.toString()); } } // private static MethodDescriptor createMethodDescriptor(Method javaMethod, // ClassLoader classLoader) { // String methodName = javaMethod.getName(); // int modifiers = javaMethod.getModifiers(); // String returnType = javaMethod.getReturnType().getName(); // Class[] javaParameters = javaMethod.getParameterTypes(); // String[] parameters = new String[javaParameters.length]; // for (int i = 0; i < parameters.length; i++) { // parameters[i] = javaParameters[i].getName(); // } // return new MethodDescriptor(methodName, modifiers, returnType, parameters, classLoader); // } // // private static FieldDescriptor createFieldDescriptor(Field javaField, // ClassLoader classLoader) { // String fieldName = javaField.getName(); // int modifiers = javaField.getModifiers(); // String type = javaField.getType().getName(); // return new FieldDescriptor(fieldName, modifiers, type, classLoader); // } // // private static JAXXObjectDescriptor getJAXXObjectDescriptor(Class jaxxClass) { // if (!JAXXObject.class.isAssignableFrom(jaxxClass) || // JAXXObject.class.equals(jaxxClass)) { // return null; // } // try { // Method getJAXXObjectDescriptor = jaxxClass.getMethod("$getJAXXObjectDescriptor"); // return (JAXXObjectDescriptor) getJAXXObjectDescriptor.invoke(null); // } catch (NoSuchMethodException e) { // throw new CompilerException("Expected JAXXObject " + jaxxClass.getName() + " to have a static method named $getJAXXObjectDescriptor"); // } catch (IllegalAccessException e) { // throw new CompilerException("Expected JAXXObject " + jaxxClass.getName() + "'s $getJAXXObjectDescriptor method to be public"); // } catch (InvocationTargetException e) { // throw new RuntimeException(e); // } // } public static void checkSupportClass(Class handlerClass, ClassDescriptor beanClass, Class... tagClasses) { for (Class tagClass : tagClasses) { if (getClassDescriptor(tagClass).isAssignableFrom(beanClass)) { return; } } throw new IllegalArgumentException(handlerClass.getName() + " does not support the class " + beanClass.getName()); } public static void reset() { descriptors.clear(); } public static MethodDescriptor createMethodDescriptor(Method javaMethod, ClassLoader classLoader) { String methodName = javaMethod.getName(); int modifiers = javaMethod.getModifiers(); String returnType = javaMethod.getReturnType().getName(); Class[] javaParameters = javaMethod.getParameterTypes(); String[] parameters = new String[javaParameters.length]; for (int i = 0; i < parameters.length; i++) { parameters[i] = javaParameters[i].getName(); } return new MethodDescriptor(methodName, modifiers, returnType, parameters, classLoader ); } public static MethodDescriptor createMethodDescriptor(Constructor javaMethod, ClassLoader classLoader) { String methodName = javaMethod.getName(); int modifiers = javaMethod.getModifiers(); String returnType = null; Class[] javaParameters = javaMethod.getParameterTypes(); String[] parameters = new String[javaParameters.length]; for (int i = 0; i < parameters.length; i++) { parameters[i] = javaParameters[i].getName(); } return new MethodDescriptor(methodName, modifiers, returnType, parameters, classLoader ); } public static FieldDescriptor createFieldDescriptor(Field javaField, ClassLoader classLoader) { String fieldName = javaField.getName(); int modifiers = javaField.getModifiers(); String type = javaField.getType().getName(); return new FieldDescriptor(fieldName, modifiers, type, classLoader); } public static JAXXObjectDescriptor getJAXXObjectDescriptor(Class jaxxClass) { if (!JAXXObject.class.isAssignableFrom(jaxxClass) || JAXXObject.class.equals(jaxxClass)) { return null; } try { Method getJAXXObjectDescriptor = jaxxClass.getMethod("$getJAXXObjectDescriptor"); return (JAXXObjectDescriptor) getJAXXObjectDescriptor.invoke(null); } catch (NoSuchMethodException e) { throw new CompilerException("Expected JAXXObject " + jaxxClass.getName() + " to have a static method named $getJAXXObjectDescriptor"); } catch (IllegalAccessException e) { throw new CompilerException("Expected JAXXObject " + jaxxClass.getName() + "'s $getJAXXObjectDescriptor method to be public"); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } public static void setShowLoading(boolean b) { SHOW_LOADING = b; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy