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