org.nuiton.jaxx.compiler.reflect.ClassDescriptor 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;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuiton.jaxx.runtime.JAXXObjectDescriptor;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
/**
* Mirrors the class java.lang.Class
. 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).
*/
public abstract class ClassDescriptor {
/** Logger. */
private static final Logger log = LogManager.getLogger(ClassDescriptor.class);
public static final FieldDescriptor[] EMPTY_FIELD_DESCRIPTORS_ARRAY =
new FieldDescriptor[0];
private final String name;
private final String packageName;
private final String superclass;
private final String[] interfaces;
private final boolean isInterface;
private final boolean isArray;
private final String componentType;
private final JAXXObjectDescriptor jaxxObjectDescriptor;
private final ClassLoader classLoader;
private final MethodDescriptor[] constructorDescriptors;
private final MethodDescriptor[] methodDescriptors;
private final FieldDescriptor[] fieldDescriptors;
protected final FieldDescriptor[] declaredFieldDescriptors;
protected final ClassDescriptorHelper.ResolverType resolverType;
public abstract Optional tryToGetDeclaredMethodDescriptor(String name, ClassDescriptor... parameterTypes);
public abstract MethodDescriptor getDeclaredMethodDescriptor(
String name,
ClassDescriptor... parameterTypes) throws NoSuchMethodException;
// public abstract FieldDescriptor getDeclaredFieldDescriptor(
// String name) throws NoSuchFieldException;
public FieldDescriptor getDeclaredFieldDescriptor(String name) throws NoSuchFieldException {
for (FieldDescriptor descriptor : declaredFieldDescriptors) {
if (name.equals(descriptor.getName())) {
if (log.isDebugEnabled()) {
log.debug("Using a declared field descriptor [" + name +
"] for " + getName());
}
return descriptor;
}
}
throw new NoSuchFieldException(name);
}
protected ClassDescriptor(ClassDescriptorHelper.ResolverType resolverType,
String name,
String packageName,
String superclass,
String[] interfaces,
boolean isInterface,
boolean isArray,
String componentType,
JAXXObjectDescriptor jaxxObjectDescriptor,
ClassLoader classLoader,
MethodDescriptor[] constructorDescriptors,
MethodDescriptor[] methodDescriptors,
FieldDescriptor[] fieldDescriptors) {
this(
resolverType, name,
packageName,
superclass,
interfaces,
isInterface,
isArray,
componentType,
jaxxObjectDescriptor,
classLoader,
constructorDescriptors,
methodDescriptors,
fieldDescriptors,
null
);
}
protected ClassDescriptor(
ClassDescriptorHelper.ResolverType resolverType,
String name,
String packageName,
String superclass,
String[] interfaces,
boolean isInterface,
boolean isArray,
String componentType,
JAXXObjectDescriptor jaxxObjectDescriptor,
ClassLoader classLoader,
MethodDescriptor[] constructorDescriptors,
MethodDescriptor[] methodDescriptors,
FieldDescriptor[] fieldDescriptors,
FieldDescriptor[] declaredFieldDescriptors) {
this.resolverType = resolverType;
this.name = name;
this.packageName = packageName;
this.superclass = superclass;
this.interfaces = interfaces;
this.isInterface = isInterface;
this.isArray = isArray;
this.componentType = componentType;
this.jaxxObjectDescriptor = jaxxObjectDescriptor;
this.classLoader = classLoader;
this.constructorDescriptors = constructorDescriptors;
this.methodDescriptors = methodDescriptors;
this.fieldDescriptors = fieldDescriptors;
this.declaredFieldDescriptors = declaredFieldDescriptors;
}
public Map getTypeParameters() {
return Map.of();
}
public ClassDescriptorHelper.ResolverType getResolverType() {
return resolverType;
}
public String getName() {
return name;
}
public String getSimpleName() {
int dot = name.lastIndexOf(".");
return dot == -1 ? name : name.substring(dot + 1);
}
public String getPackageName() {
return packageName;
}
public ClassDescriptor getSuperclass() {
return getClassDescriptor(superclass);
}
public ClassDescriptor[] getInterfaces() {
ClassDescriptor[] result = new ClassDescriptor[interfaces.length];
for (int i = 0; i < result.length; i++) {
result[i] = getClassDescriptor(interfaces[i]);
}
return result;
}
public boolean isInterface() {
return isInterface;
}
public boolean isArray() {
return isArray;
}
public ClassDescriptor getComponentType() {
return getClassDescriptor(componentType);
}
public ClassLoader getClassLoader() {
return classLoader;
}
public MethodDescriptor[] getConstructorDescriptors() {
return constructorDescriptors;
}
public MethodDescriptor[] getMethodDescriptors() {
return methodDescriptors;
}
public MethodDescriptor getMethodDescriptor(String name,
ClassDescriptor... parameterTypes) throws NoSuchMethodException {
for (MethodDescriptor m : methodDescriptors) {
if (m.getName().equals(name) &&
m.getParameterTypes().length == parameterTypes.length &&
Arrays.equals(m.getParameterTypes(), parameterTypes)) {
return m;
}
}
throw new NoSuchMethodException(
"Could not find method " + name + "(" +
Arrays.asList(parameterTypes) + ") in " + getName());
}
public FieldDescriptor[] getFieldDescriptors() {
return fieldDescriptors;
}
public FieldDescriptor[] getDeclaredFieldDescriptors() {
return declaredFieldDescriptors == null ? EMPTY_FIELD_DESCRIPTORS_ARRAY : declaredFieldDescriptors;
}
public FieldDescriptor getFieldDescriptor(String name) throws NoSuchFieldException {
for (FieldDescriptor fieldDescriptor : fieldDescriptors) {
if (fieldDescriptor.getName().equals(name)) {
return fieldDescriptor;
}
}
throw new NoSuchFieldException(
"Could not find field " + name + " in " + getName());
}
public Optional tryToGetFieldDescriptor(String name) {
for (FieldDescriptor descriptor : fieldDescriptors) {
if (descriptor.getName().equals(name)) {
return Optional.of(descriptor);
}
}
if (declaredFieldDescriptors!=null) {
for (FieldDescriptor descriptor : declaredFieldDescriptors) {
if (descriptor.getName().equals(name)) {
return Optional.of(descriptor);
}
}
}
return Optional.empty();
}
public Optional tryToGetSetterMethodDescriptor(String name) {
String methodName = "set"+ StringUtils.capitalize(name);
for (MethodDescriptor descriptor : methodDescriptors) {
if (descriptor.getName().equals(methodName)) {
return Optional.of(descriptor);
}
}
return tryToGetDeclaredMethodDescriptor(name);
}
public JAXXObjectDescriptor getJAXXObjectDescriptor() {
return jaxxObjectDescriptor;
}
public boolean isAssignableFrom(ClassDescriptor descriptor) {
while (descriptor != null) {
if (equals(descriptor)) {
return true;
}
for (ClassDescriptor anInterface : descriptor.getInterfaces()) {
if (equals(anInterface) || isAssignableFrom(anInterface)) {
return true;
}
}
descriptor = descriptor.getSuperclass();
}
return false;
}
@Override
public String toString() {
return "ClassDescriptor[" + getName() + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ClassDescriptor)) return false;
ClassDescriptor that = (ClassDescriptor) o;
return name.equals(that.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
protected ClassDescriptor getClassDescriptor(String fqn) {
if (fqn == null) {
return null;
}
try {
return ClassDescriptorHelper.getClassDescriptor(
fqn,
getClassLoader()
);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}