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

com.cryptomorin.xseries.reflection.jvm.classes.DynamicClassHandle Maven / Gradle / Ivy

There is a newer version: 12.1.0
Show newest version
package com.cryptomorin.xseries.reflection.jvm.classes;

import com.cryptomorin.xseries.reflection.ReflectiveNamespace;
import com.cryptomorin.xseries.reflection.XReflection;
import com.google.common.base.Strings;
import org.intellij.lang.annotations.Pattern;

import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * @see StaticClassHandle
 */
public class DynamicClassHandle extends ClassHandle {
    protected ClassHandle parent;
    protected String packageName;
    protected final Set classNames = new HashSet<>(5);
    protected int array;

    public DynamicClassHandle(ReflectiveNamespace namespace) {
        super(namespace);
    }

    public DynamicClassHandle inPackage(@Pattern(PackageHandle.JAVA_PACKAGE_PATTERN) @Nonnull String packageName) {
        Objects.requireNonNull(packageName, "Null package name");
        this.packageName = packageName;
        return this;
    }

    public DynamicClassHandle inPackage(@Nonnull PackageHandle packageHandle) {
        // noinspection PatternValidation
        return inPackage(packageHandle, "");
    }

    public DynamicClassHandle inPackage(@Nonnull PackageHandle packageHandle,
                                        @Pattern(PackageHandle.JAVA_PACKAGE_PATTERN) @Nonnull String packageName) {
        Objects.requireNonNull(packageHandle, "Null package handle type");
        Objects.requireNonNull(packageName, "Null package handle name");
        if (parent != null)
            throw new IllegalStateException("Cannot change package of an inner class: " + packageHandle + " -> " + packageName);
        this.packageName = packageHandle.getPackage(packageName);
        return this;
    }

    public DynamicClassHandle named(@Pattern(PackageHandle.JAVA_IDENTIFIER_PATTERN) @Nonnull String... classNames) {
        Objects.requireNonNull(classNames);
        for (String className : this.classNames) {
            Objects.requireNonNull(className, () -> "Cannot add null class name from: " + Arrays.toString(classNames) + " to " + this);
        }
        this.classNames.addAll(Arrays.asList(classNames));
        return this;
    }

    public String[] reflectClassNames() {
        if (this.parent == null) Objects.requireNonNull(packageName, "Package name is null");
        String[] classNames = new String[this.classNames.size()];
        Class parent = this.parent == null ? null : XReflection.of(this.parent.unreflect()).asArray(0).unreflect();

        int i = 0;
        for (String className : this.classNames) {
            @SuppressWarnings("NonConstantStringShouldBeStringBuffer")
            String clazz;
            if (parent == null) clazz = packageName + '.' + className;
            else clazz = parent.getName() + '$' + className;

            if (array != 0) clazz = Strings.repeat("[", array) + 'L' + clazz + ';';
            classNames[i++] = clazz;
        }

        return classNames;
    }

    @Override
    public DynamicClassHandle clone() {
        DynamicClassHandle handle = new DynamicClassHandle(namespace);
        handle.array = this.array;
        handle.parent = this.parent;
        handle.packageName = this.packageName;
        handle.classNames.addAll(this.classNames);
        return handle;
    }

    @Override
    public Class reflect() throws ClassNotFoundException {
        String[] classNames = reflectClassNames();
        if (classNames.length == 0) throw new IllegalStateException("No class name specified for " + this);

        ClassNotFoundException errors = null;
        for (String className : classNames) {
            try {
                return Class.forName(className);
            } catch (ClassNotFoundException ex) {
                if (errors == null) errors = new ClassNotFoundException("None of the classes were found");
                errors.addSuppressed(ex);
            }
        }

        throw XReflection.relativizeSuppressedExceptions(errors);
    }

    @Override
    public DynamicClassHandle asArray(int dimension) {
        if (dimension < 0) throw new IllegalArgumentException("Array dimension cannot be negative: " + dimension);
        this.array = dimension;
        return this;
    }

    @Override
    public boolean isArray() {
        return this.array > 0;
    }

    @Override
    public Set getPossibleNames() {
        return classNames;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy