org.nuiton.jaxx.compiler.reflect.resolvers.ClassDescriptorResolverFromJavaClass Maven / Gradle / Ivy
The newest version!
/*
* #%L
* JAXX :: Compiler
* %%
* Copyright (C) 2008 - 2024 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.resolvers;
import com.google.common.collect.ImmutableSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptor;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptorHelper;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptorResolver;
import org.nuiton.jaxx.compiler.reflect.FieldDescriptor;
import org.nuiton.jaxx.compiler.reflect.MethodDescriptor;
import org.nuiton.jaxx.runtime.JAXXObjectDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.TypeVariable;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
* To obtain a class descriptor from a java source file.
*
* @author Tony Chemit - [email protected]
* @since 2.0.2
*/
public class ClassDescriptorResolverFromJavaClass extends ClassDescriptorResolver {
/**
* Logger
*/
private static final Logger log =
LogManager.getLogger(ClassDescriptorResolverFromJavaClass.class);
public ClassDescriptorResolverFromJavaClass() {
super(ClassDescriptorHelper.ResolverType.JAVA_CLASS);
}
@Override
public ClassDescriptor resolveDescriptor(String className,
URL source) throws ClassNotFoundException {
if (log.isDebugEnabled()) {
log.debug("for source " + className);
}
Class> javaClass =
ClassDescriptorHelper.getClass(className, getClassLoader());
String name = javaClass.getName();
Package p = javaClass.getPackage();
String packageName = p != null ? p.getName() : null;
Class> superclass = javaClass.getSuperclass();
String superclassName = superclass != null ? superclass.getName() : null;
Class>[] interfaces = javaClass.getInterfaces();
String[] interfaceNames = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
interfaceNames[i] = interfaces[i].getName();
}
boolean isInterface = javaClass.isInterface();
boolean isArray = javaClass.isArray();
String componentTypeName = isArray ? javaClass.getComponentType().getName() : null;
ClassLoader classLoader = javaClass.getClassLoader();
Constructor>[] javaConstructors = javaClass.getConstructors();
MethodDescriptor[] constructors = new MethodDescriptor[javaConstructors.length];
for (int i = 0; i < constructors.length; i++) {
constructors[i] = ClassDescriptorHelper.createMethodDescriptor(
javaConstructors[i],
javaClass.getClassLoader()
);
}
Method[] javaMethods = javaClass.getMethods();
MethodDescriptor[] methods = new MethodDescriptor[javaMethods.length];
for (int i = 0; i < methods.length; i++) {
methods[i] = ClassDescriptorHelper.createMethodDescriptor(
javaMethods[i],
javaClass.getClassLoader()
);
}
ImmutableSet.Builder fieldsBuilder = ImmutableSet.builder();
ImmutableSet.Builder declaredFieldsBuilder = ImmutableSet.builder();
Set> pathFromRoot = pathFromRoot(javaClass);
for (Class> aClass : pathFromRoot) {
fieldsBuilder.addAll(Arrays.asList(aClass.getFields()));
declaredFieldsBuilder.addAll(Arrays.asList(aClass.getDeclaredFields()));
}
ImmutableSet javaFields = fieldsBuilder.build();
FieldDescriptor[] fields = new FieldDescriptor[javaFields.size()];
int i = 0;
for (Field javaField : javaFields) {
fields[i++] = ClassDescriptorHelper.createFieldDescriptor(javaField, javaClass.getClassLoader());
}
ImmutableSet javaDeclaredFields = declaredFieldsBuilder.build();
FieldDescriptor[] declaredFields = new FieldDescriptor[javaDeclaredFields.size()];
i = 0;
for (Field javaDeclaredField : javaDeclaredFields) {
declaredFields[i++] = ClassDescriptorHelper.createFieldDescriptor(javaDeclaredField, javaClass.getClassLoader());
}
JAXXObjectDescriptor jaxxObjectDescriptor =
ClassDescriptorHelper.getJAXXObjectDescriptor(javaClass);
Map typeParameters = new LinkedHashMap<>();
for (TypeVariable extends Class>> typeParameter : javaClass.getTypeParameters()) {
typeParameters.put(typeParameter.getName(), typeParameter.getBounds()[0].getTypeName());
}
return new JavaClassClassDescriptor(
javaClass,
typeParameters,
name,
packageName,
superclassName,
interfaceNames,
isInterface,
isArray,
componentTypeName,
jaxxObjectDescriptor,
classLoader,
constructors,
methods,
fields,
declaredFields
);
}
private Set> pathFromRoot(Class> type) {
List> result = new LinkedList<>();
while (type != null && type != Object.class) {
result.add(type);
type = type.getSuperclass();
}
Collections.reverse(result);
return new LinkedHashSet<>(result);
}
private class JavaClassClassDescriptor extends ClassDescriptor {
private final Class> javaClass;
private final Map typeParameters;
public JavaClassClassDescriptor(
Class> javaClass,
Map typeParameters, String name,
String packageName,
String superclassName,
String[] interfaceNames,
boolean anInterface,
boolean array,
String componentTypeName,
JAXXObjectDescriptor jaxxObjectDescriptor,
ClassLoader classLoader,
MethodDescriptor[] constructors,
MethodDescriptor[] methods,
FieldDescriptor[] fields,
FieldDescriptor[] declaredFields
) {
super(
ClassDescriptorResolverFromJavaClass.this.getResolverType(),
name,
packageName,
superclassName,
interfaceNames,
anInterface,
array,
componentTypeName,
jaxxObjectDescriptor,
classLoader,
constructors,
methods,
fields,
declaredFields
);
this.javaClass = javaClass;
this.typeParameters = typeParameters;
}
@Override
public Map getTypeParameters() {
return typeParameters;
}
// @Override
// public FieldDescriptor getDeclaredFieldDescriptor(String name) throws NoSuchFieldException {
// return ClassDescriptorHelper.createFieldDescriptor(javaClass.getDeclaredField(name),
// javaClass.getClassLoader()
// );
// }
@Override
public MethodDescriptor getDeclaredMethodDescriptor(String name,
ClassDescriptor... parameterTypes) throws NoSuchMethodException {
try {
Class>[] parameterTypeClasses = new Class[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
parameterTypeClasses[i] = Class.forName(parameterTypes[i].getName());
}
return ClassDescriptorHelper.createMethodDescriptor(javaClass.getDeclaredMethod(name, parameterTypeClasses), javaClass.getClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public Optional tryToGetDeclaredMethodDescriptor(String name, ClassDescriptor... parameterTypes) {
try {
Class>[] parameterTypeClasses = new Class[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
parameterTypeClasses[i] = Class.forName(parameterTypes[i].getName());
}
return Optional.of(ClassDescriptorHelper.createMethodDescriptor(javaClass.getDeclaredMethod(name, parameterTypeClasses), javaClass.getClassLoader()));
} catch (Exception e) {
return Optional.empty();
}
}
}
}