diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main/javassist/CtClassType.java | 7 | ||||
-rw-r--r-- | src/main/javassist/bytecode/AnnotationsAttribute.java | 26 | ||||
-rw-r--r-- | src/main/javassist/bytecode/AttributeInfo.java | 11 | ||||
-rw-r--r-- | src/main/javassist/bytecode/ClassFile.java | 16 | ||||
-rw-r--r-- | src/main/javassist/bytecode/FieldInfo.java | 16 | ||||
-rw-r--r-- | src/main/javassist/bytecode/MethodInfo.java | 16 | ||||
-rw-r--r-- | src/main/javassist/bytecode/analysis/ControlFlow.java | 9 | ||||
-rw-r--r-- | src/test/javassist/JvstTest3.java | 3 | ||||
-rw-r--r-- | src/test/javassist/JvstTest5.java | 48 | ||||
-rw-r--r-- | src/test/test5/RemoveAnnotation.java | 20 |
10 files changed, 163 insertions, 9 deletions
diff --git a/src/main/javassist/CtClassType.java b/src/main/javassist/CtClassType.java index 627c15cf..29aace81 100644 --- a/src/main/javassist/CtClassType.java +++ b/src/main/javassist/CtClassType.java @@ -1400,10 +1400,11 @@ class CtClassType extends CtClass { int mod = m.getModifiers(); if ((getModifiers() & Modifier.INTERFACE) != 0) { - m.setModifiers(mod | Modifier.PUBLIC); - if ((mod & Modifier.ABSTRACT) == 0) + if (Modifier.isProtected(mod) || Modifier.isPrivate(mod)) throw new CannotCompileException( - "an interface method must be abstract: " + m.toString()); + "an interface method must be public: " + m.toString()); + + m.setModifiers(mod | Modifier.PUBLIC); } getMembers().addMethod(m); diff --git a/src/main/javassist/bytecode/AnnotationsAttribute.java b/src/main/javassist/bytecode/AnnotationsAttribute.java index d1d5b988..be69fe8b 100644 --- a/src/main/javassist/bytecode/AnnotationsAttribute.java +++ b/src/main/javassist/bytecode/AnnotationsAttribute.java @@ -214,6 +214,32 @@ 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(); + for (int i = 0; i < annotations.length; i++) { + if (annotations[i].getTypeName().equals(type)) { + Annotation[] newlist = new Annotation[annotations.length - 1]; + System.arraycopy(annotations, 0, newlist, 0, i); + if (i < annotations.length - 1) { + System.arraycopy(annotations, i + 1, newlist, i, + annotations.length - i - 1); + } + setAnnotations(newlist); + return true; + } + } + return false; + } + + /** * Parses the annotations and returns a data structure representing * that parsed annotations. Note that changes of the node values of the * returned tree are not reflected on the annotations represented by diff --git a/src/main/javassist/bytecode/AttributeInfo.java b/src/main/javassist/bytecode/AttributeInfo.java index 9a1ac16c..5fd73281 100644 --- a/src/main/javassist/bytecode/AttributeInfo.java +++ b/src/main/javassist/bytecode/AttributeInfo.java @@ -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) diff --git a/src/main/javassist/bytecode/ClassFile.java b/src/main/javassist/bytecode/ClassFile.java index 9e7729fd..e48b8e04 100644 --- a/src/main/javassist/bytecode/ClassFile.java +++ b/src/main/javassist/bytecode/ClassFile.java @@ -771,6 +771,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() @@ -788,6 +793,17 @@ public final class ClassFile { } /** + * 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. * diff --git a/src/main/javassist/bytecode/FieldInfo.java b/src/main/javassist/bytecode/FieldInfo.java index cbba0a85..0e2f76a5 100644 --- a/src/main/javassist/bytecode/FieldInfo.java +++ b/src/main/javassist/bytecode/FieldInfo.java @@ -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() */ @@ -239,6 +244,17 @@ public final class FieldInfo { } /** + * 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. * diff --git a/src/main/javassist/bytecode/MethodInfo.java b/src/main/javassist/bytecode/MethodInfo.java index 4b8c1c4d..72642268 100644 --- a/src/main/javassist/bytecode/MethodInfo.java +++ b/src/main/javassist/bytecode/MethodInfo.java @@ -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() @@ -324,6 +329,17 @@ public class MethodInfo { } /** + * 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. * diff --git a/src/main/javassist/bytecode/analysis/ControlFlow.java b/src/main/javassist/bytecode/analysis/ControlFlow.java index 736299cb..0bf76a3d 100644 --- a/src/main/javassist/bytecode/analysis/ControlFlow.java +++ b/src/main/javassist/bytecode/analysis/ControlFlow.java @@ -71,6 +71,8 @@ public class ControlFlow { return new Block[size]; } }.make(minfo); + if (basicBlocks == null) + basicBlocks = new Block[0]; int size = basicBlocks.length; int[] counters = new int[size]; for (int i = 0; i < size; i++) { @@ -97,6 +99,9 @@ public class ControlFlow { /** * Returns all the basic blocks in the method body. + * + * @return an array of basic blocks, the array has length 0 if + * the method doesn't have code. */ public Block[] basicBlocks() { return basicBlocks; @@ -133,7 +138,7 @@ public class ControlFlow { * For every array element <code>node</code>, its index in the * array is equivalent to <code>node.block().index()</code>. * - * @return an array of the tree nodes, or null if the method is abstract. + * @return an array of the tree nodes, or null if the method doesn't have code. * @see Node#block() * @see Block#index() */ @@ -179,7 +184,7 @@ public class ControlFlow { * For every array element <code>node</code>, its index in the * array is equivalent to <code>node.block().index()</code>. * - * @return an array of the tree nodes, or null if the method is abstract. + * @return an array of the tree nodes, or null if the method doesn't have code. * @see Node#block() * @see Block#index() */ diff --git a/src/test/javassist/JvstTest3.java b/src/test/javassist/JvstTest3.java index f399d077..056df5c2 100644 --- a/src/test/javassist/JvstTest3.java +++ b/src/test/javassist/JvstTest3.java @@ -1086,7 +1086,8 @@ public class JvstTest3 extends JvstTestRoot { CtMethod m3 = CtMethod.make("public void foo3() {}", cc); try { cc.addMethod(m3); - fail(); + if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_8) + fail(); } catch (CannotCompileException e) { // System.out.println(e); diff --git a/src/test/javassist/JvstTest5.java b/src/test/javassist/JvstTest5.java index 41b640c7..9d22c47c 100644 --- a/src/test/javassist/JvstTest5.java +++ b/src/test/javassist/JvstTest5.java @@ -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; @@ -241,5 +242,52 @@ public class JvstTest5 extends JvstTestRoot { cp.appendClassPath(new LoaderClassPath(new Loader())); assertNotNull(cp.get(Object.class.getName())); assertNotNull(cp.get(this.getClass().getName())); + + public void testAddDefaultMethod() throws Exception { + CtClass cc = sloader.makeInterface("test5.AddDefaultMethod"); + cc.addMethod(CtNewMethod.make("static int foo() { return 1; }", cc)); + cc.addMethod(CtNewMethod.make("public static int foo1() { return 1; }", cc)); + cc.addMethod(CtNewMethod.make("public int foo2() { return 1; }", cc)); + cc.addMethod(CtNewMethod.make("int foo3() { return 1; }", cc)); + try { + cc.addMethod(CtNewMethod.make("private int foo4() { return 1; }", cc)); + fail(); + } catch (CannotCompileException e) {} + try { + cc.addMethod(CtNewMethod.make("private static int foo5() { return 1; }", cc)); + 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")); } } diff --git a/src/test/test5/RemoveAnnotation.java b/src/test/test5/RemoveAnnotation.java new file mode 100644 index 00000000..97f75253 --- /dev/null +++ b/src/test/test5/RemoveAnnotation.java @@ -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(); } +} |