diff options
author | chibash <chiba@javassist.org> | 2017-06-01 22:46:39 +0900 |
---|---|---|
committer | chibash <chiba@javassist.org> | 2017-06-01 22:46:39 +0900 |
commit | dfd0733e1f73853453ff76086481ebec2e88a624 (patch) | |
tree | 267e33ac3f8c053f5a83d9fb934ca75c938c8a8a | |
parent | ab117a9fe31902167b9a74fee1982068e4c4d095 (diff) | |
download | javassist-dfd0733e1f73853453ff76086481ebec2e88a624.tar.gz javassist-dfd0733e1f73853453ff76086481ebec2e88a624.zip |
modifies CtClass#setModifiers() to correctly support inner classes.
-rw-r--r-- | javassist.jar | bin | 727192 -> 727665 bytes | |||
-rw-r--r-- | src/main/javassist/ClassPool.java | 2 | ||||
-rw-r--r-- | src/main/javassist/CtClassType.java | 45 | ||||
-rw-r--r-- | src/main/javassist/CtNewNestedClass.java | 67 | ||||
-rw-r--r-- | src/main/javassist/bytecode/InnerClassesAttribute.java | 18 | ||||
-rw-r--r-- | src/test/javassist/JvstTest5.java | 55 | ||||
-rw-r--r-- | src/test/test5/InnerModifier.java | 6 |
7 files changed, 117 insertions, 76 deletions
diff --git a/javassist.jar b/javassist.jar Binary files differindex 2f0ef0fb..98e6eebb 100644 --- a/javassist.jar +++ b/javassist.jar 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 {} +} |