Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
xapi.bytecode.CtClassType Maven / Gradle / Ivy
Go to download
This module exists solely to package all other gwt modules into a single
uber jar. This makes deploying to non-mavenized targets much easier.
Of course, you would be wise to inherit your dependencies individually;
the uber jar is intended for projects like collide,
which have complex configuration, and adding many jars would be a pain.
/*
* 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.
*
* MODIFIED BY James Nelson of We The Internet, 2013.
* Repackaged to avoid conflicts with different versions of Javassist,
* and modified Javassist APIs to make them more accessible to outside code.
*/
package xapi.bytecode;
import static xapi.source.X_Modifier.ABSTRACT;
import static xapi.source.X_Modifier.INTERFACE;
import static xapi.source.X_Modifier.PUBLIC;
import static xapi.source.X_Modifier.isPrivate;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import xapi.bytecode.CtMember.Cache;
import xapi.bytecode.annotation.Annotation;
import xapi.bytecode.annotation.AnnotationsAttribute;
import xapi.bytecode.attributes.AttributeInfo;
import xapi.bytecode.attributes.InnerClassesAttribute;
import xapi.bytecode.attributes.ParameterAnnotationsAttribute;
import xapi.source.X_Modifier;
@SuppressWarnings({"unchecked", "rawtypes"})
public class CtClassType extends CtClass {
ClassPool classPool;
boolean wasChanged;
boolean wasPruned;
boolean gcConstPool; // if true, the constant pool entries will be garbage
// collected.
ClassFile classfile;
byte[] rawClassfile; // backup storage
private WeakReference memberCache;
private Hashtable, ?> hiddenMethods; // must be synchronous
private int uniqueNumberSeed;
private boolean doPruning = ClassPool.doPruning;
private int getCount;
private static final int GET_THRESHOLD = 2; // see compress()
CtClassType(String name, ClassPool cp) {
super(name);
classPool = cp;
wasChanged = wasPruned = gcConstPool = false;
classfile = null;
rawClassfile = null;
memberCache = null;
hiddenMethods = null;
uniqueNumberSeed = 0;
getCount = 0;
}
public CtClassType(InputStream ins, ClassPool cp) throws IOException {
this((String) null, cp);
classfile = new ClassFile(new DataInputStream(ins));
qualifiedName = classfile.getName();
}
@Override
public ClassFile getClassFile2() {
ClassFile cfile = classfile;
if (cfile != null) {
return cfile;
}
classPool.compress();
if (rawClassfile != null) {
try {
classfile = new ClassFile(new DataInputStream(new ByteArrayInputStream(
rawClassfile)));
rawClassfile = null;
getCount = GET_THRESHOLD;
return classfile;
} catch (IOException e) {
throw new RuntimeException(e.toString(), e);
}
}
InputStream fin = null;
try {
fin = classPool.openClassfile(getName());
if (fin == null) {
throw new NotFoundException(getName());
}
fin = new BufferedInputStream(fin);
ClassFile cf = new ClassFile(new DataInputStream(fin));
if (!cf.getName().equals(qualifiedName)) {
throw new RuntimeException("cannot find " + qualifiedName + ": "
+ cf.getName() + " found in " + qualifiedName.replace('.', '/')
+ ".class");
}
classfile = cf;
return cf;
} catch (NotFoundException e) {
throw new RuntimeException(e.toString(), e);
} catch (IOException e) {
throw new RuntimeException(e.toString(), e);
} finally {
if (fin != null) {
try {
fin.close();
} catch (IOException e) {
}
}
}
}
/*
* Inherited from CtClass. Called by get() in ClassPool.
*
* @see javassist.CtClass#incGetCounter()
*
* @see #toBytecode(DataOutputStream)
*/
@Override
final void incGetCounter() {
++getCount;
}
/**
* Invoked from ClassPool#compress(). It releases the class files that have
* not been recently used if they are unmodified.
*/
@Override
void compress() {
if (getCount < GET_THRESHOLD) {
if (!isModified() && ClassPool.releaseUnmodifiedClassFile) {
removeClassFile();
} else if (isFrozen() && !wasPruned) {
saveClassFile();
}
}
getCount = 0;
}
/**
* Converts a ClassFile object into a byte array for saving memory space.
*/
private synchronized void saveClassFile() {
/*
* getMembers() and releaseClassFile() are also synchronized.
*/
if (classfile == null) {
return;
}
ByteArrayOutputStream barray = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(barray);
try {
classfile.write(out);
barray.close();
rawClassfile = barray.toByteArray();
classfile = null;
} catch (IOException e) {
}
}
private synchronized void removeClassFile() {
if (classfile != null && !isModified()) {
classfile = null;
}
}
@Override
public ClassPool getClassPool() {
return classPool;
}
void setClassPool(ClassPool cp) {
classPool = cp;
}
@Override
public URL getURL() throws NotFoundException {
URL url = classPool.find(getName());
if (url == null) {
throw new NotFoundException(getName());
} else {
return url;
}
}
@Override
public boolean isModified() {
return wasChanged;
}
@Override
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;
}
// @Override
@Override
public void setName(String name) throws RuntimeException {
String oldname = getName();
if (name.equals(oldname)) {
return;
}
// check this in advance although classNameChanged() below does.
classPool.checkNotFrozen(name);
ClassFile cf = getClassFile2();
super.setName(name);
cf.setName(name);
nameReplaced();
classPool.classNameChanged(oldname, this);
}
private void nameReplaced() {
CtMember.Cache cache = hasMemberCache();
if (cache != null) {
CtMember mth = cache.methodHead();
CtMember tail = cache.lastMethod();
while (mth != tail) {
mth = mth.next();
mth.nameReplaced();
}
}
}
/**
* Returns null if members are not cached.
*/
protected CtMember.Cache hasMemberCache() {
if (memberCache != null) {
return (CtMember.Cache) memberCache.get();
} else {
return null;
}
}
@Override
public boolean isInterface() {
return X_Modifier.isInterface(getModifiers());
}
@Override
public boolean isAnnotation() {
return X_Modifier.isAnnotation(getModifiers());
}
@Override
public boolean isEnum() {
return X_Modifier.isEnum(getModifiers());
}
@Override
public int getModifiers() {
ClassFile cf = getClassFile2();
int acc = cf.getAccessFlags();
acc = X_Modifier.clear(acc, X_Modifier.SUPER);
int inner = cf.getInnerAccessFlags();
if (inner != -1 && (inner & X_Modifier.STATIC) != 0) {
acc |= X_Modifier.STATIC;
}
return acc;
}
@Override
public CtClass[] getNestedClasses() throws NotFoundException {
ClassFile cf = getClassFile2();
InnerClassesAttribute ica = (InnerClassesAttribute) cf
.getAttribute(InnerClassesAttribute.tag);
if (ica == null) {
return new CtClass[0];
}
String thisName = cf.getName();
int n = ica.tableLength();
ArrayList list = new ArrayList(n);
for (int i = 0; i < n; i++) {
String outer = ica.outerClass(i);
/*
* If a nested class is local or anonymous, the outer_class_info_index is
* 0.
*/
if (outer == null || outer.equals(thisName)) {
String inner = ica.innerClass(i);
if (inner != null) {
list.add(classPool.get(inner));
}
}
}
return (CtClass[]) list.toArray(new CtClass[list.size()]);
}
@Override
public void setModifiers(int mod) {
ClassFile cf = getClassFile2();
if (X_Modifier.isStatic(mod)) {
int flags = cf.getInnerAccessFlags();
if (flags != -1 && (flags & X_Modifier.STATIC) != 0) {
mod = mod & ~X_Modifier.STATIC;
} else {
throw new RuntimeException("cannot change " + getName()
+ " into a static class");
}
}
checkModify();
cf.setAccessFlags(mod);
}
@Override
public boolean hasAnnotation(Class> clz) {
ClassFile cf = getClassFile2();
AnnotationsAttribute ainfo = (AnnotationsAttribute) cf
.getAttribute(AnnotationsAttribute.invisibleTag);
AnnotationsAttribute ainfo2 = (AnnotationsAttribute) cf
.getAttribute(AnnotationsAttribute.visibleTag);
return hasAnnotationType(clz, getClassPool(), ainfo, ainfo2);
}
static boolean hasAnnotationType(Class> clz, ClassPool cp,
AnnotationsAttribute a1, AnnotationsAttribute a2) {
Annotation[] anno1, anno2;
if (a1 == null) {
anno1 = null;
} else {
anno1 = a1.getAnnotations();
}
if (a2 == null) {
anno2 = null;
} else {
anno2 = a2.getAnnotations();
}
String typeName = clz.getName();
if (anno1 != null) {
for (int i = 0; i < anno1.length; i++) {
if (anno1[i].getTypeName().equals(typeName)) {
return true;
}
}
}
if (anno2 != null) {
for (int i = 0; i < anno2.length; i++) {
if (anno2[i].getTypeName().equals(typeName)) {
return true;
}
}
}
return false;
}
@Override
public Object getAnnotation(Class> clz) throws ClassNotFoundException {
ClassFile cf = getClassFile2();
AnnotationsAttribute ainfo = (AnnotationsAttribute) cf
.getAttribute(AnnotationsAttribute.invisibleTag);
AnnotationsAttribute ainfo2 = (AnnotationsAttribute) cf
.getAttribute(AnnotationsAttribute.visibleTag);
return getAnnotationType(clz, getClassPool(), ainfo, ainfo2);
}
static Object getAnnotationType(Class> clz, ClassPool cp,
AnnotationsAttribute a1, AnnotationsAttribute a2)
throws ClassNotFoundException {
Annotation[] anno1, anno2;
if (a1 == null) {
anno1 = null;
} else {
anno1 = a1.getAnnotations();
}
if (a2 == null) {
anno2 = null;
} else {
anno2 = a2.getAnnotations();
}
String typeName = clz.getName();
if (anno1 != null) {
for (int i = 0; i < anno1.length; i++) {
if (anno1[i].getTypeName().equals(typeName)) {
return toAnnoType(anno1[i], cp);
}
}
}
if (anno2 != null) {
for (int i = 0; i < anno2.length; i++) {
if (anno2[i].getTypeName().equals(typeName)) {
return toAnnoType(anno2[i], cp);
}
}
}
return null;
}
@Override
public Object[] getAnnotations() throws ClassNotFoundException {
return getAnnotations(false);
}
@Override
public Object[] getAvailableAnnotations() {
try {
return getAnnotations(true);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unexpected exception ", e);
}
}
private Object[] getAnnotations(boolean ignoreNotFound)
throws ClassNotFoundException {
ClassFile cf = getClassFile2();
AnnotationsAttribute ainfo = (AnnotationsAttribute) cf
.getAttribute(AnnotationsAttribute.invisibleTag);
AnnotationsAttribute ainfo2 = (AnnotationsAttribute) cf
.getAttribute(AnnotationsAttribute.visibleTag);
return toAnnotationType(ignoreNotFound, getClassPool(), ainfo, ainfo2);
}
static Object[] toAnnotationType(boolean ignoreNotFound, ClassPool cp,
AnnotationsAttribute a1, AnnotationsAttribute a2)
throws ClassNotFoundException {
Annotation[] anno1, anno2;
int size1, size2;
if (a1 == null) {
anno1 = null;
size1 = 0;
} else {
anno1 = a1.getAnnotations();
size1 = anno1.length;
}
if (a2 == null) {
anno2 = null;
size2 = 0;
} else {
anno2 = a2.getAnnotations();
size2 = anno2.length;
}
if (!ignoreNotFound) {
Object[] result = new Object[size1 + size2];
for (int i = 0; i < size1; i++) {
result[i] = toAnnoType(anno1[i], cp);
}
for (int j = 0; j < size2; j++) {
result[j + size1] = toAnnoType(anno2[j], cp);
}
return result;
} else {
ArrayList annotations = new ArrayList();
for (int i = 0; i < size1; i++) {
try {
annotations.add(toAnnoType(anno1[i], cp));
} catch (ClassNotFoundException e) {
}
}
for (int j = 0; j < size2; j++) {
try {
annotations.add(toAnnoType(anno2[j], cp));
} catch (ClassNotFoundException e) {
}
}
return annotations.toArray();
}
}
static Object[][] toAnnotationType(boolean ignoreNotFound, ClassPool cp,
ParameterAnnotationsAttribute a1, ParameterAnnotationsAttribute a2,
MethodInfo minfo) throws ClassNotFoundException {
int numParameters = 0;
if (a1 != null) {
numParameters = a1.numParameters();
} else if (a2 != null) {
numParameters = a2.numParameters();
} else {
numParameters = Descriptor.numOfParameters(minfo.getDescriptor());
}
Object[][] result = new Object[numParameters][];
for (int i = 0; i < numParameters; i++) {
Annotation[] anno1, anno2;
int size1, size2;
if (a1 == null) {
anno1 = null;
size1 = 0;
} else {
anno1 = a1.getAnnotations()[i];
size1 = anno1.length;
}
if (a2 == null) {
anno2 = null;
size2 = 0;
} else {
anno2 = a2.getAnnotations()[i];
size2 = anno2.length;
}
if (!ignoreNotFound) {
result[i] = new Object[size1 + size2];
for (int j = 0; j < size1; ++j) {
result[i][j] = toAnnoType(anno1[j], cp);
}
for (int j = 0; j < size2; ++j) {
result[i][j + size1] = toAnnoType(anno2[j], cp);
}
} else {
ArrayList annotations = new ArrayList();
for (int j = 0; j < size1; j++) {
try {
annotations.add(toAnnoType(anno1[j], cp));
} catch (ClassNotFoundException e) {
}
}
for (int j = 0; j < size2; j++) {
try {
annotations.add(toAnnoType(anno2[j], cp));
} catch (ClassNotFoundException e) {
}
}
result[i] = annotations.toArray();
}
}
return result;
}
private static Object toAnnoType(Annotation anno, ClassPool cp)
throws ClassNotFoundException {
try {
ClassLoader cl = cp.getClassLoader();
return anno.toAnnotationType(cl, cp);
} catch (ClassNotFoundException e) {
ClassLoader cl2 = cp.getClass().getClassLoader();
return anno.toAnnotationType(cl2, cp);
}
}
@Override
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;
}
@Override
public CtClass getSuperclass() throws NotFoundException {
String supername = getClassFile2().getSuperclass();
if (supername == null) {
return null;
} else {
return classPool.get(supername);
}
}
@Override
public void setSuperclass(CtClass clazz) {
checkModify();
if (isInterface()) {
addInterface(clazz);
} else {
getClassFile2().setSuperclass(clazz.getName());
}
}
@Override
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;
}
@Override
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);
}
@Override
public void addInterface(CtClass anInterface) {
checkModify();
if (anInterface != null) {
getClassFile2().addInterface(anInterface.getName());
}
}
@Override
public CtClass getDeclaringClass() throws NotFoundException {
ClassFile cf = getClassFile2();
InnerClassesAttribute ica = (InnerClassesAttribute) cf
.getAttribute(InnerClassesAttribute.tag);
if (ica == null) {
return null;
}
String name = getName();
int n = ica.tableLength();
for (int i = 0; i < n; ++i) {
if (name.equals(ica.innerClass(i))) {
String outName = ica.outerClass(i);
if (outName != null) {
return classPool.get(outName);
} else {
// we don't support anonymous or local classes
// // maybe anonymous or local class.
// EnclosingMethodAttribute ema
// = (EnclosingMethodAttribute)cf.getAttribute(
// EnclosingMethodAttribute.tag);
// if (ema != null)
// return classPool.get(ema.className());
}
}
}
return null;
}
//
// @Override
// public CtMethod getEnclosingMethod() throws NotFoundException {
// ClassFile cf = getClassFile2();
// EnclosingMethodAttribute ema
// = (EnclosingMethodAttribute)cf.getAttribute(
// EnclosingMethodAttribute.tag);
// if (ema != null) {
// CtClass enc = classPool.get(ema.className());
// return enc.getMethod(ema.methodName(), ema.methodDescriptor());
// }
//
// return null;
// }
@Override
public CtClass makeNestedClass(String name, boolean isStatic) {
if (!isStatic) {
throw new RuntimeException("sorry, only nested static class is supported");
}
checkModify();
CtClass c = classPool.makeNestedClass(getName() + "$" + name);
ClassFile cf = getClassFile2();
ClassFile cf2 = c.getClassFile2();
InnerClassesAttribute ica = (InnerClassesAttribute) cf
.getAttribute(InnerClassesAttribute.tag);
if (ica == null) {
ica = new InnerClassesAttribute(cf.getConstPool());
cf.addAttribute(ica);
}
ica.append(c.getName(), this.getName(), name,
(cf2.getAccessFlags() & ~X_Modifier.SUPER) | X_Modifier.STATIC);
cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
return c;
}
private static boolean isPubCons(CtConstructor cons) {
return !X_Modifier.isPrivate(cons.getModifiers()) && cons.isConstructor();
}
@Override
public CtConstructor getConstructor(String desc) throws NotFoundException {
CtMember.Cache memCache = getMembers();
CtMember cons = memCache.consHead();
CtMember consTail = memCache.lastCons();
while (cons != consTail) {
cons = cons.next();
CtConstructor cc = (CtConstructor) cons;
if (cc.getMethodInfo2().getDescriptor().equals(desc)
&& cc.isConstructor()) {
return cc;
}
}
return super.getConstructor(desc);
}
@Override
public CtConstructor[] getDeclaredConstructors() {
CtMember.Cache memCache = getMembers();
CtMember cons = memCache.consHead();
CtMember consTail = memCache.lastCons();
int n = 0;
CtMember mem = cons;
while (mem != consTail) {
mem = mem.next();
CtConstructor cc = (CtConstructor) mem;
if (cc.isConstructor()) {
n++;
}
}
CtConstructor[] result = new CtConstructor[n];
int i = 0;
mem = cons;
while (mem != consTail) {
mem = mem.next();
CtConstructor cc = (CtConstructor) mem;
if (cc.isConstructor()) {
result[i++] = cc;
}
}
return result;
}
@Override
public CtConstructor getClassInitializer() {
CtMember.Cache memCache = getMembers();
CtMember cons = memCache.consHead();
CtMember consTail = memCache.lastCons();
while (cons != consTail) {
cons = cons.next();
CtConstructor cc = (CtConstructor) cons;
if (cc.isClassInitializer()) {
return cc;
}
}
return null;
}
@Override
public CtMethod[] getMethods() {
HashMap h = new HashMap();
getMethods0(h, this);
return (CtMethod[]) h.values().toArray(new CtMethod[h.size()]);
}
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) {
CtMember.Cache memCache = ((CtClassType) cc).getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();
while (mth != mthTail) {
mth = mth.next();
if (!X_Modifier.isPrivate(mth.getModifiers())) {
h.put(((CtMethod) mth).getStringRep(), mth);
}
}
}
}
protected synchronized CtMember.Cache getMembers() {
CtMember.Cache cache = null;
if (memberCache == null
|| (cache = (CtMember.Cache) memberCache.get()) == null) {
cache = new CtMember.Cache(this);
makeFieldCache(cache);
makeBehaviorCache(cache);
memberCache = new WeakReference(cache);
}
return cache;
}
private void makeFieldCache(CtMember.Cache cache) {
List> list = getClassFile2().getFields();
int n = list.size();
for (int i = 0; i < n; ++i) {
FieldInfo finfo = (FieldInfo)list.get(i);
CtField newField = new CtField(finfo, this);
cache.addField(newField);
}
}
private void makeBehaviorCache(CtMember.Cache cache) {
List> list = getClassFile2().getMethods();
int n = list.size();
for (int i = 0; i < n; ++i) {
MethodInfo minfo = (MethodInfo) list.get(i);
if (minfo.isMethod()) {
CtMethod newMethod = new CtMethod(minfo, this);
cache.addMethod(newMethod);
} else {
// TODO do something with ctors
// CtConstructor newCons = new CtConstructor(minfo, this);
// cache.addConstructor(newCons);
}
}
}
@Override
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) {
CtMember.Cache memCache = ((CtClassType) cc).getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();
while (mth != mthTail) {
mth = mth.next();
if (mth.getName().equals(name)
&& ((CtMethod) mth).getMethodInfo2().getDescriptor().equals(desc)) {
return (CtMethod) mth;
}
}
}
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;
}
@Override
public CtMethod[] getDeclaredMethods() {
CtMember.Cache memCache = getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();
int num = CtMember.Cache.count(mth, mthTail);
CtMethod[] cms = new CtMethod[num];
int i = 0;
while (mth != mthTail) {
mth = mth.next();
cms[i++] = (CtMethod) mth;
}
return cms;
}
@Override
public CtMethod getDeclaredMethod(String name) throws NotFoundException {
CtMember.Cache memCache = getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();
while (mth != mthTail) {
mth = mth.next();
if (mth.getName().equals(name)) {
return (CtMethod) mth;
}
}
throw new NotFoundException(name + "(..) is not found in " + getName());
}
@Override
public CtMethod getDeclaredMethod(String name, CtClass[] params)
throws NotFoundException {
String desc = Descriptor.ofParameters(params);
CtMember.Cache memCache = getMembers();
CtMember mth = memCache.methodHead();
CtMember mthTail = memCache.lastMethod();
while (mth != mthTail) {
mth = mth.next();
if (mth.getName().equals(name)
&& ((CtMethod) mth).getMethodInfo2().getDescriptor().startsWith(desc)) {
return (CtMethod) mth;
}
}
throw new NotFoundException(name + "(..) is not found in " + getName());
}
@Override
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) {}
CtMember.Cache memCache = ((CtClassType)cc).getMembers();
CtMember field = memCache.fieldHead();
CtMember tail = memCache.lastField();
while (field != tail) {
field = field.next();
if (!isPrivate(field.getModifiers())) {
alist.add(field);
}
}
}
@Override
public CtField getField(String name) throws NotFoundException {
return getField(name, null);
}
public CtField getField(String name, String desc) throws NotFoundException {
CtField f = getField2(name, desc);
return checkGetField(f, name, desc);
}
private CtField checkGetField(CtField f, String name, String desc)
throws NotFoundException
{
if (f == null) {
String msg = "field: " + name;
if (desc != null) {
msg += " type " + desc;
}
throw new NotFoundException(msg + " in " + getName());
} else {
return f;
}
}
@Override
CtField getField2(String name, String desc) {
CtField df = getDeclaredField2(name, desc);
if (df != null) {
return df;
}
try {
CtClass[] ifs = getInterfaces();
int num = ifs.length;
for (int i = 0; i < num; ++i) {
CtField f = ifs[i].getField2(name, desc);
if (f != null) {
return f;
}
}
CtClass s = getSuperclass();
if (s != null) {
return s.getField2(name, desc);
}
}
catch (NotFoundException e) {}
return null;
}
@Override
public CtField[] getDeclaredFields() {
CtMember.Cache memCache = getMembers();
CtMember field = memCache.fieldHead();
CtMember tail = memCache.lastField();
int num = CtMember.Cache.count(field, tail);
CtField[] cfs = new CtField[num];
int i = 0;
while (field != tail) {
field = field.next();
cfs[i++] = (CtField)field;
}
return cfs;
}
@Override
public CtField getDeclaredField(String name) throws NotFoundException {
return getDeclaredField(name, null);
}
public CtField getDeclaredField(String name, String desc) throws NotFoundException {
CtField f = getDeclaredField2(name, desc);
return checkGetField(f, name, desc);
}
private CtField getDeclaredField2(String name, String desc) {
CtMember.Cache memCache = getMembers();
CtMember field = memCache.fieldHead();
CtMember tail = memCache.lastField();
while (field != tail) {
field = field.next();
if (field.getName().equals(name)
&& (desc == null || desc.equals(field.getSignature()))) {
return (CtField)field;
}
}
return null;
}
@Override
public void removeField(CtField f) throws NotFoundException {
checkModify();
FieldInfo fi = f.getFieldInfo2();
ClassFile cf = getClassFile2();
if (cf.getFields().remove(fi)) {
getMembers().remove(f);
gcConstPool = true;
} else {
throw new NotFoundException(f.toString());
}
}
@Override
public void addConstructor(CtConstructor c)
throws CannotCompileException
{
checkModify();
if (c.getDeclaringClass() != this) {
throw new CannotCompileException("cannot add");
}
getMembers().addConstructor(c);
getClassFile2().addMethod(c.getMethodInfo2());
}
@Override
public void removeConstructor(CtConstructor m) throws NotFoundException {
checkModify();
MethodInfo mi = m.getMethodInfo2();
ClassFile cf = getClassFile2();
if (cf.getMethods().remove(mi)) {
getMembers().remove(m);
gcConstPool = true;
} else {
throw new NotFoundException(m.toString());
}
}
@Override
public void addMethod(CtMethod m) throws CannotCompileException {
checkModify();
if (m.getDeclaringClass() != this) {
throw new CannotCompileException("bad declaring class");
}
int mod = m.getModifiers();
if ((getModifiers() & INTERFACE) != 0) {
m.setModifiers(mod | PUBLIC);
if ((mod & ABSTRACT) == 0) {
throw new CannotCompileException(
"an interface method must be abstract: " + m.toString());
}
}
getMembers().addMethod(m);
getClassFile2().addMethod(m.getMethodInfo2());
if ((mod & ABSTRACT) != 0) {
setModifiers(getModifiers() | ABSTRACT);
}
}
@Override
public void removeMethod(CtMethod m) throws NotFoundException {
checkModify();
MethodInfo mi = m.getMethodInfo2();
ClassFile cf = getClassFile2();
if (cf.getMethods().remove(mi)) {
getMembers().remove(m);
gcConstPool = true;
} else {
throw new NotFoundException(m.toString());
}
}
@Override
public byte[] getAttribute(String name) {
AttributeInfo ai = getClassFile2().getAttribute(name);
if (ai == null) {
return null;
} else {
return ai.get();
}
}
@Override
public void setAttribute(String name, byte[] data) {
checkModify();
ClassFile cf = getClassFile2();
cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
}
/**
* @see javassist.CtClass#prune()
* @see javassist.CtClass#stopPruning(boolean)
*/
@Override
public void prune() {
if (wasPruned) {
return;
}
wasPruned = true;
getClassFile2().prune();
}
@Override
public void rebuildClassFile() {
gcConstPool = true;
}
// @Override
// public void toBytecode(DataOutputStream out)
// throws CannotCompileException, IOException
// {
// try {
// if (isModified()) {
// checkPruned("toBytecode");
// ClassFile cf = getClassFile2();
// if (gcConstPool) {
// cf.compact();
// gcConstPool = false;
// }
//
// modifyClassConstructor(cf);
// modifyConstructors(cf);
// cf.write(out);
// out.flush();
// fieldInitializers = null;
// if (doPruning) {
// // to save memory
// cf.prune();
// wasPruned = true;
// }
// }
// else {
// classPool.writeClassfile(getName(), out);
// // to save memory
// // classfile = null;
// }
//
// getCount = 0;
// wasFrozen = true;
// }
// catch (NotFoundException e) {
// throw new CannotCompileException(e);
// }
// catch (IOException e) {
// throw new CannotCompileException(e);
// }
// }
@Override
public boolean stopPruning(boolean stop) {
boolean prev = !doPruning;
doPruning = !stop;
return prev;
}
// private void modifyClassConstructor(ClassFile cf)
// throws CannotCompileException, NotFoundException
// {
// if (fieldInitializers == null)
// return;
//
// Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
// Javac jv = new Javac(code, this);
// int stacksize = 0;
// boolean doInit = false;
// for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
// CtField f = fi.field;
// if (AccessFlagisStatic(f.getModifiers())) {
// doInit = true;
// int s = fi.init.compileIfStatic(f.getType(), f.getName(),
// code, jv);
// if (stacksize < s)
// stacksize = s;
// }
// }
//
// if (doInit) // need an initializer for static fileds.
// modifyClassConstructor(cf, code, stacksize, 0);
// }
//
// private void modifyClassConstructor(ClassFile cf, Bytecode code,
// int stacksize, int localsize)
// throws CannotCompileException
// {
// MethodInfo m = cf.getStaticInitializer();
// if (m == null) {
// code.add(Bytecode.RETURN);
// code.setMaxStack(stacksize);
// code.setMaxLocals(localsize);
// m = new MethodInfo(cf.getConstPool(), "", "()V");
// m.setAccessFlags(AccessFlag.STATIC);
// m.setCodeAttribute(code.toCodeAttribute());
// cf.addMethod(m);
// CtMember.Cache cache = hasMemberCache();
// if (cache != null)
// cache.addConstructor(new CtConstructor(m, this));
// }
// else {
// CodeAttribute codeAttr = m.getCodeAttribute();
// if (codeAttr == null)
// throw new CannotCompileException("empty ");
//
// 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);
//
// int maxlocals = codeAttr.getMaxLocals();
// if (maxlocals < localsize)
// codeAttr.setMaxLocals(localsize);
// }
// catch (BadBytecode e) {
// throw new CannotCompileException(e);
// }
// }
//
// try {
// m.rebuildStackMapIf6(classPool, cf);
// }
// catch (BadBytecode e) {
// throw new CannotCompileException(e);
// }
// }
//
// private 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);
// minfo.rebuildStackMapIf6(classPool, cf);
// }
// 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 (!AccessFlagisStatic(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++;
}
@Override
public String makeUniqueName(String prefix) {
HashMap table = new HashMap();
makeMemberList(table);
Set keys = table.keySet();
String[] methods = new String[keys.size()];
keys.toArray(methods);
if (notFindInArray(prefix, methods)) {
return prefix;
}
int i = 100;
String name;
do {
if (i > 999) {
throw new RuntimeException("too many unique name");
}
name = prefix + i++;
} while (!notFindInArray(name, methods));
return name;
}
private static boolean notFindInArray(String prefix, String[] values) {
int len = values.length;
for (int i = 0; i < len; i++) {
if (values[i].startsWith(prefix)) {
return false;
}
}
return true;
}
private void makeMemberList(HashMap table) {
int mod = getModifiers();
if (X_Modifier.isAbstract(mod) || X_Modifier.isInterface(mod)) {
try {
CtClass[] ifs = getInterfaces();
int size = ifs.length;
for (int i = 0; i < size; i++) {
CtClass ic = ifs[i];
if (ic != null && ic instanceof CtClassType) {
((CtClassType) ic).makeMemberList(table);
}
}
} catch (NotFoundException e) {
}
}
try {
CtClass s = getSuperclass();
if (s != null && s instanceof CtClassType) {
((CtClassType) s).makeMemberList(table);
}
} catch (NotFoundException e) {
}
List> list = getClassFile2().getMethods();
int n = list.size();
for (int i = 0; i < n; i++) {
MethodInfo minfo = (MethodInfo) list.get(i);
table.put(minfo.getName(), this);
}
list = getClassFile2().getFields();
n = list.size();
for (int i = 0; i < n; i++) {
FieldInfo finfo = (FieldInfo) list.get(i);
table.put(finfo.getName(), this);
}
}
}
// class FieldInitLink {
// FieldInitLink next;
// CtField field;
// CtField.Initializer init;
//
// FieldInitLink(CtField f, CtField.Initializer i) {
// next = null;
// field = f;
// init = i;
// }
// }