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

io.github.dmlloyd.classfile.impl.ClassImpl Maven / Gradle / Ivy

/*
 * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package io.github.dmlloyd.classfile.impl;

import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

import io.github.dmlloyd.classfile.constantpool.ClassEntry;
import io.github.dmlloyd.classfile.extras.reflect.AccessFlag;
import io.github.dmlloyd.classfile.AccessFlags;
import io.github.dmlloyd.classfile.Attribute;
import io.github.dmlloyd.classfile.Attributes;
import io.github.dmlloyd.classfile.ClassElement;
import io.github.dmlloyd.classfile.ClassModel;
import io.github.dmlloyd.classfile.ClassFile;
import io.github.dmlloyd.classfile.ClassFileVersion;
import io.github.dmlloyd.classfile.CustomAttribute;
import io.github.dmlloyd.classfile.constantpool.ConstantPool;
import io.github.dmlloyd.classfile.FieldModel;
import io.github.dmlloyd.classfile.Interfaces;
import io.github.dmlloyd.classfile.MethodModel;
import io.github.dmlloyd.classfile.Superclass;
import io.github.dmlloyd.classfile.attribute.InnerClassesAttribute;
import io.github.dmlloyd.classfile.attribute.ModuleAttribute;
import io.github.dmlloyd.classfile.attribute.ModuleHashesAttribute;
import io.github.dmlloyd.classfile.attribute.ModuleMainClassAttribute;
import io.github.dmlloyd.classfile.attribute.ModulePackagesAttribute;
import io.github.dmlloyd.classfile.attribute.ModuleResolutionAttribute;
import io.github.dmlloyd.classfile.attribute.ModuleTargetAttribute;
import io.github.dmlloyd.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
import io.github.dmlloyd.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
import io.github.dmlloyd.classfile.attribute.SourceDebugExtensionAttribute;
import io.github.dmlloyd.classfile.attribute.SourceFileAttribute;

public final class ClassImpl
        extends AbstractElement
        implements ClassModel {

    final ClassReaderImpl reader;
    private final int attributesPos;
    private final List methods;
    private final List fields;
    private List> attributes;
    private List interfaces;

    public ClassImpl(byte[] cfbytes, ClassFileImpl context) {
        this.reader = new ClassReaderImpl(cfbytes, context);
        int p = reader.interfacesPos;
        int icnt = reader.readU2(p);
        p += 2 + icnt * 2;
        int fcnt = reader.readU2(p);
        FieldImpl[] fields = new FieldImpl[fcnt];
        p += 2;
        for (int i = 0; i < fcnt; ++i) {
            int startPos = p;
            int attrStart = p + 6;
            p = reader.skipAttributeHolder(attrStart);
            fields[i] = new FieldImpl(reader, startPos, p, attrStart);
        }
        this.fields = List.of(fields);
        int mcnt = reader.readU2(p);
        MethodImpl[] methods = new MethodImpl[mcnt];
        p += 2;
        for (int i = 0; i < mcnt; ++i) {
            int startPos = p;
            int attrStart = p + 6;
            p = reader.skipAttributeHolder(attrStart);
            methods[i] = new MethodImpl(reader, startPos, p, attrStart);
        }
        this.methods = List.of(methods);
        this.attributesPos = p;
        reader.setContainedClass(this);
    }

    public int classfileLength() {
        return reader.classfileLength();
    }

    @Override
    public AccessFlags flags() {
        return new AccessFlagsImpl(AccessFlag.Location.CLASS, reader.flags());
    }

    @Override
    public int majorVersion() {
        return reader.readU2(6);
    }

    @Override
    public int minorVersion() {
        return reader.readU2(4);
    }

    @Override
    public ConstantPool constantPool() {
        return reader;
    }

    @Override
    public ClassEntry thisClass() {
        return reader.thisClassEntry();
    }

    @Override
    public Optional superclass() {
        return reader.superclassEntry();
    }

    @Override
    public List interfaces() {
        if (interfaces == null) {
            int pos = reader.thisClassPos() + 4;
            int cnt = reader.readU2(pos);
            pos += 2;
            var arr = new ClassEntry[cnt];
            for (int i = 0; i < cnt; ++i) {
                arr[i] = reader.readEntry(pos, ClassEntry.class);
                pos += 2;
            }
            this.interfaces = List.of(arr);
        }
        return interfaces;
    }

    @Override
    public List> attributes() {
        if (attributes == null) {
            attributes = BoundAttribute.readAttributes(this, reader, attributesPos, reader.customAttributes());
        }
        return attributes;
    }

    // ClassModel

    @Override
    public void forEach(Consumer consumer) {
        consumer.accept(flags());
        consumer.accept(ClassFileVersion.of(majorVersion(), minorVersion()));
        superclass().ifPresent(new Consumer() {
            @Override
            public void accept(ClassEntry entry) {
                consumer.accept(Superclass.of(entry));
            }
        });
        consumer.accept(Interfaces.of(interfaces()));
        fields().forEach(consumer);
        methods().forEach(consumer);
        for (Attribute attr : attributes()) {
            if (attr instanceof ClassElement e)
                consumer.accept(e);
        }
    }

    @Override
    public List fields() {
        return fields;
    }

    @Override
    public List methods() {
        return methods;
    }

    @Override
    public boolean isModuleInfo() {
        AccessFlags flags = flags();
        // move to where?
        return flags.has(AccessFlag.MODULE)
               && majorVersion() >= ClassFile.JAVA_9_VERSION
               && thisClass().asInternalName().equals("module-info")
               && (superclass().isEmpty())
               && interfaces().isEmpty()
               && fields().isEmpty()
               && methods().isEmpty()
               && verifyModuleAttributes();
    }

    @Override
    public String toString() {
        return String.format("ClassModel[thisClass=%s, flags=%d]", thisClass().name().stringValue(), flags().flagsMask());
    }

    private boolean verifyModuleAttributes() {
        if (findAttribute(Attributes.module()).isEmpty())
            return false;

        return attributes().stream().allMatch(a ->
                a instanceof ModuleAttribute
             || a instanceof ModulePackagesAttribute
             || a instanceof ModuleHashesAttribute
             || a instanceof ModuleMainClassAttribute
             || a instanceof ModuleResolutionAttribute
             || a instanceof ModuleTargetAttribute
             || a instanceof InnerClassesAttribute
             || a instanceof SourceFileAttribute
             || a instanceof SourceDebugExtensionAttribute
             || a instanceof RuntimeVisibleAnnotationsAttribute
             || a instanceof RuntimeInvisibleAnnotationsAttribute
             || a instanceof CustomAttribute);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy