| /* |
| * 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; |
| import java.util.function.ToIntBiFunction; |
| |
| public class AnnotationsBuilder<S, T, E> extends AbstractBuilder<S, T, E, AnnotationsBuilder<S, T, E>> { |
| |
| GrowableByteBuffer annoAttribute; |
| int nannos; |
| |
| AnnotationsBuilder(PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) { |
| super(poolHelper, typeHelper); |
| this.annoAttribute = new GrowableByteBuffer(); |
| annoAttribute.writeChar(0); |
| } |
| |
| public enum Kind { |
| RUNTIME_VISIBLE, |
| RUNTIME_INVISIBLE; |
| } |
| |
| enum Tag { |
| B('B'), |
| C('C'), |
| D('D'), |
| F('F'), |
| I('I'), |
| J('J'), |
| S('S'), |
| Z('Z'), |
| STRING('s'), |
| ENUM('e'), |
| CLASS('c'), |
| ANNO('@'), |
| ARRAY('['); |
| |
| char tagChar; |
| |
| Tag(char tagChar) { |
| this.tagChar = tagChar; |
| } |
| } |
| |
| AnnotationsBuilder<S, T, E> withAnnotation(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) { |
| annoAttribute.writeChar(poolHelper.putType(annoType)); |
| int offset = annoAttribute.offset; |
| annoAttribute.writeChar(0); |
| if (annotationBuilder != null) { |
| AnnotationElementBuilder _builder = new AnnotationElementBuilder(); |
| int nelems = _builder.withElements(annotationBuilder); |
| patchCharAt(offset, nelems); |
| } |
| nannos++; |
| return this; |
| } |
| |
| byte[] build() { |
| patchCharAt(0, nannos); |
| return annoAttribute.bytes(); |
| } |
| |
| private void patchCharAt(int offset, int newChar) { |
| int prevOffset = annoAttribute.offset; |
| try { |
| annoAttribute.offset = offset; |
| annoAttribute.writeChar(newChar); |
| } finally { |
| annoAttribute.offset = prevOffset; |
| } |
| } |
| |
| @SuppressWarnings({"unchecked", "rawtypes"}) |
| static Consumer NO_BUILDER = |
| new Consumer() { |
| @Override |
| public void accept(Object o) { |
| //do nothing |
| } |
| }; |
| |
| public class AnnotationElementBuilder { |
| |
| int nelems; |
| |
| public AnnotationElementBuilder withString(String name, String s) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writeStringValue(s); |
| return this; |
| } |
| |
| private void writeStringValue(String s) { |
| annoAttribute.writeByte(Tag.STRING.tagChar); |
| annoAttribute.writeChar(poolHelper.putUtf8(s)); |
| nelems++; |
| } |
| |
| public AnnotationElementBuilder withClass(String name, T s) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writeClassValue(s); |
| return this; |
| } |
| |
| private void writeClassValue(T s) { |
| annoAttribute.writeByte(Tag.CLASS.tagChar); |
| annoAttribute.writeChar(poolHelper.putType(s)); |
| nelems++; |
| } |
| |
| public AnnotationElementBuilder withEnum(String name, T enumType, int constant) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writeEnumValue(enumType, constant); |
| return this; |
| } |
| |
| private void writeEnumValue(T enumType, int constant) { |
| annoAttribute.writeByte(Tag.ENUM.tagChar); |
| annoAttribute.writeChar(poolHelper.putType(enumType)); |
| annoAttribute.writeChar(constant); |
| nelems++; |
| } |
| |
| public AnnotationElementBuilder withAnnotation(String name, T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writeAnnotationValue(annoType, annotationBuilder); |
| return this; |
| } |
| |
| private void writeAnnotationValue(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) { |
| annoAttribute.writeByte(Tag.ANNO.tagChar); |
| annoAttribute.writeChar(poolHelper.putType(annoType)); |
| int offset = annoAttribute.offset; |
| annoAttribute.writeChar(0); |
| int nelems = withNestedElements(annotationBuilder); |
| patchCharAt(offset, nelems); |
| this.nelems++; |
| } |
| |
| public AnnotationElementBuilder withPrimitive(String name, char c) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writePrimitiveValue(Tag.C, (int)c, PoolHelper::putInt); |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitive(String name, short s) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writePrimitiveValue(Tag.S, (int)s, PoolHelper::putInt); |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitive(String name, byte b) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writePrimitiveValue(Tag.B, (int)b, PoolHelper::putInt); |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitive(String name, int i) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writePrimitiveValue(Tag.I, i, PoolHelper::putInt); |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitive(String name, float f) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writePrimitiveValue(Tag.F, f, PoolHelper::putFloat); |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitive(String name, long l) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writePrimitiveValue(Tag.J, l, PoolHelper::putLong); |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitive(String name, double d) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writePrimitiveValue(Tag.D, d, PoolHelper::putDouble); |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitive(String name, boolean b) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| writePrimitiveValue(Tag.Z, b ? 1 : 0, PoolHelper::putInt); |
| return this; |
| } |
| |
| private <Z> void writePrimitiveValue(Tag tag, Z value, ToIntBiFunction<PoolHelper<S, T, E>, Z> poolFunc) { |
| annoAttribute.writeByte(tag.tagChar); |
| annoAttribute.writeChar(poolFunc.applyAsInt(poolHelper, value)); |
| nelems++; |
| } |
| |
| AnnotationElementBuilder withStrings(String name, String... ss) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(ss.length); |
| for (String s : ss) { |
| writeStringValue(s); |
| } |
| return this; |
| } |
| |
| @SuppressWarnings("unchecked") |
| AnnotationElementBuilder withClasses(String name, T... cc) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(cc.length); |
| for (T c : cc) { |
| writeClassValue(c); |
| } |
| return this; |
| } |
| |
| AnnotationElementBuilder withEnums(String name, T enumType, int... constants) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(constants.length); |
| for (int c : constants) { |
| writeEnumValue(enumType, c); |
| } |
| return this; |
| } |
| |
| @SuppressWarnings("unchecked") |
| public AnnotationElementBuilder withAnnotations(String name, T annoType, Consumer<? super AnnotationElementBuilder>... annotationBuilders) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(annotationBuilders.length); |
| for (Consumer<? super AnnotationElementBuilder> annotationBuilder : annotationBuilders) { |
| writeAnnotationValue(annoType, annotationBuilder); |
| } |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitives(String name, char... cc) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(cc.length); |
| for (char c : cc) { |
| writePrimitiveValue(Tag.C, (int)c, PoolHelper::putInt); |
| } |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitives(String name, short... ss) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(ss.length); |
| for (short s : ss) { |
| writePrimitiveValue(Tag.S, (int)s, PoolHelper::putInt); |
| } |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitives(String name, byte... bb) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(bb.length); |
| for (byte b : bb) { |
| writePrimitiveValue(Tag.B, (int)b, PoolHelper::putInt); |
| } |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitives(String name, int... ii) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(ii.length); |
| for (int i : ii) { |
| writePrimitiveValue(Tag.I, i, PoolHelper::putInt); |
| } |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitives(String name, float... ff) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(ff.length); |
| for (float f : ff) { |
| writePrimitiveValue(Tag.F, f, PoolHelper::putFloat); |
| } |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitives(String name, long... ll) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(ll.length); |
| for (long l : ll) { |
| writePrimitiveValue(Tag.J, l, PoolHelper::putLong); |
| } |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitives(String name, double... dd) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(dd.length); |
| for (double d : dd) { |
| writePrimitiveValue(Tag.D, d, PoolHelper::putDouble); |
| } |
| return this; |
| } |
| |
| public AnnotationElementBuilder withPrimitives(String name, boolean... bb) { |
| annoAttribute.writeChar(poolHelper.putUtf8(name)); |
| annoAttribute.writeChar(bb.length); |
| for (boolean b : bb) { |
| writePrimitiveValue(Tag.Z, b ? 1 : 0, PoolHelper::putInt); |
| } |
| return this; |
| } |
| |
| int withNestedElements(Consumer<? super AnnotationElementBuilder> annotationBuilder) { |
| return withElements(new AnnotationElementBuilder(), annotationBuilder); |
| } |
| |
| int withElements(Consumer<? super AnnotationElementBuilder> annotationBuilder) { |
| return withElements(this, annotationBuilder); |
| } |
| |
| private int withElements(AnnotationElementBuilder builder, Consumer<? super AnnotationElementBuilder> annotationBuilder) { |
| annotationBuilder.accept(builder); |
| return builder.nelems; |
| } |
| } |
| } |