Browse Source

modifies CtClass#setModifiers() to correctly support inner classes.

tags/list
chibash 7 years ago
parent
commit
dfd0733e1f

BIN
javassist.jar View File


+ 1
- 1
src/main/javassist/ClassPool.java View File

@@ -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;
}

+ 37
- 8
src/main/javassist/CtClassType.java View File

@@ -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

+ 0
- 67
src/main/javassist/CtNewNestedClass.java View File

@@ -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;
}
}
}

+ 18
- 0
src/main/javassist/bytecode/InnerClassesAttribute.java View File

@@ -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);
@@ -156,6 +158,22 @@ public class InnerClassesAttribute extends AttributeInfo {
ByteArray.write16bit(flags, get(), nth * 8 + 8);
}

/**
* 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.
*

+ 55
- 0
src/test/javassist/JvstTest5.java View File

@@ -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);
}
}

+ 6
- 0
src/test/test5/InnerModifier.java View File

@@ -0,0 +1,6 @@
package test5;

public class InnerModifier {
protected class NonStatic {}
static class Static {}
}

Loading…
Cancel
Save