com.caucho.bytecode.JavaClass Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.bytecode;
import com.caucho.vfs.ReadStream;
import com.caucho.vfs.Vfs;
import com.caucho.vfs.WriteStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Represents a java class.
*/
public class JavaClass extends JClass {
static private final Logger log
= Logger.getLogger(JavaClass.class.getName());
public static final int MAGIC = 0xcafebabe;
public static final int ACC_PUBLIC = 0x0001;
public static final int ACC_PRIVATE = 0x0002;
public static final int ACC_PROTECTED = 0x0004;
public static final int ACC_STATIC = 0x0008;
public static final int ACC_FINAL = 0x0010;
public static final int ACC_SUPER = 0x0020;
private JavaClassLoader _loader;
private URL _url;
private int _major;
private int _minor;
private ConstantPool _constantPool = new ConstantPool();
private int _accessFlags;
private String _thisClass;
private String _superClass;
private ArrayList _interfaces = new ArrayList();
private ArrayList _fields = new ArrayList();
private ArrayList _methods = new ArrayList();
private ArrayList _attributes = new ArrayList();
private JavaAnnotation []_annotations;
private boolean _isWrite;
public JavaClass()
{
this(new JavaClassLoader());
}
public JavaClass(JavaClassLoader loader)
{
if (loader == null)
throw new NullPointerException();
_loader = loader;
}
/**
* Returns the loader.
*/
public JavaClassLoader getClassLoader()
{
return _loader;
}
public void setWrite(boolean isWrite)
{
_isWrite = isWrite;
}
/**
* Sets the URL.
*/
public void setURL(URL url)
{
_url = url;
}
/**
* Sets the major identifier of the class file.
*/
public void setMajor(int major)
{
_major = major;
}
/**
* Gets the major identifier of the class file.
*/
public int getMajor()
{
return _major;
}
/**
* Sets the minor identifier of the class file.
*/
public void setMinor(int minor)
{
_minor = minor;
}
/**
* Gets the minor identifier of the class file.
*/
public int getMinor()
{
return _minor;
}
/**
* Returns the class's constant pool.
*/
public ConstantPool getConstantPool()
{
return _constantPool;
}
/**
* Sets the access flags.
*/
public void setAccessFlags(int flags)
{
_accessFlags = flags;
}
/**
* Gets the access flags.
*/
public int getAccessFlags()
{
lazyLoad();
return _accessFlags;
}
/**
* Sets this class.
*/
public void setThisClass(String className)
{
_thisClass = className;
if (_isWrite)
getConstantPool().addClass(className);
}
/**
* Gets this class name.
*/
public String getThisClass()
{
return _thisClass;
}
/**
* Sets the super class.
*/
public void setSuperClass(String className)
{
_superClass = className;
getConstantPool().addClass(className);
}
/**
* Gets the super class name.
*/
public String getSuperClassName()
{
lazyLoad();
return _superClass;
}
/**
* Gets the super class name.
*/
public JClass getSuperClass()
{
lazyLoad();
if (_superClass == null)
return null;
else
return getClassLoader().forName(_superClass.replace('/', '.'));
}
/**
* Returns true for a final class.
*/
public boolean isFinal()
{
return Modifier.isFinal(getAccessFlags());
}
/**
* Returns true for an abstract class.
*/
public boolean isAbstract()
{
return Modifier.isAbstract(getAccessFlags());
}
/**
* Returns true for a public class.
*/
public boolean isPublic()
{
return Modifier.isPublic(getAccessFlags());
}
/**
* Returns true for a primitive class.
*/
public boolean isPrimitive()
{
return false;
}
/**
* Adds an interface.
*/
public void addInterface(String className)
{
_interfaces.add(className);
if (_isWrite)
getConstantPool().addClass(className);
}
/**
* Adds an interface.
*/
public ArrayList getInterfaceNames()
{
return _interfaces;
}
/**
* Gets the interfaces.
*/
public JClass []getInterfaces()
{
lazyLoad();
JClass []interfaces = new JClass[_interfaces.size()];
for (int i = 0; i < _interfaces.size(); i++) {
String name = _interfaces.get(i);
name = name.replace('/', '.');
interfaces[i] = getClassLoader().forName(name);
}
return interfaces;
}
/**
* Adds a field
*/
public void addField(JavaField field)
{
_fields.add(field);
}
public JavaField createField(String name, String descriptor)
{
if (! _isWrite)
throw new IllegalStateException("create field requires write");
JavaField jField = new JavaField();
jField.setWrite(true);
jField.setJavaClass(this);
jField.setName(name);
jField.setDescriptor(descriptor);
_fields.add(jField);
return jField;
}
/**
* Returns the fields.
*/
public ArrayList getFieldList()
{
lazyLoad();
return _fields;
}
/**
* Returns a fields.
*/
public JavaField getField(String name)
{
ArrayList fieldList = getFieldList();
for (int i = 0; i < fieldList.size(); i++) {
JavaField field = fieldList.get(i);
if (field.getName().equals(name))
return field;
}
return null;
}
/**
* Adds a method
*/
public void addMethod(JavaMethod method)
{
_methods.add(method);
}
public JavaMethod createMethod(String name, String descriptor)
{
if (! _isWrite)
throw new IllegalStateException("create method requires write");
JavaMethod jMethod = new JavaMethod();
jMethod.setWrite(true);
jMethod.setJavaClass(this);
jMethod.setName(name);
jMethod.setDescriptor(descriptor);
_methods.add(jMethod);
return jMethod;
}
/**
* Returns the methods.
*/
public ArrayList getMethodList()
{
lazyLoad();
return _methods;
}
/**
* Returns true for an array.
*/
public boolean isArray()
{
return false;
}
/**
* Returns true for an interface.
*/
public boolean isInterface()
{
lazyLoad();
return Modifier.isInterface(_accessFlags);
}
/**
* Returns a method.
*/
public JavaMethod getMethod(String name)
{
ArrayList methodList = getMethodList();
for (int i = 0; i < methodList.size(); i++) {
JavaMethod method = methodList.get(i);
if (method.getName().equals(name))
return method;
}
return null;
}
/**
* Finds a method.
*/
public JavaMethod findMethod(String name, String descriptor)
{
ArrayList methodList = getMethodList();
for (int i = 0; i < methodList.size(); i++) {
JavaMethod method = methodList.get(i);
if (method.getName().equals(name) &&
method.getDescriptor().equals(descriptor))
return method;
}
return null;
}
/**
* Adds an attribute
*/
public void addAttribute(Attribute attr)
{
_attributes.add(attr);
attr.addConstants(this);
}
/**
* Returns the methods.
*/
public ArrayList getAttributeList()
{
lazyLoad();
return _attributes;
}
/**
* Returns the attribute.
*/
public Attribute getAttribute(String name)
{
ArrayList attributeList = getAttributeList();
for (int i = attributeList.size() - 1; i >= 0; i--) {
Attribute attr = attributeList.get(i);
if (attr.getName().equals(name))
return attr;
}
return null;
}
//
// JClass methods.
//
/**
* Returns the class-equivalent name.
*/
public String getName()
{
return getThisClass().replace('/', '.');
}
/**
* Returns true if the class is assignable from the argument.
*/
public boolean isAssignableFrom(JClass cl)
{
if (getName().equals(cl.getName()))
return true;
JClass []ifc = cl.getInterfaces();
for (int i = 0; i < ifc.length; i++) {
if (isAssignableFrom(ifc[i]))
return true;
}
if (cl.getSuperClass() != null)
return isAssignableFrom(cl.getSuperClass());
else
return false;
}
/**
* Returns true if the class is assignable from the argument.
*/
public boolean isAssignableFrom(Class cl)
{
if (getName().equals(cl.getName()))
return true;
Class []ifc = cl.getInterfaces();
for (int i = 0; i < ifc.length; i++) {
if (isAssignableFrom(ifc[i]))
return true;
}
if (cl.getSuperclass() != null)
return isAssignableFrom(cl.getSuperclass());
else
return false;
}
/**
* Returns true if the class is assignable from the argument.
*/
public boolean isAssignableTo(Class cl)
{
if (getName().equals(cl.getName()))
return true;
JClass []ifc = getInterfaces();
for (int i = 0; i < ifc.length; i++) {
if (ifc[i].isAssignableTo(cl))
return true;
}
if (getSuperClass() != null)
return getSuperClass().isAssignableTo(cl);
else
return false;
}
/**
* Returns the array of declared methods.
*/
public JMethod []getDeclaredMethods()
{
ArrayList methodList = getMethodList();
JMethod[] methods = new JMethod[methodList.size()];
methodList.toArray(methods);
return methods;
}
/**
* Returns the array of declared methods.
*/
public JMethod []getConstructors()
{
ArrayList ctorList = new ArrayList();
for (JavaMethod method : getMethodList()) {
if (method.getName().equals(""))
ctorList.add(method);
}
JMethod[] methods = new JMethod[ctorList.size()];
ctorList.toArray(methods);
return methods;
}
/**
* Returns the matching method
*/
public JMethod getMethod(String name, JClass []paramTypes)
{
loop:
for (JMethod method : getMethods()) {
if (! method.getName().equals(name))
continue;
JClass []mParamTypes = method.getParameterTypes();
if (mParamTypes.length != paramTypes.length)
continue;
for (int i = 0; i < paramTypes.length; i++) {
if (! paramTypes[i].getName().equals(mParamTypes[i].getName()))
continue loop;
}
return method;
}
return null;
}
/**
* Returns the matching method
*/
public JMethod []getMethods()
{
ArrayList methodList = new ArrayList();
getMethods(methodList);
JMethod []methods = new JMethod[methodList.size()];
methodList.toArray(methods);
return methods;
}
/**
* Returns the matching method
*/
private void getMethods(ArrayList methodList)
{
for (JMethod method : getDeclaredMethods()) {
if (! methodList.contains(method))
methodList.add(method);
}
if (getSuperClass() != null) {
for (JMethod method : getSuperClass().getMethods()) {
if (! methodList.contains(method))
methodList.add(method);
}
}
}
/**
* Returns the array of declared fields.
*/
public JField []getDeclaredFields()
{
ArrayList fieldList = getFieldList();
JField[] fields = new JField[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
/**
* Returns the array of fields.
*/
public JField []getFields()
{
ArrayList fieldList = new ArrayList();
getFields(fieldList);
JField []fields = new JField[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
/**
* Returns all the fields
*/
private void getFields(ArrayList fieldList)
{
for (JField field : getDeclaredFields()) {
if (! fieldList.contains(field))
fieldList.add(field);
}
if (getSuperClass() != null) {
for (JField field : getSuperClass().getFields()) {
if (! fieldList.contains(field))
fieldList.add(field);
}
}
}
/**
* Returns the declared annotations.
*/
public JAnnotation []getDeclaredAnnotations()
{
if (_annotations == null) {
Attribute attr = getAttribute("RuntimeVisibleAnnotations");
if (attr instanceof OpaqueAttribute) {
byte []buffer = ((OpaqueAttribute) attr).getValue();
try {
ByteArrayInputStream is = new ByteArrayInputStream(buffer);
ConstantPool cp = getConstantPool();
_annotations = JavaAnnotation.parseAnnotations(is, cp,
getClassLoader());
} catch (IOException e) {
log.log(Level.FINER, e.toString(), e);
}
}
if (_annotations == null) {
_annotations = new JavaAnnotation[0];
}
}
return _annotations;
}
/**
* Returns the annotation.
*/
public JAnnotation getAnnotation(String className)
{
JAnnotation []annList = getDeclaredAnnotations();
for (int i = 0; i < annList.length; i++) {
if (annList[i].getType().equals(className))
return annList[i];
}
return null;
}
/**
* Lazily load the class.
*/
private void lazyLoad()
{
if (_major > 0)
return;
try {
if (_url == null)
throw new IllegalStateException();
InputStream is = _url.openStream();
ReadStream rs = Vfs.openRead(is);
try {
_major = 1;
ByteCodeParser parser = new ByteCodeParser();
parser.setClassLoader(_loader);
parser.setJavaClass(this);
parser.parse(rs);
} finally {
rs.close();
is.close();
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Writes the class to the output.
*/
public void write(WriteStream os)
throws IOException
{
ByteCodeWriter out = new ByteCodeWriter(os, this);
out.writeInt(MAGIC);
out.writeShort(_minor);
out.writeShort(_major);
_constantPool.write(out);
out.writeShort(_accessFlags);
out.writeClass(_thisClass);
out.writeClass(_superClass);
out.writeShort(_interfaces.size());
for (int i = 0; i < _interfaces.size(); i++) {
String className = _interfaces.get(i);
out.writeClass(className);
}
out.writeShort(_fields.size());
for (int i = 0; i < _fields.size(); i++) {
JavaField field = _fields.get(i);
field.write(out);
}
out.writeShort(_methods.size());
for (int i = 0; i < _methods.size(); i++) {
JavaMethod method = _methods.get(i);
method.write(out);
}
out.writeShort(_attributes.size());
for (int i = 0; i < _attributes.size(); i++) {
Attribute attr = _attributes.get(i);
attr.write(out);
}
}
public String toString()
{
return "JavaClass[" + _thisClass + "]";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy