1 /*
   2  * Copyright (c) 2016, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  * Create class file using ASM, slightly modified the ASMifier output
  28  */
  29 
  30 
  31 
  32 import java.io.File;
  33 import java.io.FileOutputStream;
  34 import java.io.IOException;
  35 import jdk.internal.org.objectweb.asm.*;
  36 
  37 
  38 public class ClassFileGenerator {
  39 
  40     public static void main(String... args) throws Exception {
  41         classFileWriter("AnnotationWithVoidReturn.class", AnnoationWithVoidReturnDump.dump());
  42         classFileWriter("AnnotationWithParameter.class", AnnoationWithParameterDump.dump());
  43         classFileWriter("AnnotationWithExtraInterface.class", AnnotationWithExtraInterfaceDump.dump());
  44         classFileWriter("AnnotationWithException.class", AnnotationWithExceptionDump.dump());
  45         classFileWriter("AnnotationWithHashCode.class", AnnotationWithHashCodeDump.dump());
  46         classFileWriter("AnnotationWithDefaultMember.class", AnnotationWithDefaultMemberDump.dump());
  47         classFileWriter("AnnotationWithoutAnnotationAccessModifier.class",
  48                         AnnotationWithoutAnnotationAccessModifierDump.dump());
  49         classFileWriter("HolderX.class", HolderXDump.dump());
  50     }
  51 
  52     private static void classFileWriter(String name, byte[] contents) throws IOException {
  53         try (FileOutputStream fos = new FileOutputStream(new File(System.getProperty("test.classes"),
  54                 name))) {
  55             fos.write(contents);
  56         }
  57     }
  58 
  59     /* Following code creates equivalent classfile, which is not allowed by javac:
  60 
  61     @Retention(RetentionPolicy.RUNTIME)
  62     public @interface AnnotationWithVoidReturn {
  63         void m() default 1;
  64     }
  65 
  66     */
  67 
  68     private static class AnnoationWithVoidReturnDump implements Opcodes {
  69         public static byte[] dump() throws Exception {
  70             ClassWriter cw = new ClassWriter(0);
  71             MethodVisitor mv;
  72             AnnotationVisitor av0;
  73 
  74             cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
  75                     "AnnotationWithVoidReturn", null,
  76                     "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
  77 
  78             {
  79                 av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
  80                 av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
  81                         "RUNTIME");
  82                 av0.visitEnd();
  83             }
  84             {
  85                 mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()V", null, null);
  86                 mv.visitEnd();
  87             }
  88             {
  89                 av0 = mv.visitAnnotationDefault();
  90                 av0.visit(null, new Integer(1));
  91                 av0.visitEnd();
  92             }
  93             cw.visitEnd();
  94 
  95             return cw.toByteArray();
  96 
  97         }
  98     }
  99 
 100     /* Following code creates equivalent classfile, which is not allowed by javac:
 101 
 102     @Retention(RetentionPolicy.RUNTIME)
 103     public @interface AnnotationWithParameter {
 104         int m(int x) default -1;
 105     }
 106 
 107     */
 108 
 109     private static class AnnoationWithParameterDump implements Opcodes {
 110         public static byte[] dump() throws Exception {
 111 
 112             ClassWriter cw = new ClassWriter(0);
 113             MethodVisitor mv;
 114             AnnotationVisitor av0;
 115 
 116             cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
 117                     "AnnotationWithParameter", null,
 118                     "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
 119 
 120             {
 121                 av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
 122                 av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
 123                         "RUNTIME");
 124                 av0.visitEnd();
 125             }
 126             {
 127                 mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT,
 128                         "badValue",
 129                         "(I)I", // Bad method with a parameter
 130                         null, null);
 131                 mv.visitEnd();
 132             }
 133             {
 134                 av0 = mv.visitAnnotationDefault();
 135                 av0.visit(null, new Integer(-1));
 136                 av0.visitEnd();
 137             }
 138             cw.visitEnd();
 139 
 140             return cw.toByteArray();
 141         }
 142     }
 143 
 144     /* Following code creates equivalent classfile, which is not allowed by javac:
 145 
 146     @Retention(RetentionPolicy.RUNTIME)
 147     public @interface AnnotationWithExtraInterface extends java.io.Serializable {
 148         int m() default 1;
 149     }
 150 
 151     */
 152 
 153     private static class AnnotationWithExtraInterfaceDump implements Opcodes {
 154         public static byte[] dump() throws Exception {
 155             ClassWriter cw = new ClassWriter(0);
 156             MethodVisitor mv;
 157             AnnotationVisitor av0;
 158 
 159             cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
 160                     "AnnotationWithExtraInterface", null,
 161                     "java/lang/Object", new String[]{"java/lang/annotation/Annotation",
 162                                                      "java/io/Serializable"});
 163 
 164             {
 165                 av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
 166                 av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
 167                         "RUNTIME");
 168                 av0.visitEnd();
 169             }
 170             {
 171                 mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
 172                 mv.visitEnd();
 173             }
 174             {
 175                 av0 = mv.visitAnnotationDefault();
 176                 av0.visit(null, new Integer(1));
 177                 av0.visitEnd();
 178             }
 179             cw.visitEnd();
 180 
 181             return cw.toByteArray();
 182         }
 183     }
 184 
 185     /* Following code creates equivalent classfile, which is not allowed by javac:
 186 
 187     @Retention(RetentionPolicy.RUNTIME)
 188     public @interface AnnotationWithException {
 189         int m() throws Exception default 1;
 190     }
 191 
 192     */
 193 
 194     private static class AnnotationWithExceptionDump implements Opcodes {
 195         public static byte[] dump() throws Exception {
 196             ClassWriter cw = new ClassWriter(0);
 197             MethodVisitor mv;
 198             AnnotationVisitor av0;
 199 
 200             cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
 201                     "AnnotationWithException", null,
 202                     "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
 203 
 204             {
 205                 av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
 206                 av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
 207                         "RUNTIME");
 208                 av0.visitEnd();
 209             }
 210             {
 211                 mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null,
 212                                     new String[] {"java/lang/Exception"});
 213                 mv.visitEnd();
 214             }
 215             {
 216                 av0 = mv.visitAnnotationDefault();
 217                 av0.visit(null, new Integer(1));
 218                 av0.visitEnd();
 219             }
 220             cw.visitEnd();
 221 
 222             return cw.toByteArray();
 223         }
 224     }
 225 
 226     /* Following code creates equivalent classfile, which is not allowed by javac:
 227 
 228     @Retention(RetentionPolicy.RUNTIME)
 229     public @interface AnnotationWithHashCode {
 230         int hashCode() default 1;
 231     }
 232 
 233     */
 234 
 235     private static class AnnotationWithHashCodeDump implements Opcodes {
 236         public static byte[] dump() throws Exception {
 237             ClassWriter cw = new ClassWriter(0);
 238             MethodVisitor mv;
 239             AnnotationVisitor av0;
 240 
 241             cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
 242                     "AnnotationWithHashCode", null,
 243                     "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
 244 
 245             {
 246                 av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
 247                 av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
 248                         "RUNTIME");
 249                 av0.visitEnd();
 250             }
 251             {
 252                 mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "hashCode", "()I", null, null);
 253                 mv.visitEnd();
 254             }
 255             {
 256                 av0 = mv.visitAnnotationDefault();
 257                 av0.visit(null, new Integer(1));
 258                 av0.visitEnd();
 259             }
 260             cw.visitEnd();
 261 
 262             return cw.toByteArray();
 263         }
 264     }
 265 
 266     /* Following code creates equivalent classfile, which is not allowed by javac:
 267 
 268     @Retention(RetentionPolicy.RUNTIME)
 269     public @interface AnnotationWithDefaultMember {
 270         int m() default 1;
 271         default int d() default 2 { return 2; }
 272     }
 273 
 274     */
 275 
 276     private static class AnnotationWithDefaultMemberDump implements Opcodes {
 277         public static byte[] dump() throws Exception {
 278             ClassWriter cw = new ClassWriter(0);
 279             MethodVisitor mv, dv;
 280             AnnotationVisitor av0;
 281 
 282             cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
 283                     "AnnotationWithDefaultMember", null,
 284                     "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
 285 
 286             {
 287                 av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
 288                 av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
 289                         "RUNTIME");
 290                 av0.visitEnd();
 291             }
 292             {
 293                 mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
 294                 mv.visitEnd();
 295             }
 296             {
 297                 av0 = mv.visitAnnotationDefault();
 298                 av0.visit(null, new Integer(1));
 299                 av0.visitEnd();
 300             }
 301             {
 302                 dv = cw.visitMethod(ACC_PUBLIC, "d", "()I", null, null);
 303                 dv.visitMaxs(1, 1);
 304                 dv.visitCode();
 305                 dv.visitInsn(Opcodes.ICONST_2);
 306                 dv.visitInsn(Opcodes.IRETURN);
 307                 dv.visitEnd();
 308             }
 309             {
 310                 av0 = dv.visitAnnotationDefault();
 311                 av0.visit(null, new Integer(2));
 312                 av0.visitEnd();
 313             }
 314             cw.visitEnd();
 315 
 316             return cw.toByteArray();
 317         }
 318     }
 319 
 320     /* Following code creates equivalent classfile, which is not allowed by javac:
 321 
 322     @Retention(RetentionPolicy.RUNTIME)
 323     public interface AnnotationWithoutAnnotationAccessModifier extends java.lang.annotation.Annotation {
 324         int m() default 1;
 325     }
 326 
 327     */
 328 
 329     private static class AnnotationWithoutAnnotationAccessModifierDump implements Opcodes {
 330         public static byte[] dump() throws Exception {
 331             ClassWriter cw = new ClassWriter(0);
 332             MethodVisitor mv;
 333             AnnotationVisitor av0;
 334 
 335             cw.visit(52, ACC_PUBLIC + /* ACC_ANNOTATION +*/ ACC_ABSTRACT + ACC_INTERFACE,
 336                     "AnnotationWithoutAnnotationAccessModifier", null,
 337                     "java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
 338 
 339             {
 340                 av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
 341                 av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
 342                         "RUNTIME");
 343                 av0.visitEnd();
 344             }
 345             {
 346                 mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
 347                 mv.visitEnd();
 348             }
 349             {
 350                 av0 = mv.visitAnnotationDefault();
 351                 av0.visit(null, new Integer(1));
 352                 av0.visitEnd();
 353             }
 354             cw.visitEnd();
 355 
 356             return cw.toByteArray();
 357         }
 358     }
 359 
 360     /* Following code creates equivalent classfile, which is not allowed by javac
 361        since AnnotationWithoutAnnotationAccessModifier is not marked with ACC_ANNOTATION:
 362 
 363     @GoodAnnotation
 364     @AnnotationWithoutAnnotationAccessModifier
 365     public interface HolderX {
 366     }
 367 
 368     */
 369 
 370     private static class HolderXDump implements Opcodes {
 371         public static byte[] dump() throws Exception {
 372             ClassWriter cw = new ClassWriter(0);
 373 
 374             cw.visit(52, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
 375                     "HolderX", null,
 376                     "java/lang/Object", new String[0]);
 377 
 378             {
 379                 AnnotationVisitor av0;
 380                 av0 = cw.visitAnnotation("LGoodAnnotation;", true);
 381                 av0.visitEnd();
 382                 av0 = cw.visitAnnotation("LAnnotationWithoutAnnotationAccessModifier;", true);
 383                 av0.visitEnd();
 384             }
 385             cw.visitEnd();
 386 
 387             return cw.toByteArray();
 388         }
 389     }
 390 }