/* * Copyright (c) 2017, 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. * * 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 jdk.experimental.bytecode; import java.util.function.Consumer; /** * Base class builder. The base of higher level class builders. * * @param the type of symbol representation * @param the type of type descriptors representation * @param the type of this builder */ public class ClassBuilder> extends DeclBuilder { /** * The helper to use to manipulate type descriptors. */ protected TypeHelper typeHelper; /** * The symbol for the class being built. */ protected S thisClass; /** * The super-interfaces of the class being built.. */ protected GrowableByteBuffer interfaces = new GrowableByteBuffer(); /** * The fields of the class being built. */ protected GrowableByteBuffer fields = new GrowableByteBuffer(); /** * The methods of the class being built. */ protected GrowableByteBuffer methods = new GrowableByteBuffer(); int majorVersion; int minorVersion; int flags; int superclass; int nmethods, nfields, ninterfaces; /** * Create a class builder. * * @param poolHelper the helper to build the constant pool * @param typeHelper the helper to use to manipulate type descriptors */ public ClassBuilder(BytePoolHelper poolHelper, TypeHelper typeHelper) { super(poolHelper, typeHelper); this.typeHelper = typeHelper; } /** * Set the minor class file version. * * @param minorVersion the minor version number * @return this builder, for chained calls */ public C withMinorVersion(int minorVersion) { this.minorVersion = minorVersion; return thisBuilder(); } /** * Set the major class file version. * * @param majorVersion the major version number * @return this builder, for chained calls */ public C withMajorVersion(int majorVersion) { this.majorVersion = majorVersion; return thisBuilder(); } /** * Set the class symbol * * @param thisClass the class symbol * @return this builder, for chained calls */ public C withThisClass(S thisClass) { this.thisClass = thisClass; return thisBuilder(); } /** * Set the class access flags * * @param flags an array of {@code Flag} * @return this builder, for chained calls */ @Override public C withFlags(Flag... flags) { for (Flag f : flags) { this.flags |= f.flag; } return thisBuilder(); } /** * Set the superclass * * @param sup the superclass symbol * @return this builder, for chained calls */ public C withSuperclass(S sup) { this.superclass = poolHelper.putClass(sup); return thisBuilder(); } /** * Add a super interface. * * @param sup an interface symbol * @return this builder, for chained calls */ public C withSuperinterface(S sup) { this.interfaces.writeChar(poolHelper.putClass(sup)); ninterfaces++; return thisBuilder(); } /** * Add a field. * * @param name the name of the field * @param type the type descriptor of the field * @return this builder, for chained calls */ public final C withField(CharSequence name, T type) { return withField(name, type, FB -> { }); } /** * Add a field. * * @param name the name of the field * @param type the type descriptor of the field * @param fieldConfig access to the {@code FieldBuilder} to allow clients to * adjust flags, annotations and bytecode attributes on the field declaration * @return this builder, for chained calls */ public C withField(CharSequence name, T type, Consumer> fieldConfig) { FieldBuilder F = new FieldBuilder<>(name, type, poolHelper, typeHelper); fieldConfig.accept(F); F.build(fields); nfields++; return thisBuilder(); } /** * Add a method * * @param name the name of the method * @param type the type descriptor of the method * @return this builder, for chained calls */ public final C withMethod(CharSequence name, T type) { return withMethod(name, type, MB -> { }); } /** * Add a method * * @param name the name of the method * @param type the type descriptor of the method * @param methodConfig access to the {@code MethodBuilder} to allow clients to * adjust flags, annotations and bytecode attributes on the method declaration * @return this builder, for chained calls */ public C withMethod(CharSequence name, T type, Consumer> methodConfig) { MethodBuilder M = new MethodBuilder<>(thisClass, name, type, poolHelper, typeHelper); methodConfig.accept(M); M.build(methods); nmethods++; return thisBuilder(); } /** * Build the constant pool into a byte array. * * @return a representation of this constant pool as a byte array */ @SuppressWarnings("unchecked") public byte[] build() { ((BytePoolHelper)poolHelper).addAttributes(this); addAnnotations(); int thisClassIdx = poolHelper.putClass(thisClass); byte[] poolBytes = poolHelper.entries(); GrowableByteBuffer buf = new GrowableByteBuffer(); buf.writeInt(0xCAFEBABE); buf.writeChar(minorVersion); buf.writeChar(majorVersion); buf.writeChar(poolHelper.size() + 1); buf.writeBytes(poolBytes); buf.writeChar(flags); buf.writeChar(thisClassIdx); buf.writeChar(superclass); buf.writeChar(ninterfaces); if (ninterfaces > 0) { buf.writeBytes(interfaces); } buf.writeChar(nfields); buf.writeBytes(fields); buf.writeChar(nmethods); buf.writeBytes(methods); buf.writeChar(nattrs); buf.writeBytes(attributes); return buf.bytes(); } }