/*
* 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.bytecode;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import javassist.CannotCompileException;
/**
* ClassFile represents a Java .class file, which
* consists of a constant pool, methods, fields, and attributes.
*
*
For example,
*
* ClassFile cf = new ClassFile(false, "test.Foo", null);
* cf.setInterfaces(new String[] { "java.lang.Cloneable" });
*
* FieldInfo f = new FieldInfo(cf.getConstPool(), "width", "I");
* f.setAccessFlags(AccessFlag.PUBLIC);
* cf.addField(f);
*
* cf.write(new DataOutputStream(new FileOutputStream("Foo.class")));
*
* This code generates a class file Foo.class for the following class:
* package test;
* class Foo implements Cloneable {
* public int width;
* }
*
*
* @see FieldInfo
* @see MethodInfo
* @see ClassFileWriter
* @see javassist.CtClass#getClassFile()
* @see javassist.ClassPool#makeClass(ClassFile)
*/
public final class ClassFile {
int major, minor; // version number
ConstPool constPool;
int thisClass;
int accessFlags;
int superClass;
int[] interfaces;
Listjava.lang.StringBuilder.
* It is 50 (JDK 1.6)
* if the JVM supports java.util.zip.DeflaterInputStream.
* It is 51 (JDK 1.7)
* if the JVM supports java.lang.invoke.CallSite.
* It is 52 (JDK 1.8)
* if the JVM supports java.util.function.Function.
* It is 53 (JDK 1.9)
* if the JVM supports java.lang.reflect.Module.
* It is 54 (JDK 10)
* if the JVM supports java.util.List.copyOf(Collection).
* It is 55 (JDK 11)
* if the JVM supports java.util.Optional.isEmpty().
*/
public static final int MAJOR_VERSION;
static {
int ver = JAVA_3;
try {
Class.forName("java.lang.StringBuilder");
ver = JAVA_5;
Class.forName("java.util.zip.DeflaterInputStream");
ver = JAVA_6;
Class.forName("java.lang.invoke.CallSite", false, ClassLoader.getSystemClassLoader());
ver = JAVA_7;
Class.forName("java.util.function.Function");
ver = JAVA_8;
Class.forName("java.lang.Module");
ver = JAVA_9;
List.class.getMethod("copyOf", Collection.class);
ver = JAVA_10;
Class.forName("java.util.Optional").getMethod("isEmpty");
ver = JAVA_11;
}
catch (Throwable t) {}
MAJOR_VERSION = ver;
}
/**
* Constructs a class file from a byte stream.
*/
public ClassFile(DataInputStream in) throws IOException {
read(in);
}
/**
* Constructs a class file including no members.
*
* @param isInterface
* true if this is an interface. false if this is a class.
* @param classname
* a fully-qualified class name
* @param superclass
* a fully-qualified super class name or null.
*/
public ClassFile(boolean isInterface, String classname, String superclass) {
major = MAJOR_VERSION;
minor = 0; // JDK 1.3 or later
constPool = new ConstPool(classname);
thisClass = constPool.getThisClassInfo();
if (isInterface)
accessFlags = AccessFlag.INTERFACE | AccessFlag.ABSTRACT;
else
accessFlags = AccessFlag.SUPER;
initSuperclass(superclass);
interfaces = null;
fields = new ArrayListThe returned value is obtained from inner_class_access_flags
* of the entry representing this nested class itself
* in InnerClasses_attribute.
*/
public int getInnerAccessFlags() {
InnerClassesAttribute ica
= (InnerClassesAttribute)getAttribute(InnerClassesAttribute.tag);
if (ica == null)
return -1;
String name = getName();
int n = ica.tableLength();
for (int i = 0; i < n; ++i)
if (name.equals(ica.innerClass(i)))
return ica.accessFlags(i);
return -1;
}
/**
* Returns the class name.
*/
public String getName() {
return thisclassname;
}
/**
* Sets the class name. This method substitutes the new name for all
* occurrences of the old class name in the class file.
*/
public void setName(String name) {
renameClass(thisclassname, name);
}
/**
* Returns the super class name.
*/
public String getSuperclass() {
if (cachedSuperclass == null)
cachedSuperclass = constPool.getClassInfo(superClass);
return cachedSuperclass;
}
/**
* Returns the index of the constant pool entry representing the super
* class.
*/
public int getSuperclassId() {
return superClass;
}
/**
* Sets the super class.
*
*
* The new super class should inherit from the old super class. * This method modifies constructors so that they call constructors declared * in the new super class. */ public void setSuperclass(String superclass) throws CannotCompileException { if (superclass == null) superclass = "java.lang.Object"; try { this.superClass = constPool.addClassInfo(superclass); for (MethodInfo minfo:methods) minfo.setSuperclass(superclass); } catch (BadBytecode e) { throw new CannotCompileException(e); } cachedSuperclass = superclass; } /** * Replaces all occurrences of a class name in the class file. * *
* If class X is substituted for class Y in the class file, X and Y must
* have the same signature. If Y provides a method m(), X must provide it
* even if X inherits m() from the super class. If this fact is not
* guaranteed, the bytecode verifier may cause an error.
*
* @param oldname
* the replaced class name
* @param newname
* the substituted class name
*/
public final void renameClass(String oldname, String newname) {
if (oldname.equals(newname))
return;
if (oldname.equals(thisclassname))
thisclassname = newname;
oldname = Descriptor.toJvmName(oldname);
newname = Descriptor.toJvmName(newname);
constPool.renameClass(oldname, newname);
AttributeInfo.renameClass(attributes, oldname, newname);
for (MethodInfo minfo :methods) {
String desc = minfo.getDescriptor();
minfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
AttributeInfo.renameClass(minfo.getAttributes(), oldname, newname);
}
for (FieldInfo finfo:fields) {
String desc = finfo.getDescriptor();
finfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
AttributeInfo.renameClass(finfo.getAttributes(), oldname, newname);
}
}
/**
* Replaces all occurrences of several class names in the class file.
*
* @param classnames
* specifies which class name is replaced with which new name.
* Class names must be described with the JVM-internal
* representation like An attribute name can be obtained by, for example,
* {@link AnnotationsAttribute#visibleTag} or
* {@link AnnotationsAttribute#invisibleTag}.
* java/lang/Object.
* @see #renameClass(String,String)
*/
public final void renameClass(MapCtClass.getRefClasses() calls this method.
*/
public final void getRefClasses(MapFieldInfo.
* @see FieldInfo
*/
public ListMethodInfo.
* @see MethodInfo
*/
public ListList object
* is shared with this object. If you add a new attribute to the list,
* the attribute is also added to the classs file represented by this
* object. If you remove an attribute from the list, it is also removed
* from the class file.
*
* @return a list of AttributeInfo objects.
* @see AttributeInfo
*/
public List