- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2003 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.
- *
- * 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.*;
- import javassist.compiler.Javac;
- import javassist.compiler.CompileError;
- import javassist.expr.ExprEditor;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.InputStream;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Hashtable;
- import java.util.List;
-
- /**
- * Class types.
- */
- class CtClassType extends CtClass {
- protected ClassPool classPool;
- protected boolean wasChanged;
- protected boolean wasFrozen;
- protected ClassFile classfile;
-
- private CtField fieldsCache;
- private CtConstructor constructorsCache;
- private CtConstructor classInitializerCache;
- private CtMethod methodsCache;
-
- private FieldInitLink fieldInitializers;
- private Hashtable hiddenMethods; // must be synchronous
- private int uniqueNumberSeed;
-
- CtClassType(String name, ClassPool cp) {
- super(name);
- classPool = cp;
- wasChanged = wasFrozen = false;
- classfile = null;
- fieldInitializers = null;
- hiddenMethods = null;
- uniqueNumberSeed = 0;
- eraseCache();
- }
-
- CtClassType(InputStream ins, ClassPool cp) throws IOException {
- this((String)null, cp);
- classfile = new ClassFile(new DataInputStream(ins));
- qualifiedName = classfile.getName();
- }
-
- protected void eraseCache() {
- fieldsCache = null;
- constructorsCache = null;
- classInitializerCache = null;
- methodsCache = null;
- }
-
- public ClassFile getClassFile2() {
- if (classfile != null)
- return classfile;
-
- try {
- byte[] b = classPool.readSource(getName());
- DataInputStream dis
- = new DataInputStream(new ByteArrayInputStream(b));
- return (classfile = new ClassFile(dis));
- }
- catch (NotFoundException e) {
- throw new RuntimeException(e.toString());
- }
- catch (IOException e) {
- throw new RuntimeException(e.toString());
- }
- catch (CannotCompileException e) {
- throw new RuntimeException(e.toString());
- }
- }
-
- public ClassPool getClassPool() { return classPool; }
-
- public boolean isModified() { return wasChanged; }
-
- public boolean isFrozen() { return wasFrozen; }
-
- void freeze() { wasFrozen = true; }
-
- void checkModify() throws RuntimeException {
- super.checkModify();
- wasChanged = true;
- }
-
- public void defrost() { wasFrozen = false; }
-
- public boolean subtypeOf(CtClass clazz) throws NotFoundException {
- int i;
- String cname = clazz.getName();
- if (this == clazz || getName().equals(cname))
- return true;
-
- ClassFile file = getClassFile2();
- String supername = file.getSuperclass();
- if (supername != null && supername.equals(cname))
- return true;
-
- String[] ifs = file.getInterfaces();
- int num = ifs.length;
- for (i = 0; i < num; ++i)
- if (ifs[i].equals(cname))
- return true;
-
- if (supername != null && classPool.get(supername).subtypeOf(clazz))
- return true;
-
- for (i = 0; i < num; ++i)
- if (classPool.get(ifs[i]).subtypeOf(clazz))
- return true;
-
- return false;
- }
-
- public void setName(String name) throws RuntimeException {
- String oldname = getName();
- if (name.equals(oldname))
- return;
-
- classPool.checkNotFrozen(name,
- "the class with the new name is frozen");
- ClassFile cf = getClassFile2();
- super.setName(name);
- cf.setName(name);
- eraseCache();
- classPool.classNameChanged(oldname, this);
- }
-
- public void replaceClassName(ClassMap classnames)
- throws RuntimeException
- {
- String oldClassName = getName();
- String newClassName
- = (String)classnames.get(Descriptor.toJvmName(oldClassName));
- if (newClassName != null) {
- newClassName = Descriptor.toJavaName(newClassName);
- classPool.checkNotFrozen(newClassName,
- "the class " + newClassName + " is frozen");
- }
-
- super.replaceClassName(classnames);
- ClassFile cf = getClassFile2();
- cf.renameClass(classnames);
- eraseCache();
-
- if (newClassName != null) {
- super.setName(newClassName);
- classPool.classNameChanged(oldClassName, this);
- }
- }
-
- public void replaceClassName(String oldname, String newname)
- throws RuntimeException
- {
- String thisname = getName();
- if (thisname.equals(oldname))
- setName(newname);
- else {
- super.replaceClassName(oldname, newname);
- getClassFile2().renameClass(oldname, newname);
- eraseCache();
- }
- }
-
- public boolean isInterface() {
- return Modifier.isInterface(getModifiers());
- }
-
- public int getModifiers() {
- int acc = getClassFile2().getAccessFlags();
- acc = AccessFlag.clear(acc, AccessFlag.SUPER);
- return AccessFlag.toModifier(acc);
- }
-
- public void setModifiers(int mod) {
- checkModify();
- int acc = AccessFlag.of(mod) | AccessFlag.SUPER;
- getClassFile2().setAccessFlags(acc);
- }
-
- public boolean subclassOf(CtClass superclass) {
- if (superclass == null)
- return false;
-
- String superName = superclass.getName();
- CtClass curr = this;
- try {
- while (curr != null) {
- if (curr.getName().equals(superName))
- return true;
-
- curr = curr.getSuperclass();
- }
- }
- catch (Exception ignored) {}
- return false;
- }
-
- public CtClass getSuperclass() throws NotFoundException {
- String supername = getClassFile2().getSuperclass();
- if (supername == null)
- return null;
- else
- return classPool.get(supername);
- }
-
- public void setSuperclass(CtClass clazz) throws CannotCompileException {
- checkModify();
- getClassFile2().setSuperclass(clazz.getName());
- }
-
- public CtClass[] getInterfaces() throws NotFoundException {
- String[] ifs = getClassFile2().getInterfaces();
- int num = ifs.length;
- CtClass[] ifc = new CtClass[num];
- for (int i = 0; i < num; ++i)
- ifc[i] = classPool.get(ifs[i]);
-
- return ifc;
- }
-
- public void setInterfaces(CtClass[] list) {
- checkModify();
- String[] ifs;
- if (list == null)
- ifs = new String[0];
- else {
- int num = list.length;
- ifs = new String[num];
- for (int i = 0; i < num; ++i)
- ifs[i] = list[i].getName();
- }
-
- getClassFile2().setInterfaces(ifs);
- }
-
- public void addInterface(CtClass anInterface) {
- checkModify();
- if (anInterface != null)
- getClassFile2().addInterface(anInterface.getName());
- }
-
- public CtField[] getFields() {
- ArrayList alist = new ArrayList();
- getFields(alist, this);
- return (CtField[])alist.toArray(new CtField[alist.size()]);
- }
-
- private static void getFields(ArrayList alist, CtClass cc) {
- int i, num;
- if (cc == null)
- return;
-
- try {
- getFields(alist, cc.getSuperclass());
- }
- catch (NotFoundException e) {}
-
- try {
- CtClass[] ifs = cc.getInterfaces();
- num = ifs.length;
- for (i = 0; i < num; ++i)
- getFields(alist, ifs[i]);
- }
- catch (NotFoundException e) {}
-
- CtField cf = ((CtClassType)cc).getFieldsCache();
- while (cf != null) {
- if (Modifier.isPublic(cf.getModifiers()))
- alist.add(cf);
-
- cf = cf.next;
- }
- }
-
- public CtField getField(String name) throws NotFoundException {
- try {
- return getDeclaredField(name);
- }
- catch (NotFoundException e) {}
-
- try {
- CtClass[] ifs = getInterfaces();
- int num = ifs.length;
- for (int i = 0; i < num; ++i)
- try {
- return ifs[i].getField(name);
- }
- catch (NotFoundException e) {}
- }
- catch (NotFoundException e) {}
-
- try {
- CtClass s = getSuperclass();
- if (s != null)
- return s.getField(name);
- }
- catch (NotFoundException e) {}
-
- throw new NotFoundException(name);
- }
-
- public CtField[] getDeclaredFields() {
- CtField cf = getFieldsCache();
- int num = CtField.count(cf);
- CtField[] cfs = new CtField[num];
- int i = 0;
- while (cf != null) {
- cfs[i++] = cf;
- cf = cf.next;
- }
-
- return cfs;
- }
-
- protected CtField getFieldsCache() {
- if (fieldsCache == null) {
- List list = getClassFile2().getFields();
- int n = list.size();
- for (int i = 0; i < n; ++i) {
- FieldInfo finfo = (FieldInfo)list.get(i);
- fieldsCache = CtField.append(fieldsCache,
- new CtField(finfo, this));
- }
- }
-
- return fieldsCache;
- }
-
- public CtField getDeclaredField(String name) throws NotFoundException {
- CtField cf = getFieldsCache();
- while (cf != null) {
- if (cf.getName().equals(name))
- return cf;
-
- cf = cf.next;
- }
-
- throw new NotFoundException(name);
- }
-
- public CtBehavior[] getDeclaredBehaviors() {
- CtConstructor cc = getConstructorsCache();
- CtMethod cm = getMethodsCache();
- int num = CtMethod.count(cm) + CtConstructor.count(cc);
- CtBehavior[] cb = new CtBehavior[num];
- int i = 0;
- while (cc != null) {
- cb[i++] = cc;
- cc = cc.next;
- }
-
- while (cm != null) {
- cb[i++] = cm;
- cm = cm.next;
- }
-
- return cb;
- }
-
- public CtConstructor[] getConstructors() {
- CtConstructor[] cons = getDeclaredConstructors();
- if (cons.length == 0)
- return cons;
-
- int n = 0;
- int i = cons.length;
- while (--i >= 0)
- if (Modifier.isPublic(cons[i].getModifiers()))
- ++n;
-
- CtConstructor[] result = new CtConstructor[n];
- n = 0;
- i = cons.length;
- while (--i >= 0) {
- CtConstructor c = cons[i];
- if (Modifier.isPublic(c.getModifiers()))
- result[n++] = c;
- }
-
- return result;
- }
-
- public CtConstructor getConstructor(String desc)
- throws NotFoundException
- {
- CtConstructor cc = getConstructorsCache();
- while (cc != null) {
- if (cc.getMethodInfo2().getDescriptor().equals(desc))
- return cc;
-
- cc = cc.next;
- }
-
- return super.getConstructor(desc);
- }
-
- public CtConstructor[] getDeclaredConstructors() {
- CtConstructor cc = getConstructorsCache();
- int num = CtConstructor.count(cc);
- CtConstructor[] ccs = new CtConstructor[num];
- int i = 0;
- while (cc != null) {
- ccs[i++] = cc;
- cc = cc.next;
- }
-
- return ccs;
- }
-
- protected CtConstructor getConstructorsCache() {
- if (constructorsCache == null) {
- List list = getClassFile2().getMethods();
- int n = list.size();
- for (int i = 0; i < n; ++i) {
- MethodInfo minfo = (MethodInfo)list.get(i);
- if (minfo.isConstructor())
- constructorsCache
- = CtConstructor.append(constructorsCache,
- new CtConstructor(minfo, this));
- }
- }
-
- return constructorsCache;
- }
-
- public CtConstructor getClassInitializer() {
- if (classInitializerCache == null) {
- List list = getClassFile2().getMethods();
- int n = list.size();
- for (int i = 0; i < n; ++i) {
- MethodInfo minfo = (MethodInfo)list.get(i);
- if (minfo.isStaticInitializer()) {
- classInitializerCache = new CtConstructor(minfo, this);
- break;
- }
- }
- }
-
- return classInitializerCache;
- }
-
- public CtMethod[] getMethods() {
- HashMap h = new HashMap();
- getMethods0(h, this);
- return (CtMethod[])h.values().toArray(new CtMethod[0]);
- }
-
- private static void getMethods0(HashMap h, CtClass cc) {
- try {
- CtClass[] ifs = cc.getInterfaces();
- int size = ifs.length;
- for (int i = 0; i < size; ++i)
- getMethods0(h, ifs[i]);
- }
- catch (NotFoundException e) {}
-
- try {
- CtClass s = cc.getSuperclass();
- if (s != null)
- getMethods0(h, s);
- }
- catch (NotFoundException e) {}
-
- if (cc instanceof CtClassType) {
- CtMethod cm = ((CtClassType)cc).getMethodsCache();
- while (cm != null) {
- if (Modifier.isPublic(cm.getModifiers()))
- h.put(cm, cm);
-
- cm = cm.next;
- }
- }
- }
-
- public CtMethod getMethod(String name, String desc)
- throws NotFoundException
- {
- CtMethod m = getMethod0(this, name, desc);
- if (m != null)
- return m;
- else
- throw new NotFoundException(name + "(..) is not found in "
- + getName());
- }
-
- private static CtMethod getMethod0(CtClass cc,
- String name, String desc) {
- if (cc instanceof CtClassType) {
- CtMethod cm = ((CtClassType)cc).getMethodsCache();
- while (cm != null) {
- if (cm.getName().equals(name)
- && cm.getMethodInfo2().getDescriptor().equals(desc))
- return cm;
-
- cm = cm.next;
- }
- }
-
- try {
- CtClass s = cc.getSuperclass();
- if (s != null) {
- CtMethod m = getMethod0(s, name, desc);
- if (m != null)
- return m;
- }
- }
- catch (NotFoundException e) {}
-
- try {
- CtClass[] ifs = cc.getInterfaces();
- int size = ifs.length;
- for (int i = 0; i < size; ++i) {
- CtMethod m = getMethod0(ifs[i], name, desc);
- if (m != null)
- return m;
- }
- }
- catch (NotFoundException e) {}
- return null;
- }
-
- public CtMethod[] getDeclaredMethods() {
- CtMethod cm = getMethodsCache();
- int num = CtMethod.count(cm);
- CtMethod[] cms = new CtMethod[num];
- int i = 0;
- while (cm != null) {
- cms[i++] = cm;
- cm = cm.next;
- }
-
- return cms;
- }
-
- public CtMethod getDeclaredMethod(String name) throws NotFoundException {
- CtMethod m = getMethodsCache();
- while (m != null) {
- if (m.getName().equals(name))
- return m;
-
- m = m.next;
- }
-
- throw new NotFoundException(name + "(..) is not found in "
- + getName());
- }
-
- public CtMethod getDeclaredMethod(String name, CtClass[] params)
- throws NotFoundException
- {
- String desc = Descriptor.ofParameters(params);
- CtMethod m = getMethodsCache();
- while (m != null) {
- if (m.getName().equals(name)
- && m.getMethodInfo2().getDescriptor().startsWith(desc))
- return m;
-
- m = m.next;
- }
-
- throw new NotFoundException(name + "(..) is not found in "
- + getName());
- }
-
- protected CtMethod getMethodsCache() {
- if (methodsCache == null) {
- List list = getClassFile2().getMethods();
- int n = list.size();
- for (int i = 0; i < n; ++i) {
- MethodInfo minfo = (MethodInfo)list.get(i);
- if (minfo.isMethod())
- methodsCache = CtMethod.append(methodsCache,
- new CtMethod(minfo, this));
- }
- }
-
- return methodsCache;
- }
-
- public void addField(CtField f, String init)
- throws CannotCompileException
- {
- addField(f, CtField.Initializer.byExpr(init));
- }
-
- public void addField(CtField f, CtField.Initializer init)
- throws CannotCompileException
- {
- checkModify();
- if (f.getDeclaringClass() != this)
- throw new CannotCompileException("cannot add");
-
- if (init == null)
- init = f.getInit();
-
- getFieldsCache();
- fieldsCache = CtField.append(fieldsCache, f);
- getClassFile2().addField(f.getFieldInfo2());
-
- if (init != null) {
- FieldInitLink fil = new FieldInitLink(f, init);
- FieldInitLink link = fieldInitializers;
- if (link == null)
- fieldInitializers = fil;
- else {
- while (link.next != null)
- link = link.next;
-
- link.next = fil;
- }
- }
- }
-
- public void addConstructor(CtConstructor c)
- throws CannotCompileException
- {
- checkModify();
- if (c.getDeclaringClass() != this)
- throw new CannotCompileException("cannot add");
-
- getConstructorsCache();
- constructorsCache = CtConstructor.append(constructorsCache, c);
- getClassFile2().addMethod(c.getMethodInfo2());
- }
-
- public void addMethod(CtMethod m) throws CannotCompileException {
- checkModify();
- if (m.getDeclaringClass() != this)
- throw new CannotCompileException("cannot add");
-
- getMethodsCache();
- methodsCache = CtMethod.append(methodsCache, m);
- getClassFile2().addMethod(m.getMethodInfo2());
- if ((m.getModifiers() & Modifier.ABSTRACT) != 0)
- setModifiers(getModifiers() | Modifier.ABSTRACT);
- }
-
- public byte[] getAttribute(String name) {
- AttributeInfo ai = getClassFile2().getAttribute(name);
- if (ai == null)
- return null;
- else
- return ai.get();
- }
-
- public void setAttribute(String name, byte[] data) {
- checkModify();
- ClassFile cf = getClassFile2();
- cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
- }
-
- public void instrument(CodeConverter converter)
- throws CannotCompileException
- {
- checkModify();
- ClassFile cf = getClassFile2();
- ConstPool cp = cf.getConstPool();
- List list = cf.getMethods();
- int n = list.size();
- for (int i = 0; i < n; ++i) {
- MethodInfo minfo = (MethodInfo)list.get(i);
- converter.doit(this, minfo, cp);
- }
- }
-
- public void instrument(ExprEditor editor)
- throws CannotCompileException
- {
- checkModify();
- ClassFile cf = getClassFile2();
- List list = cf.getMethods();
- int n = list.size();
- for (int i = 0; i < n; ++i) {
- MethodInfo minfo = (MethodInfo)list.get(i);
- editor.doit(this, minfo);
- }
- }
-
- void toBytecode(DataOutputStream out)
- throws CannotCompileException, IOException
- {
- ClassFile cf = getClassFile2();
- try {
- modifyClassConstructor(cf);
- modifyConstructors(cf);
- }
- catch (NotFoundException e) {
- throw new CannotCompileException(e);
- }
-
- wasFrozen = true;
- try {
- cf.write(out);
- out.flush();
- }
- catch (IOException e) {
- throw new CannotCompileException(e);
- }
- }
-
- protected void modifyClassConstructor(ClassFile cf)
- throws CannotCompileException, NotFoundException
- {
- Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
- Javac jv = new Javac(code, this);
- int stacksize = 0;
- boolean none = true;
- for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
- CtField f = fi.field;
- if (Modifier.isStatic(f.getModifiers())) {
- none = false;
- int s = fi.init.compileIfStatic(f.getType(), f.getName(),
- code, jv);
- if (stacksize < s)
- stacksize = s;
- }
- }
-
- if (none)
- return; // no initializer for static fileds.
-
- MethodInfo m = cf.getStaticInitializer();
- if (m == null) {
- code.add(Bytecode.RETURN);
- code.setMaxStack(stacksize);
- m = new MethodInfo(cf.getConstPool(),
- "<clinit>", "()V");
- m.setAccessFlags(AccessFlag.STATIC);
- m.setCodeAttribute(code.toCodeAttribute());
- cf.addMethod(m);
- }
- else {
- CodeAttribute codeAttr = m.getCodeAttribute();
- if (codeAttr == null)
- throw new CannotCompileException("empty <clinit>");
-
- try {
- CodeIterator it = codeAttr.iterator();
- int pos = it.insertEx(code.get());
- it.insert(code.getExceptionTable(), pos);
- int maxstack = codeAttr.getMaxStack();
- if (maxstack < stacksize)
- codeAttr.setMaxStack(stacksize);
- }
- catch (BadBytecode e) {
- throw new CannotCompileException(e);
- }
- }
- }
-
- protected void modifyConstructors(ClassFile cf)
- throws CannotCompileException, NotFoundException
- {
- if (fieldInitializers == null)
- return;
-
- ConstPool cp = cf.getConstPool();
- List list = cf.getMethods();
- int n = list.size();
- for (int i = 0; i < n; ++i) {
- MethodInfo minfo = (MethodInfo)list.get(i);
- if (minfo.isConstructor()) {
- CodeAttribute codeAttr = minfo.getCodeAttribute();
- if (codeAttr != null)
- try {
- Bytecode init = new Bytecode(cp, 0,
- codeAttr.getMaxLocals());
- CtClass[] params
- = Descriptor.getParameterTypes(
- minfo.getDescriptor(),
- classPool);
- int stacksize = makeFieldInitializer(init, params);
- insertAuxInitializer(codeAttr, init, stacksize);
- }
- catch (BadBytecode e) {
- throw new CannotCompileException(e);
- }
- }
- }
- }
-
- private static void insertAuxInitializer(CodeAttribute codeAttr,
- Bytecode initializer,
- int stacksize)
- throws BadBytecode
- {
- CodeIterator it = codeAttr.iterator();
- int index = it.skipSuperConstructor();
- if (index < 0) {
- index = it.skipThisConstructor();
- if (index >= 0)
- return; // this() is called.
-
- // Neither this() or super() is called.
- }
-
- int pos = it.insertEx(initializer.get());
- it.insert(initializer.getExceptionTable(), pos);
- int maxstack = codeAttr.getMaxStack();
- if (maxstack < stacksize)
- codeAttr.setMaxStack(stacksize);
- }
-
- private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
- throws CannotCompileException, NotFoundException
- {
- int stacksize = 0;
- Javac jv = new Javac(code, this);
- try {
- jv.recordParams(parameters, false);
- }
- catch (CompileError e) {
- throw new CannotCompileException(e);
- }
-
- for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
- CtField f = fi.field;
- if (!Modifier.isStatic(f.getModifiers())) {
- int s = fi.init.compile(f.getType(), f.getName(), code,
- parameters, jv);
- if (stacksize < s)
- stacksize = s;
- }
- }
-
- return stacksize;
- }
-
- // Methods used by CtNewWrappedMethod
-
- Hashtable getHiddenMethods() {
- if (hiddenMethods == null)
- hiddenMethods = new Hashtable();
-
- return hiddenMethods;
- }
-
- int getUniqueNumber() { return uniqueNumberSeed++; }
- }
-
- class FieldInitLink {
- FieldInitLink next;
- CtField field;
- CtField.Initializer init;
-
- FieldInitLink(CtField f, CtField.Initializer i) {
- next = null;
- field = f;
- init = i;
- }
- }
|