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

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);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy