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

io.github.dmlloyd.classfile.ClassBuilder 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;


import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

import io.github.dmlloyd.classfile.constantpool.ClassEntry;
import io.github.dmlloyd.classfile.constantpool.Utf8Entry;

import io.github.dmlloyd.classfile.impl.AccessFlagsImpl;
import io.github.dmlloyd.classfile.impl.ChainedClassBuilder;
import io.github.dmlloyd.classfile.impl.DirectClassBuilder;
import io.github.dmlloyd.classfile.impl.Util;
import io.github.dmlloyd.classfile.extras.reflect.AccessFlag;
import io.github.dmlloyd.classfile.attribute.CodeAttribute;
import io.github.dmlloyd.classfile.extras.PreviewFeature;

/**
 * A builder for classfiles.  Builders are not created directly; they are passed
 * to handlers by methods such as {@link ClassFile#build(ClassDesc, Consumer)}
 * or to class transforms.  The elements of a classfile can be specified
 * abstractly (by passing a {@link ClassElement} to {@link #with(ClassFileElement)})
 * or concretely by calling the various {@code withXxx} methods.
 *
 * @see ClassTransform
 *
 * @since 22
 */
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public sealed interface ClassBuilder
        extends ClassFileBuilder
        permits ChainedClassBuilder, DirectClassBuilder {

    /**
     * Sets the classfile version.
     * @param major the major version number
     * @param minor the minor version number
     * @return this builder
     */
    default ClassBuilder withVersion(int major, int minor) {
        return with(ClassFileVersion.of(major, minor));
    }

    /**
     * Sets the classfile access flags.
     * @param flags the access flags, as a bit mask
     * @return this builder
     */
    default ClassBuilder withFlags(int flags) {
        return with(new AccessFlagsImpl(AccessFlag.Location.CLASS, flags));
    }

    /**
     * Sets the classfile access flags.
     * @param flags the access flags
     * @return this builder
     */
    default ClassBuilder withFlags(AccessFlag... flags) {
        return with(new AccessFlagsImpl(AccessFlag.Location.CLASS, flags));
    }

    /**
     * Sets the superclass of this class.
     * @param superclassEntry the superclass
     * @return this builder
     */
    default ClassBuilder withSuperclass(ClassEntry superclassEntry) {
        return with(Superclass.of(superclassEntry));
    }

    /**
     * Sets the superclass of this class.
     * @param desc the superclass
     * @return this builder
     * @throws IllegalArgumentException if {@code desc} represents a primitive type
     */
    default ClassBuilder withSuperclass(ClassDesc desc) {
        return withSuperclass(constantPool().classEntry(desc));
    }

    /**
     * Sets the interfaces of this class.
     * @param interfaces the interfaces
     * @return this builder
     */
    default ClassBuilder withInterfaces(List interfaces) {
        return with(Interfaces.of(interfaces));
    }

    /**
     * Sets the interfaces of this class.
     * @param interfaces the interfaces
     * @return this builder
     */
    default ClassBuilder withInterfaces(ClassEntry... interfaces) {
        return withInterfaces(List.of(interfaces));
    }

    /**
     * Sets the interfaces of this class.
     * @param interfaces the interfaces
     * @return this builder
     */
    default ClassBuilder withInterfaceSymbols(List interfaces) {
        return withInterfaces(Util.entryList(interfaces));
    }

    /**
     * Sets the interfaces of this class.
     * @param interfaces the interfaces
     * @return this builder
     */
    default ClassBuilder withInterfaceSymbols(ClassDesc... interfaces) {
        // List view, since ref to interfaces is temporary
        return withInterfaceSymbols(Arrays.asList(interfaces));
    }

    /**
     * Adds a field.
     * @param name the name of the field
     * @param descriptor the field descriptor
     * @param handler handler which receives a {@link FieldBuilder} which can
     *                    further define the contents of the field
     * @return this builder
     */
    ClassBuilder withField(Utf8Entry name,
                           Utf8Entry descriptor,
                           Consumer handler);

    /**
     * Adds a field.
     * @param name the name of the field
     * @param descriptor the field descriptor
     * @param flags the access flags for this field
     * @return this builder
     */
    default ClassBuilder withField(Utf8Entry name,
                                   Utf8Entry descriptor,
                                   int flags) {
        return withField(name, descriptor, Util.buildingFlags(flags));
    }

    /**
     * Adds a field.
     * @param name the name of the field
     * @param descriptor the field descriptor
     * @param handler handler which receives a {@link FieldBuilder} which can
     *                    further define the contents of the field
     * @return this builder
     */
    default ClassBuilder withField(String name,
                                   ClassDesc descriptor,
                                   Consumer handler) {
        return withField(constantPool().utf8Entry(name),
                         constantPool().utf8Entry(descriptor),
                         handler);
    }

    /**
     * Adds a field.
     * @param name the name of the field
     * @param descriptor the field descriptor
     * @param flags the access flags for this field
     * @return this builder
     */
    default ClassBuilder withField(String name,
                                   ClassDesc descriptor,
                                   int flags) {
        return withField(name, descriptor, Util.buildingFlags(flags));
    }

    /**
     * Adds a field by transforming a field from another class.
     *
     * @implNote
     * 

This method behaves as if: * {@snippet lang=java : * withField(field.fieldName(), field.fieldType(), * b -> b.transformField(field, transform)); * } * * @param field the field to be transformed * @param transform the transform to apply to the field * @return this builder */ ClassBuilder transformField(FieldModel field, FieldTransform transform); /** * Adds a method. * @param name the name of the method * @param descriptor the method descriptor * @param methodFlags the access flags * @param handler handler which receives a {@link MethodBuilder} which can * further define the contents of the method * @return this builder */ ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int methodFlags, Consumer handler); /** * Adds a method, with only a {@code Code} attribute. * * @param name the name of the method * @param descriptor the method descriptor * @param methodFlags the access flags * @param handler handler which receives a {@link CodeBuilder} which can * define the contents of the method body * @return this builder */ default ClassBuilder withMethodBody(Utf8Entry name, Utf8Entry descriptor, int methodFlags, Consumer handler) { return withMethod(name, descriptor, methodFlags, Util.buildingCode(handler)); } /** * Adds a method. * @param name the name of the method * @param descriptor the method descriptor * @param methodFlags the access flags * @param handler handler which receives a {@link MethodBuilder} which can * further define the contents of the method * @return this builder */ default ClassBuilder withMethod(String name, MethodTypeDesc descriptor, int methodFlags, Consumer handler) { return withMethod(constantPool().utf8Entry(name), constantPool().utf8Entry(descriptor), methodFlags, handler); } /** * Adds a method, with only a {@link CodeAttribute}. * @param name the name of the method * @param descriptor the method descriptor * @param methodFlags the access flags * @param handler handler which receives a {@link CodeBuilder} which can * define the contents of the method body * @return this builder */ default ClassBuilder withMethodBody(String name, MethodTypeDesc descriptor, int methodFlags, Consumer handler) { return withMethod(name, descriptor, methodFlags, Util.buildingCode(handler)); } /** * Adds a method by transforming a method from another class. * * @implNote *

This method behaves as if: * {@snippet lang=java : * withMethod(method.methodName(), method.methodType(), * b -> b.transformMethod(method, transform)); * } * @param method the method to be transformed * @param transform the transform to apply to the method * @return this builder */ ClassBuilder transformMethod(MethodModel method, MethodTransform transform); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy