1 /*
2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package jdk.experimental.bytecode;
25 
26 import java.util.function.Consumer;
27 import java.util.function.ToIntBiFunction;
28 
29 public class AnnotationsBuilder<S, T, E> extends AbstractBuilder<S, T, E, AnnotationsBuilder<S, T, E>> {
30 
31     GrowableByteBuffer annoAttribute;
32     int nannos;
33 
AnnotationsBuilder(PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper)34     AnnotationsBuilder(PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
35         super(poolHelper, typeHelper);
36         this.annoAttribute = new GrowableByteBuffer();
37         annoAttribute.writeChar(0);
38     }
39 
40     public enum Kind {
41         RUNTIME_VISIBLE,
42         RUNTIME_INVISIBLE;
43     }
44 
45     enum Tag {
46         B('B'),
47         C('C'),
48         D('D'),
49         F('F'),
50         I('I'),
51         J('J'),
52         S('S'),
53         Z('Z'),
54         STRING('s'),
55         ENUM('e'),
56         CLASS('c'),
57         ANNO('@'),
58         ARRAY('[');
59 
60         char tagChar;
61 
Tag(char tagChar)62         Tag(char tagChar) {
63             this.tagChar = tagChar;
64         }
65     }
66 
withAnnotation(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder)67     AnnotationsBuilder<S, T, E> withAnnotation(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
68         annoAttribute.writeChar(poolHelper.putType(annoType));
69         int offset = annoAttribute.offset;
70         annoAttribute.writeChar(0);
71         if (annotationBuilder != null) {
72             AnnotationElementBuilder _builder = new AnnotationElementBuilder();
73             int nelems = _builder.withElements(annotationBuilder);
74             patchCharAt(offset, nelems);
75         }
76         nannos++;
77         return this;
78     }
79 
build()80     byte[] build() {
81         patchCharAt(0, nannos);
82         return annoAttribute.bytes();
83     }
84 
patchCharAt(int offset, int newChar)85     private void patchCharAt(int offset, int newChar) {
86         int prevOffset = annoAttribute.offset;
87         try {
88             annoAttribute.offset = offset;
89             annoAttribute.writeChar(newChar);
90         } finally {
91             annoAttribute.offset = prevOffset;
92         }
93     }
94 
95     @SuppressWarnings({"unchecked", "rawtypes"})
96     static Consumer NO_BUILDER =
97             new Consumer() {
98                 @Override
99                 public void accept(Object o) {
100                     //do nothing
101                 }
102             };
103 
104     public class AnnotationElementBuilder {
105 
106         int nelems;
107 
withString(String name, String s)108         public AnnotationElementBuilder withString(String name, String s) {
109             annoAttribute.writeChar(poolHelper.putUtf8(name));
110             writeStringValue(s);
111             return this;
112         }
113 
writeStringValue(String s)114         private void writeStringValue(String s) {
115             annoAttribute.writeByte(Tag.STRING.tagChar);
116             annoAttribute.writeChar(poolHelper.putUtf8(s));
117             nelems++;
118         }
119 
withClass(String name, T s)120         public AnnotationElementBuilder withClass(String name, T s) {
121             annoAttribute.writeChar(poolHelper.putUtf8(name));
122             writeClassValue(s);
123             return this;
124         }
125 
writeClassValue(T s)126         private void writeClassValue(T s) {
127             annoAttribute.writeByte(Tag.CLASS.tagChar);
128             annoAttribute.writeChar(poolHelper.putType(s));
129             nelems++;
130         }
131 
withEnum(String name, T enumType, int constant)132         public AnnotationElementBuilder withEnum(String name, T enumType, int constant) {
133             annoAttribute.writeChar(poolHelper.putUtf8(name));
134             writeEnumValue(enumType, constant);
135             return this;
136         }
137 
writeEnumValue(T enumType, int constant)138         private void writeEnumValue(T enumType, int constant) {
139             annoAttribute.writeByte(Tag.ENUM.tagChar);
140             annoAttribute.writeChar(poolHelper.putType(enumType));
141             annoAttribute.writeChar(constant);
142             nelems++;
143         }
144 
withAnnotation(String name, T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder)145         public AnnotationElementBuilder withAnnotation(String name, T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
146             annoAttribute.writeChar(poolHelper.putUtf8(name));
147             writeAnnotationValue(annoType, annotationBuilder);
148             return this;
149         }
150 
writeAnnotationValue(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder)151         private void writeAnnotationValue(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
152             annoAttribute.writeByte(Tag.ANNO.tagChar);
153             annoAttribute.writeChar(poolHelper.putType(annoType));
154             int offset = annoAttribute.offset;
155             annoAttribute.writeChar(0);
156             int nelems = withNestedElements(annotationBuilder);
157             patchCharAt(offset, nelems);
158             this.nelems++;
159         }
160 
withPrimitive(String name, char c)161         public AnnotationElementBuilder withPrimitive(String name, char c) {
162             annoAttribute.writeChar(poolHelper.putUtf8(name));
163             writePrimitiveValue(Tag.C, (int)c, PoolHelper::putInt);
164             return this;
165         }
166 
withPrimitive(String name, short s)167         public AnnotationElementBuilder withPrimitive(String name, short s) {
168             annoAttribute.writeChar(poolHelper.putUtf8(name));
169             writePrimitiveValue(Tag.S, (int)s, PoolHelper::putInt);
170             return this;
171         }
172 
withPrimitive(String name, byte b)173         public AnnotationElementBuilder withPrimitive(String name, byte b) {
174             annoAttribute.writeChar(poolHelper.putUtf8(name));
175             writePrimitiveValue(Tag.B, (int)b, PoolHelper::putInt);
176             return this;
177         }
178 
withPrimitive(String name, int i)179         public AnnotationElementBuilder withPrimitive(String name, int i) {
180             annoAttribute.writeChar(poolHelper.putUtf8(name));
181             writePrimitiveValue(Tag.I, i, PoolHelper::putInt);
182             return this;
183         }
184 
withPrimitive(String name, float f)185         public AnnotationElementBuilder withPrimitive(String name, float f) {
186             annoAttribute.writeChar(poolHelper.putUtf8(name));
187             writePrimitiveValue(Tag.F, f, PoolHelper::putFloat);
188             return this;
189         }
190 
withPrimitive(String name, long l)191         public AnnotationElementBuilder withPrimitive(String name, long l) {
192             annoAttribute.writeChar(poolHelper.putUtf8(name));
193             writePrimitiveValue(Tag.J, l, PoolHelper::putLong);
194             return this;
195         }
196 
withPrimitive(String name, double d)197         public AnnotationElementBuilder withPrimitive(String name, double d) {
198             annoAttribute.writeChar(poolHelper.putUtf8(name));
199             writePrimitiveValue(Tag.D, d, PoolHelper::putDouble);
200             return this;
201         }
202 
withPrimitive(String name, boolean b)203         public AnnotationElementBuilder withPrimitive(String name, boolean b) {
204             annoAttribute.writeChar(poolHelper.putUtf8(name));
205             writePrimitiveValue(Tag.Z, b ? 1 : 0, PoolHelper::putInt);
206             return this;
207         }
208 
writePrimitiveValue(Tag tag, Z value, ToIntBiFunction<PoolHelper<S, T, E>, Z> poolFunc)209         private <Z> void writePrimitiveValue(Tag tag, Z value, ToIntBiFunction<PoolHelper<S, T, E>, Z> poolFunc) {
210             annoAttribute.writeByte(tag.tagChar);
211             annoAttribute.writeChar(poolFunc.applyAsInt(poolHelper, value));
212             nelems++;
213         }
214 
withStrings(String name, String... ss)215         AnnotationElementBuilder withStrings(String name, String... ss) {
216             annoAttribute.writeChar(poolHelper.putUtf8(name));
217             annoAttribute.writeChar(ss.length);
218             for (String s : ss) {
219                 writeStringValue(s);
220             }
221             return this;
222         }
223 
224         @SuppressWarnings("unchecked")
withClasses(String name, T... cc)225         AnnotationElementBuilder withClasses(String name, T... cc) {
226             annoAttribute.writeChar(poolHelper.putUtf8(name));
227             annoAttribute.writeChar(cc.length);
228             for (T c : cc) {
229                 writeClassValue(c);
230             }
231             return this;
232         }
233 
withEnums(String name, T enumType, int... constants)234         AnnotationElementBuilder withEnums(String name, T enumType, int... constants) {
235             annoAttribute.writeChar(poolHelper.putUtf8(name));
236             annoAttribute.writeChar(constants.length);
237             for (int c : constants) {
238                 writeEnumValue(enumType, c);
239             }
240             return this;
241         }
242 
243         @SuppressWarnings("unchecked")
withAnnotations(String name, T annoType, Consumer<? super AnnotationElementBuilder>... annotationBuilders)244         public AnnotationElementBuilder withAnnotations(String name, T annoType, Consumer<? super AnnotationElementBuilder>... annotationBuilders) {
245             annoAttribute.writeChar(poolHelper.putUtf8(name));
246             annoAttribute.writeChar(annotationBuilders.length);
247             for (Consumer<? super AnnotationElementBuilder> annotationBuilder : annotationBuilders) {
248                 writeAnnotationValue(annoType, annotationBuilder);
249             }
250             return this;
251         }
252 
withPrimitives(String name, char... cc)253         public AnnotationElementBuilder withPrimitives(String name, char... cc) {
254             annoAttribute.writeChar(poolHelper.putUtf8(name));
255             annoAttribute.writeChar(cc.length);
256             for (char c : cc) {
257                 writePrimitiveValue(Tag.C, (int)c, PoolHelper::putInt);
258             }
259             return this;
260         }
261 
withPrimitives(String name, short... ss)262         public AnnotationElementBuilder withPrimitives(String name, short... ss) {
263             annoAttribute.writeChar(poolHelper.putUtf8(name));
264             annoAttribute.writeChar(ss.length);
265             for (short s : ss) {
266                 writePrimitiveValue(Tag.S, (int)s, PoolHelper::putInt);
267             }
268             return this;
269         }
270 
withPrimitives(String name, byte... bb)271         public AnnotationElementBuilder withPrimitives(String name, byte... bb) {
272             annoAttribute.writeChar(poolHelper.putUtf8(name));
273             annoAttribute.writeChar(bb.length);
274             for (byte b : bb) {
275                 writePrimitiveValue(Tag.B, (int)b, PoolHelper::putInt);
276             }
277             return this;
278         }
279 
withPrimitives(String name, int... ii)280         public AnnotationElementBuilder withPrimitives(String name, int... ii) {
281             annoAttribute.writeChar(poolHelper.putUtf8(name));
282             annoAttribute.writeChar(ii.length);
283             for (int i : ii) {
284                 writePrimitiveValue(Tag.I, i,  PoolHelper::putInt);
285             }
286             return this;
287         }
288 
withPrimitives(String name, float... ff)289         public AnnotationElementBuilder withPrimitives(String name, float... ff) {
290             annoAttribute.writeChar(poolHelper.putUtf8(name));
291             annoAttribute.writeChar(ff.length);
292             for (float f : ff) {
293                 writePrimitiveValue(Tag.F, f, PoolHelper::putFloat);
294             }
295             return this;
296         }
297 
withPrimitives(String name, long... ll)298         public AnnotationElementBuilder withPrimitives(String name, long... ll) {
299             annoAttribute.writeChar(poolHelper.putUtf8(name));
300             annoAttribute.writeChar(ll.length);
301             for (long l : ll) {
302                 writePrimitiveValue(Tag.J, l, PoolHelper::putLong);
303             }
304             return this;
305         }
306 
withPrimitives(String name, double... dd)307         public AnnotationElementBuilder withPrimitives(String name, double... dd) {
308             annoAttribute.writeChar(poolHelper.putUtf8(name));
309             annoAttribute.writeChar(dd.length);
310             for (double d : dd) {
311                 writePrimitiveValue(Tag.D, d, PoolHelper::putDouble);
312             }
313             return this;
314         }
315 
withPrimitives(String name, boolean... bb)316         public AnnotationElementBuilder withPrimitives(String name, boolean... bb) {
317             annoAttribute.writeChar(poolHelper.putUtf8(name));
318             annoAttribute.writeChar(bb.length);
319             for (boolean b : bb) {
320                 writePrimitiveValue(Tag.Z, b ? 1 : 0, PoolHelper::putInt);
321             }
322             return this;
323         }
324 
withNestedElements(Consumer<? super AnnotationElementBuilder> annotationBuilder)325         int withNestedElements(Consumer<? super AnnotationElementBuilder> annotationBuilder) {
326             return withElements(new AnnotationElementBuilder(), annotationBuilder);
327         }
328 
withElements(Consumer<? super AnnotationElementBuilder> annotationBuilder)329         int withElements(Consumer<? super AnnotationElementBuilder> annotationBuilder) {
330             return withElements(this, annotationBuilder);
331         }
332 
withElements(AnnotationElementBuilder builder, Consumer<? super AnnotationElementBuilder> annotationBuilder)333         private int withElements(AnnotationElementBuilder builder, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
334             annotationBuilder.accept(builder);
335             return builder.nelems;
336         }
337     }
338 }
339