1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm.util; 29 30 import org.objectweb.asm.AnnotationVisitor; 31 import org.objectweb.asm.Opcodes; 32 import org.objectweb.asm.Type; 33 34 /** 35 * An {@link AnnotationVisitor} that checks that its methods are properly used. 36 * 37 * @author Eric Bruneton 38 */ 39 public class CheckAnnotationAdapter extends AnnotationVisitor { 40 41 /** 42 * Whether the values of the visited annotation are named. AnnotationVisitor instances used for 43 * annotation default and annotation arrays use unnamed values. 44 */ 45 private final boolean useNamedValue; 46 47 /** Whether the {@link #visitEnd} method has been called. */ 48 private boolean visitEndCalled; 49 CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor)50 public CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor) { 51 this(annotationVisitor, true); 52 } 53 CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor, final boolean useNamedValues)54 CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor, final boolean useNamedValues) { 55 super(/* latest api = */ Opcodes.ASM9, annotationVisitor); 56 this.useNamedValue = useNamedValues; 57 } 58 59 @Override visit(final String name, final Object value)60 public void visit(final String name, final Object value) { 61 checkVisitEndNotCalled(); 62 checkName(name); 63 if (!(value instanceof Byte 64 || value instanceof Boolean 65 || value instanceof Character 66 || value instanceof Short 67 || value instanceof Integer 68 || value instanceof Long 69 || value instanceof Float 70 || value instanceof Double 71 || value instanceof String 72 || value instanceof Type 73 || value instanceof byte[] 74 || value instanceof boolean[] 75 || value instanceof char[] 76 || value instanceof short[] 77 || value instanceof int[] 78 || value instanceof long[] 79 || value instanceof float[] 80 || value instanceof double[])) { 81 throw new IllegalArgumentException("Invalid annotation value"); 82 } 83 if (value instanceof Type && ((Type) value).getSort() == Type.METHOD) { 84 throw new IllegalArgumentException("Invalid annotation value"); 85 } 86 super.visit(name, value); 87 } 88 89 @Override visitEnum(final String name, final String descriptor, final String value)90 public void visitEnum(final String name, final String descriptor, final String value) { 91 checkVisitEndNotCalled(); 92 checkName(name); 93 // Annotations can only appear in V1_5 or more classes. 94 CheckMethodAdapter.checkDescriptor(Opcodes.V1_5, descriptor, false); 95 if (value == null) { 96 throw new IllegalArgumentException("Invalid enum value"); 97 } 98 super.visitEnum(name, descriptor, value); 99 } 100 101 @Override visitAnnotation(final String name, final String descriptor)102 public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { 103 checkVisitEndNotCalled(); 104 checkName(name); 105 // Annotations can only appear in V1_5 or more classes. 106 CheckMethodAdapter.checkDescriptor(Opcodes.V1_5, descriptor, false); 107 return new CheckAnnotationAdapter(super.visitAnnotation(name, descriptor)); 108 } 109 110 @Override visitArray(final String name)111 public AnnotationVisitor visitArray(final String name) { 112 checkVisitEndNotCalled(); 113 checkName(name); 114 return new CheckAnnotationAdapter(super.visitArray(name), false); 115 } 116 117 @Override visitEnd()118 public void visitEnd() { 119 checkVisitEndNotCalled(); 120 visitEndCalled = true; 121 super.visitEnd(); 122 } 123 checkName(final String name)124 private void checkName(final String name) { 125 if (useNamedValue && name == null) { 126 throw new IllegalArgumentException("Annotation value name must not be null"); 127 } 128 } 129 checkVisitEndNotCalled()130 private void checkVisitEndNotCalled() { 131 if (visitEndCalled) { 132 throw new IllegalStateException("Cannot call a visit method after visitEnd has been called"); 133 } 134 } 135 } 136