aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchibash <chiba@javassist.org>2017-06-01 22:46:39 +0900
committerchibash <chiba@javassist.org>2017-06-01 22:46:39 +0900
commitdfd0733e1f73853453ff76086481ebec2e88a624 (patch)
tree267e33ac3f8c053f5a83d9fb934ca75c938c8a8a
parentab117a9fe31902167b9a74fee1982068e4c4d095 (diff)
downloadjavassist-dfd0733e1f73853453ff76086481ebec2e88a624.tar.gz
javassist-dfd0733e1f73853453ff76086481ebec2e88a624.zip
modifies CtClass#setModifiers() to correctly support inner classes.
-rw-r--r--javassist.jarbin727192 -> 727665 bytes
-rw-r--r--src/main/javassist/ClassPool.java2
-rw-r--r--src/main/javassist/CtClassType.java45
-rw-r--r--src/main/javassist/CtNewNestedClass.java67
-rw-r--r--src/main/javassist/bytecode/InnerClassesAttribute.java18
-rw-r--r--src/test/javassist/JvstTest5.java55
-rw-r--r--src/test/test5/InnerModifier.java6
7 files changed, 117 insertions, 76 deletions
diff --git a/javassist.jar b/javassist.jar
index 2f0ef0fb..98e6eebb 100644
--- a/javassist.jar
+++ b/javassist.jar
Binary files differ
diff --git a/src/main/javassist/ClassPool.java b/src/main/javassist/ClassPool.java
index 4be35b5f..89a0067e 100644
--- a/src/main/javassist/ClassPool.java
+++ b/src/main/javassist/ClassPool.java
@@ -864,7 +864,7 @@ public class ClassPool {
*/
synchronized CtClass makeNestedClass(String classname) {
checkNotFrozen(classname);
- CtClass clazz = new CtNewNestedClass(classname, this, false, null);
+ CtClass clazz = new CtNewClass(classname, this, false, null);
cacheCtClass(classname, clazz, true);
return clazz;
}
diff --git a/src/main/javassist/CtClassType.java b/src/main/javassist/CtClassType.java
index 29aace81..b0a8819d 100644
--- a/src/main/javassist/CtClassType.java
+++ b/src/main/javassist/CtClassType.java
@@ -453,17 +453,46 @@ class CtClassType extends CtClass {
}
public void setModifiers(int mod) {
+ checkModify();
+ updateInnerEntry(mod, getName(), this, true);
ClassFile cf = getClassFile2();
- if (Modifier.isStatic(mod)) {
- int flags = cf.getInnerAccessFlags();
- if (flags != -1 && (flags & AccessFlag.STATIC) != 0)
- mod = mod & ~Modifier.STATIC;
- else
- throw new RuntimeException("cannot change " + getName() + " into a static class");
+ cf.setAccessFlags(AccessFlag.of(mod & ~Modifier.STATIC));
+ }
+
+ private static void updateInnerEntry(int newMod, String name, CtClass clazz, boolean outer) {
+ ClassFile cf = clazz.getClassFile2();
+ InnerClassesAttribute ica
+ = (InnerClassesAttribute)cf.getAttribute(InnerClassesAttribute.tag);
+ if (ica != null) {
+ // If the class is a static inner class, its modifier
+ // does not contain the static bit. Its inner class attribute
+ // contains the static bit.
+ int mod = newMod & ~Modifier.STATIC;
+ int i = ica.find(name);
+ if (i >= 0) {
+ int isStatic = ica.accessFlags(i) & AccessFlag.STATIC;
+ if (isStatic != 0 || !Modifier.isStatic(newMod)) {
+ clazz.checkModify();
+ ica.setAccessFlags(i, AccessFlag.of(mod) | isStatic);
+ String outName = ica.outerClass(i);
+ if (outName != null && outer)
+ try {
+ CtClass parent = clazz.getClassPool().get(outName);
+ updateInnerEntry(mod, name, parent, false);
+ }
+ catch (NotFoundException e) {
+ throw new RuntimeException("cannot find the declaring class: "
+ + outName);
+ }
+
+ return;
+ }
+ }
}
- checkModify();
- cf.setAccessFlags(AccessFlag.of(mod));
+ if (Modifier.isStatic(newMod))
+ throw new RuntimeException("cannot change " + Descriptor.toJavaName(name)
+ + " into a static class");
}
//@Override
diff --git a/src/main/javassist/CtNewNestedClass.java b/src/main/javassist/CtNewNestedClass.java
deleted file mode 100644
index 8177fde3..00000000
--- a/src/main/javassist/CtNewNestedClass.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later,
- * or the Apache License Version 2.0.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist;
-
-import javassist.bytecode.ClassFile;
-import javassist.bytecode.AccessFlag;
-import javassist.bytecode.InnerClassesAttribute;
-
-/**
- * A newly created public nested class.
- */
-class CtNewNestedClass extends CtNewClass {
- CtNewNestedClass(String realName, ClassPool cp, boolean isInterface,
- CtClass superclass) {
- super(realName, cp, isInterface, superclass);
- }
-
- /**
- * This method does not change the STATIC bit. The original value is kept.
- */
- public void setModifiers(int mod) {
- mod = mod & ~Modifier.STATIC;
- super.setModifiers(mod);
- updateInnerEntry(mod, getName(), this, true);
- }
-
- private static void updateInnerEntry(int mod, String name, CtClass clazz, boolean outer) {
- ClassFile cf = clazz.getClassFile2();
- InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
- InnerClassesAttribute.tag);
- if (ica == null)
- return;
-
- int n = ica.tableLength();
- for (int i = 0; i < n; i++)
- if (name.equals(ica.innerClass(i))) {
- int acc = ica.accessFlags(i) & AccessFlag.STATIC;
- ica.setAccessFlags(i, mod | acc);
- String outName = ica.outerClass(i);
- if (outName != null && outer)
- try {
- CtClass parent = clazz.getClassPool().get(outName);
- updateInnerEntry(mod, name, parent, false);
- }
- catch (NotFoundException e) {
- throw new RuntimeException("cannot find the declaring class: "
- + outName);
- }
-
- break;
- }
- }
-}
diff --git a/src/main/javassist/bytecode/InnerClassesAttribute.java b/src/main/javassist/bytecode/InnerClassesAttribute.java
index cf021791..b5b845d7 100644
--- a/src/main/javassist/bytecode/InnerClassesAttribute.java
+++ b/src/main/javassist/bytecode/InnerClassesAttribute.java
@@ -64,8 +64,10 @@ public class InnerClassesAttribute extends AttributeInfo {
/**
* Returns the class name indicated
* by <code>classes[nth].inner_class_info_index</code>.
+ * The class name is fully-qualified and separated by dot.
*
* @return null or the class name.
+ * @see ConstPool#getClassInfo(int)
*/
public String innerClass(int nth) {
int i = innerClassIndex(nth);
@@ -157,6 +159,22 @@ public class InnerClassesAttribute extends AttributeInfo {
}
/**
+ * Finds the entry for the given inner class.
+ *
+ * @param name the fully-qualified class name separated by dot and $.
+ * @return the index or -1 if not found.
+ * @since 3.22
+ */
+ public int find(String name) {
+ int n = tableLength();
+ for (int i = 0; i < n; i++)
+ if (name.equals(innerClass(i)))
+ return i;
+
+ return -1;
+ }
+
+ /**
* Appends a new entry.
*
* @param inner <code>inner_class_info_index</code>
diff --git a/src/test/javassist/JvstTest5.java b/src/test/javassist/JvstTest5.java
index 26474bb7..76d0c1a2 100644
--- a/src/test/javassist/JvstTest5.java
+++ b/src/test/javassist/JvstTest5.java
@@ -3,6 +3,7 @@ package javassist;
import java.lang.annotation.Annotation;
import java.lang.reflect.TypeVariable;
+import javassist.bytecode.AccessFlag;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.AttributeInfo;
import javassist.bytecode.ClassFile;
@@ -291,4 +292,58 @@ public class JvstTest5 extends JvstTestRoot {
Object obj = make(cc.getName());
assertEquals(3, invoke(obj, "run"));
}
+
+ public void testInnerClassModifiers() throws Exception {
+ CtClass cc = sloader.get("test5.InnerModifier$NonStatic");
+ try {
+ cc.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
+ fail();
+ }
+ catch (RuntimeException e) {
+ if (!e.getMessage().startsWith("cannot change "))
+ fail();
+ }
+
+ cc.setModifiers(Modifier.PUBLIC);
+ cc.writeFile();
+
+ assertEquals(Modifier.PUBLIC, cc.getModifiers());
+ InnerClassesAttribute ica = getInnerClassAttr(cc);
+ int i = ica.find("test5.InnerModifier$NonStatic");
+ assertTrue(i >= 0);
+ assertEquals(Modifier.PUBLIC, ica.accessFlags(i));
+
+ CtClass cc2 = sloader.get("test5.InnerModifier$Static");
+
+ InnerClassesAttribute ica3 = getInnerClassAttr(cc2);
+ int i3 = ica3.find("test5.InnerModifier$Static");
+ assertTrue(i3 >= 0);
+ assertEquals(AccessFlag.STATIC, ica3.accessFlags(i3));
+
+ cc2.setModifiers(Modifier.PROTECTED | Modifier.STATIC);
+ cc2.setModifiers(Modifier.PUBLIC);
+ cc2.writeFile();
+
+ assertEquals(Modifier.PUBLIC | Modifier.STATIC, cc2.getModifiers());
+ InnerClassesAttribute ica2 = getInnerClassAttr(cc2);
+ int i2 = ica2.find("test5.InnerModifier$Static");
+ assertTrue(i2 >= 0);
+ assertEquals(AccessFlag.PUBLIC | AccessFlag.STATIC, ica2.accessFlags(i2));
+
+ CtClass cc3 = cc.getDeclaringClass();
+ assertTrue(cc3.isModified());
+ cc3.writeFile();
+
+ InnerClassesAttribute ica4 = getInnerClassAttr(cc3);
+ int i4 = ica4.find("test5.InnerModifier$Static");
+ assertTrue(i4 >= 0);
+ assertEquals(AccessFlag.PUBLIC | AccessFlag.STATIC, ica4.accessFlags(i4));
+ int i5 = ica4.find("test5.InnerModifier$NonStatic");
+ assertTrue(i5 >= 0);
+ assertEquals(Modifier.PUBLIC, ica4.accessFlags(i5));
+ }
+
+ private InnerClassesAttribute getInnerClassAttr(CtClass cc) {
+ return (InnerClassesAttribute)cc.getClassFile2().getAttribute(InnerClassesAttribute.tag);
+ }
}
diff --git a/src/test/test5/InnerModifier.java b/src/test/test5/InnerModifier.java
new file mode 100644
index 00000000..5093e1fd
--- /dev/null
+++ b/src/test/test5/InnerModifier.java
@@ -0,0 +1,6 @@
+package test5;
+
+public class InnerModifier {
+ protected class NonStatic {}
+ static class Static {}
+}