@@ -215,9 +215,12 @@ public class AnnotationsAttribute extends AttributeInfo { | |||
/** | |||
* Removes an annotation by type. | |||
* After removing an annotation, if {@link #numAnnotations()} returns 0, | |||
* this annotations attribute has to be removed. | |||
* | |||
* @param type of annotation to remove | |||
* @return whether an annotation with the given type has been removed | |||
* @since 3.21 | |||
*/ | |||
public boolean removeAnnotation(String type) { | |||
Annotation[] annotations = getAnnotations(); |
@@ -231,16 +231,21 @@ public class AttributeInfo { | |||
return null; // no such attribute | |||
} | |||
static synchronized void remove(ArrayList list, String name) { | |||
static synchronized AttributeInfo remove(ArrayList list, String name) { | |||
if (list == null) | |||
return; | |||
return null; | |||
AttributeInfo removed = null; | |||
ListIterator iterator = list.listIterator(); | |||
while (iterator.hasNext()) { | |||
AttributeInfo ai = (AttributeInfo)iterator.next(); | |||
if (ai.getName().equals(name)) | |||
if (ai.getName().equals(name)) { | |||
iterator.remove(); | |||
removed = ai; | |||
} | |||
} | |||
return removed; | |||
} | |||
static void writeAll(ArrayList list, DataOutputStream out) |
@@ -761,6 +761,11 @@ public final class ClassFile { | |||
* Returns the attribute with the specified name. If there are multiple | |||
* attributes with that name, this method returns either of them. It | |||
* returns null if the specified attributed is not found. | |||
* | |||
* <p>An attribute name can be obtained by, for example, | |||
* {@link AnnotationsAttribute#visibleTab} or | |||
* {@link AnnotationsAttribute#invisibleTab}. | |||
* </p> | |||
* | |||
* @param name attribute name | |||
* @see #getAttributes() | |||
@@ -777,6 +782,17 @@ public final class ClassFile { | |||
return null; | |||
} | |||
/** | |||
* Removes an attribute with the specified name. | |||
* | |||
* @param name attribute name. | |||
* @return the removed attribute or null. | |||
* @since 3.21 | |||
*/ | |||
public AttributeInfo removeAttribute(String name) { | |||
return AttributeInfo.remove(attributes, name); | |||
} | |||
/** | |||
* Appends an attribute. If there is already an attribute with the same | |||
* name, the new one substitutes for it. |
@@ -231,6 +231,11 @@ public final class FieldInfo { | |||
* Returns the attribute with the specified name. | |||
* It returns null if the specified attribute is not found. | |||
* | |||
* <p>An attribute name can be obtained by, for example, | |||
* {@link AnnotationsAttribute#visibleTab} or | |||
* {@link AnnotationsAttribute#invisibleTab}. | |||
* </p> | |||
* | |||
* @param name attribute name | |||
* @see #getAttributes() | |||
*/ | |||
@@ -238,6 +243,17 @@ public final class FieldInfo { | |||
return AttributeInfo.lookup(attribute, name); | |||
} | |||
/** | |||
* Removes an attribute with the specified name. | |||
* | |||
* @param name attribute name. | |||
* @return the removed attribute or null. | |||
* @since 3.21 | |||
*/ | |||
public AttributeInfo removeAttribute(String name) { | |||
return AttributeInfo.remove(attribute, name); | |||
} | |||
/** | |||
* Appends an attribute. If there is already an attribute with | |||
* the same name, the new one substitutes for it. |
@@ -315,6 +315,11 @@ public class MethodInfo { | |||
* Returns the attribute with the specified name. If it is not found, this | |||
* method returns null. | |||
* | |||
* <p>An attribute name can be obtained by, for example, | |||
* {@link AnnotationsAttribute#visibleTab} or | |||
* {@link AnnotationsAttribute#invisibleTab}. | |||
* </p> | |||
* | |||
* @param name attribute name | |||
* @return an <code>AttributeInfo</code> object or null. | |||
* @see #getAttributes() | |||
@@ -323,6 +328,17 @@ public class MethodInfo { | |||
return AttributeInfo.lookup(attribute, name); | |||
} | |||
/** | |||
* Removes an attribute with the specified name. | |||
* | |||
* @param name attribute name. | |||
* @return the removed attribute or null. | |||
* @since 3.21 | |||
*/ | |||
public AttributeInfo removeAttribute(String name) { | |||
return AttributeInfo.remove(attribute, name); | |||
} | |||
/** | |||
* Appends an attribute. If there is already an attribute with the same | |||
* name, the new one substitutes for it. |
@@ -4,6 +4,7 @@ import java.lang.annotation.Annotation; | |||
import java.lang.reflect.TypeVariable; | |||
import javassist.bytecode.AnnotationsAttribute; | |||
import javassist.bytecode.AttributeInfo; | |||
import javassist.bytecode.ClassFile; | |||
import javassist.bytecode.ConstPool; | |||
import javassist.bytecode.InnerClassesAttribute; | |||
@@ -251,4 +252,36 @@ public class JvstTest5 extends JvstTestRoot { | |||
fail(); | |||
} catch (CannotCompileException e) {} | |||
} | |||
public void testRemoveAnnotatino() throws Exception { | |||
CtClass cc = sloader.get("test5.RemoveAnnotation"); | |||
AnnotationsAttribute aa | |||
= (AnnotationsAttribute)cc.getClassFile().getAttribute(AnnotationsAttribute.invisibleTag); | |||
assertTrue(aa.removeAnnotation("test5.RemoveAnno1")); | |||
AttributeInfo ai = cc.getClassFile().removeAttribute(AnnotationsAttribute.invisibleTag); | |||
assertEquals(ai.getName(), AnnotationsAttribute.invisibleTag); | |||
CtMethod foo = cc.getDeclaredMethod("foo"); | |||
AnnotationsAttribute aa2 = (AnnotationsAttribute)foo.getMethodInfo().getAttribute(AnnotationsAttribute.invisibleTag); | |||
assertTrue(aa2.removeAnnotation("test5.RemoveAnno1")); | |||
CtMethod bar = cc.getDeclaredMethod("bar"); | |||
AnnotationsAttribute aa3 = (AnnotationsAttribute)bar.getMethodInfo().getAttribute(AnnotationsAttribute.invisibleTag); | |||
assertFalse(aa3.removeAnnotation("test5.RemoveAnno1")); | |||
assertTrue(aa3.removeAnnotation("test5.RemoveAnno2")); | |||
AttributeInfo ai2 = bar.getMethodInfo().removeAttribute(AnnotationsAttribute.invisibleTag); | |||
assertEquals(ai2.getName(), AnnotationsAttribute.invisibleTag); | |||
CtMethod run = cc.getDeclaredMethod("run"); | |||
AttributeInfo ai3 = run.getMethodInfo().removeAttribute(AnnotationsAttribute.invisibleTag); | |||
assertNull(ai3); | |||
CtField baz = cc.getDeclaredField("baz"); | |||
AttributeInfo ai4 = baz.getFieldInfo().removeAttribute(AnnotationsAttribute.invisibleTag); | |||
assertEquals(ai4.getName(), AnnotationsAttribute.invisibleTag); | |||
cc.writeFile(); | |||
Object obj = make(cc.getName()); | |||
assertEquals(3, invoke(obj, "run")); | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
package test5; | |||
@interface RemoveAnno1 {} | |||
@interface RemoveAnno2 { | |||
int foo() default 3; | |||
} | |||
@RemoveAnno1 public class RemoveAnnotation { | |||
@RemoveAnno1 @RemoveAnno2(foo=4) | |||
int foo() { return 1; } | |||
@RemoveAnno2 | |||
int bar() { return 2; } | |||
@RemoveAnno1 | |||
int baz = 10; | |||
public int run() { return foo() + bar(); } | |||
} |