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 29 package org.objectweb.asm.commons; 30 31 import org.objectweb.asm.AnnotationVisitor; 32 import org.objectweb.asm.Opcodes; 33 34 /** 35 * An {@link AnnotationVisitor} that remaps types with a {@link Remapper}. 36 * 37 * @author Eugene Kuleshov 38 */ 39 public class AnnotationRemapper extends AnnotationVisitor { 40 41 /** 42 * The descriptor of the visited annotation. May be {@literal null}, for instance for 43 * AnnotationDefault. 44 */ 45 protected final String descriptor; 46 47 /** The remapper used to remap the types in the visited annotation. */ 48 protected final Remapper remapper; 49 50 /** 51 * Constructs a new {@link AnnotationRemapper}. <i>Subclasses must not use this constructor</i>. 52 * Instead, they must use the {@link #AnnotationRemapper(int,AnnotationVisitor,Remapper)} version. 53 * 54 * @param annotationVisitor the annotation visitor this remapper must delegate to. 55 * @param remapper the remapper to use to remap the types in the visited annotation. 56 * @deprecated use {@link #AnnotationRemapper(String, AnnotationVisitor, Remapper)} instead. 57 */ 58 @Deprecated AnnotationRemapper(final AnnotationVisitor annotationVisitor, final Remapper remapper)59 public AnnotationRemapper(final AnnotationVisitor annotationVisitor, final Remapper remapper) { 60 this(/* descriptor = */ null, annotationVisitor, remapper); 61 } 62 63 /** 64 * Constructs a new {@link AnnotationRemapper}. <i>Subclasses must not use this constructor</i>. 65 * Instead, they must use the {@link #AnnotationRemapper(int,String,AnnotationVisitor,Remapper)} 66 * version. 67 * 68 * @param descriptor the descriptor of the visited annotation. May be {@literal null}. 69 * @param annotationVisitor the annotation visitor this remapper must delegate to. 70 * @param remapper the remapper to use to remap the types in the visited annotation. 71 */ AnnotationRemapper( final String descriptor, final AnnotationVisitor annotationVisitor, final Remapper remapper)72 public AnnotationRemapper( 73 final String descriptor, final AnnotationVisitor annotationVisitor, final Remapper remapper) { 74 this(/* latest api = */ Opcodes.ASM9, descriptor, annotationVisitor, remapper); 75 } 76 77 /** 78 * Constructs a new {@link AnnotationRemapper}. 79 * 80 * @param api the ASM API version supported by this remapper. Must be one of the {@code 81 * ASM}<i>x</i> values in {@link Opcodes}. 82 * @param annotationVisitor the annotation visitor this remapper must delegate to. 83 * @param remapper the remapper to use to remap the types in the visited annotation. 84 * @deprecated use {@link #AnnotationRemapper(int, String, AnnotationVisitor, Remapper)} instead. 85 */ 86 @Deprecated AnnotationRemapper( final int api, final AnnotationVisitor annotationVisitor, final Remapper remapper)87 protected AnnotationRemapper( 88 final int api, final AnnotationVisitor annotationVisitor, final Remapper remapper) { 89 this(api, /* descriptor = */ null, annotationVisitor, remapper); 90 } 91 92 /** 93 * Constructs a new {@link AnnotationRemapper}. 94 * 95 * @param api the ASM API version supported by this remapper. Must be one of the {@code 96 * ASM}<i>x</i> values in {@link Opcodes}. 97 * @param descriptor the descriptor of the visited annotation. May be {@literal null}. 98 * @param annotationVisitor the annotation visitor this remapper must delegate to. 99 * @param remapper the remapper to use to remap the types in the visited annotation. 100 */ AnnotationRemapper( final int api, final String descriptor, final AnnotationVisitor annotationVisitor, final Remapper remapper)101 protected AnnotationRemapper( 102 final int api, 103 final String descriptor, 104 final AnnotationVisitor annotationVisitor, 105 final Remapper remapper) { 106 super(api, annotationVisitor); 107 this.descriptor = descriptor; 108 this.remapper = remapper; 109 } 110 111 @Override visit(final String name, final Object value)112 public void visit(final String name, final Object value) { 113 super.visit(mapAnnotationAttributeName(name), remapper.mapValue(value)); 114 } 115 116 @Override visitEnum(final String name, final String descriptor, final String value)117 public void visitEnum(final String name, final String descriptor, final String value) { 118 super.visitEnum(mapAnnotationAttributeName(name), remapper.mapDesc(descriptor), value); 119 } 120 121 @Override visitAnnotation(final String name, final String descriptor)122 public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { 123 AnnotationVisitor annotationVisitor = 124 super.visitAnnotation(mapAnnotationAttributeName(name), remapper.mapDesc(descriptor)); 125 if (annotationVisitor == null) { 126 return null; 127 } else { 128 return annotationVisitor == av 129 ? this 130 : createAnnotationRemapper(descriptor, annotationVisitor); 131 } 132 } 133 134 @Override visitArray(final String name)135 public AnnotationVisitor visitArray(final String name) { 136 AnnotationVisitor annotationVisitor = super.visitArray(mapAnnotationAttributeName(name)); 137 if (annotationVisitor == null) { 138 return null; 139 } else { 140 return annotationVisitor == av 141 ? this 142 : createAnnotationRemapper(/* descriptor = */ null, annotationVisitor); 143 } 144 } 145 146 /** 147 * Constructs a new remapper for annotations. The default implementation of this method returns a 148 * new {@link AnnotationRemapper}. 149 * 150 * @param annotationVisitor the AnnotationVisitor the remapper must delegate to. 151 * @return the newly created remapper. 152 * @deprecated use {@link #createAnnotationRemapper(String, AnnotationVisitor)} instead. 153 */ 154 @Deprecated createAnnotationRemapper(final AnnotationVisitor annotationVisitor)155 protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) { 156 return new AnnotationRemapper(api, /* descriptor = */ null, annotationVisitor, remapper); 157 } 158 159 /** 160 * Constructs a new remapper for annotations. The default implementation of this method returns a 161 * new {@link AnnotationRemapper}. 162 * 163 * @param descriptor the descriptor of the visited annotation. 164 * @param annotationVisitor the AnnotationVisitor the remapper must delegate to. 165 * @return the newly created remapper. 166 */ createAnnotationRemapper( final String descriptor, final AnnotationVisitor annotationVisitor)167 protected AnnotationVisitor createAnnotationRemapper( 168 final String descriptor, final AnnotationVisitor annotationVisitor) { 169 return new AnnotationRemapper(api, descriptor, annotationVisitor, remapper) 170 .orDeprecatedValue(createAnnotationRemapper(annotationVisitor)); 171 } 172 173 /** 174 * Returns either this object, or the given one. If the given object is equal to the object 175 * returned by the default implementation of the deprecated createAnnotationRemapper method, 176 * meaning that this method has not been overridden (or only in minor ways, for instance to add 177 * logging), then we can return this object instead, supposed to have been created by the new 178 * createAnnotationRemapper method. Otherwise we must return the given object. 179 * 180 * @param deprecatedAnnotationVisitor the result of a call to the deprecated 181 * createAnnotationRemapper method. 182 * @return either this object, or the given one. 183 */ orDeprecatedValue(final AnnotationVisitor deprecatedAnnotationVisitor)184 final AnnotationVisitor orDeprecatedValue(final AnnotationVisitor deprecatedAnnotationVisitor) { 185 if (deprecatedAnnotationVisitor.getClass() == getClass()) { 186 AnnotationRemapper deprecatedAnnotationRemapper = 187 (AnnotationRemapper) deprecatedAnnotationVisitor; 188 if (deprecatedAnnotationRemapper.api == api 189 && deprecatedAnnotationRemapper.av == av 190 && deprecatedAnnotationRemapper.remapper == remapper) { 191 return this; 192 } 193 } 194 return deprecatedAnnotationVisitor; 195 } 196 197 /** 198 * Maps an annotation attribute name with the remapper. Returns the original name unchanged if the 199 * descriptor of the annotation is {@literal null}. 200 * 201 * @param name the name of the annotation attribute. 202 * @return the new name of the annotation attribute. 203 */ mapAnnotationAttributeName(final String name)204 private String mapAnnotationAttributeName(final String name) { 205 if (descriptor == null) { 206 return name; 207 } 208 return remapper.mapAnnotationAttributeName(descriptor, name); 209 } 210 } 211