Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* #%L
* JAXX :: Compiler
* %%
* Copyright (C) 2008 - 2020 Code Lutin, Ultreia.io
* %%
* 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 org.nuiton.jaxx.compiler.reflect;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.nuiton.jaxx.compiler.CompilerException;
import org.nuiton.jaxx.compiler.JAXXCompiler;
import org.nuiton.jaxx.compiler.JAXXCompilerFile;
import org.nuiton.jaxx.compiler.JAXXEngine;
import org.nuiton.jaxx.compiler.JAXXFactory;
import org.nuiton.jaxx.compiler.reflect.resolvers.ClassDescriptorResolverFromJavaClass;
import org.nuiton.jaxx.compiler.reflect.resolvers.ClassDescriptorResolverFromJavaFile;
import org.nuiton.jaxx.compiler.reflect.resolvers.ClassDescriptorResolverFromJaxxFile;
import org.nuiton.jaxx.runtime.JAXXObject;
import org.nuiton.jaxx.runtime.JAXXObjectDescriptor;
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 Tony Chemit - [email protected]
* @since 2.0.2
*/
public class ClassDescriptorHelper {
/** Logger */
private static final Logger log = LogManager.getLogger(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 final 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) {
ClassDescriptor awareDescriptor = getClassDescriptor(awareClass);
return awareDescriptor.isAssignableFrom(classDescriptor);
}
public static ClassDescriptor getClassDescriptor(String className) throws ClassNotFoundException {
return getClassDescriptor(className,
Thread.currentThread().getContextClassLoader());
}
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);
}
return classLoader.getResource(path);
}
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.resolveDescriptor(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) ||
jaxxClass.isInterface()) {
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;
}
}