com.caucho.bytecode.JavaMethod Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of resin Show documentation
Show all versions of resin Show documentation
Resin Java Application Server
/*
* 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 java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Represents a java field.
*/
public class JavaMethod extends JMethod {
static private final Logger log = Logger.getLogger(JavaMethod.class.getName());
private static final JClass []NULL_CLASS = new JClass[0];
private JavaClassLoader _loader;
private JavaClass _jClass;
private int _accessFlags;
private String _name;
private String _descriptor;
private JClass []_exceptions = NULL_CLASS;
private int _line = -1;
private ArrayList _attributes = new ArrayList();
private JavaAnnotation []_annotations;
private boolean _isWrite;
public JavaMethod(JavaClassLoader loader)
{
_loader = loader;
}
public JavaMethod()
{
}
/**
* Sets the JavaClass.
*/
public void setJavaClass(JavaClass jClass)
{
_jClass = jClass;
}
public void setWrite(boolean isWrite)
{
_isWrite = isWrite;
}
/**
* Sets the name.
*/
public void setName(String name)
{
_name = name;
if (_jClass != null)
_jClass.getConstantPool().addUTF8(name);
}
/**
* Gets the name.
*/
public String getName()
{
return _name;
}
/**
* Returns the line number.
*/
public int getLine()
{
if (_line >= 0)
return _line;
Attribute attr = getAttribute("LineNumberTable");
if (attr == null) {
_line = 0;
return _line;
}
_line = 0;
return _line;
}
/**
* Returns the class loader.
*/
public JavaClassLoader getClassLoader()
{
return _loader;
}
/**
* Sets the access flags
*/
public void setAccessFlags(int flags)
{
_accessFlags = flags;
}
/**
* Gets the access flags
*/
public int getAccessFlags()
{
return _accessFlags;
}
/**
* Returns true for a final method
*/
public boolean isFinal()
{
return Modifier.isFinal(getAccessFlags());
}
/**
* Returns true for a public method
*/
public boolean isPublic()
{
return Modifier.isPublic(getAccessFlags());
}
/**
* Returns true for a protected method
*/
public boolean isProtected()
{
return Modifier.isProtected(getAccessFlags());
}
/**
* Returns true for a private method
*/
public boolean isPrivate()
{
return Modifier.isPrivate(getAccessFlags());
}
/**
* Returns true for an abstract method
*/
public boolean isAbstract()
{
return Modifier.isAbstract(getAccessFlags());
}
/**
* Returns true for a static method
*/
public boolean isStatic()
{
return Modifier.isStatic(getAccessFlags());
}
/**
* Sets the descriptor.
*/
public void setDescriptor(String descriptor)
{
_descriptor = descriptor;
if (_jClass != null)
_jClass.getConstantPool().addUTF8(descriptor);
}
/**
* Gets the descriptor.
*/
public String getDescriptor()
{
return _descriptor;
}
/**
* Returns the declaring class.
*/
public JClass getDeclaringClass()
{
return _jClass;
}
/**
* Returns the return types.
*/
public JClass getReturnType()
{
String descriptor = getDescriptor();
int i = descriptor.lastIndexOf(')');
return getClassLoader().descriptorToClass(descriptor, i + 1);
}
/**
* Returns the return type.
*/
public JType getGenericReturnType()
{
SignatureAttribute sigAttr = (SignatureAttribute) getAttribute("Signature");
if (sigAttr != null) {
String sig = sigAttr.getSignature();
int t = sig.lastIndexOf(')');
return _loader.parseParameterizedType(sig.substring(t + 1));
}
return getReturnType();
}
/**
* Returns the parameter types.
*/
public JClass []getParameterTypes()
{
String descriptor = getDescriptor();
ArrayList typeList = new ArrayList();
int i = 0;
while ((i = nextDescriptor(descriptor, i)) >= 0) {
typeList.add(getClassLoader().descriptorToClass(descriptor, i));
}
JClass []types = new JClass[typeList.size()];
typeList.toArray(types);
return types;
}
private int nextDescriptor(String name, int i)
{
switch (name.charAt(i)) {
case ')':
return -1;
case '(':
case 'V':
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
case 'J':
case 'F':
case 'D':
i += 1;
break;
case '[':
return nextDescriptor(name, i + 1);
case 'L':
{
int tail = name.indexOf( ';', i);
if (tail < 0)
throw new IllegalStateException();
i = tail + 1;
}
break;
default:
throw new UnsupportedOperationException(name.substring(i));
}
if (name.length() <= i)
return -1;
else if (name.charAt(i) == ')')
return -1;
else
return i;
}
/**
* Sets the exception types
*/
public void setExceptionTypes(JClass []exceptions)
{
_exceptions = exceptions;
}
/**
* Returns the exception types.
*/
public JClass []getExceptionTypes()
{
return _exceptions;
}
/**
* Adds an attribute.
*/
public void addAttribute(Attribute attr)
{
_attributes.add(attr);
}
public CodeWriterAttribute createCodeWriter()
{
CodeWriterAttribute code = new CodeWriterAttribute(_jClass);
_attributes.add(code);
return code;
}
/**
* Removes an attribute.
*/
public Attribute removeAttribute(String name)
{
for (int i = _attributes.size() - 1; i >= 0; i--) {
Attribute attr = _attributes.get(i);
if (attr.getName().equals(name)) {
_attributes.remove(i);
return attr;
}
}
return null;
}
/**
* Returns the attribute.
*/
public ArrayList getAttributes()
{
return _attributes;
}
/**
* Returns the attribute.
*/
public Attribute getAttribute(String name)
{
for (int i = _attributes.size() - 1; i >= 0; i--) {
Attribute attr = _attributes.get(i);
if (attr.getName().equals(name))
return attr;
}
return null;
}
/**
* 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 = _jClass.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 code attribute.
*/
public CodeAttribute getCode()
{
for (int i = 0; i < _attributes.size(); i++) {
Attribute attr = _attributes.get(i);
if (attr instanceof CodeAttribute)
return (CodeAttribute) attr;
}
return null;
}
/**
* Create the code attribute.
*/
public CodeAttribute createCode()
{
CodeAttribute code = new CodeAttribute();
for (int i = 0; i < _attributes.size(); i++) {
Attribute attr = _attributes.get(i);
if (attr instanceof CodeAttribute)
return (CodeAttribute) attr;
}
return null;
}
/**
* Writes the field to the output.
*/
public void write(ByteCodeWriter out)
throws IOException
{
out.writeShort(_accessFlags);
out.writeUTF8Const(_name);
out.writeUTF8Const(_descriptor);
out.writeShort(_attributes.size());
for (int i = 0; i < _attributes.size(); i++) {
Attribute attr = _attributes.get(i);
attr.write(out);
}
}
/**
* exports the method.
*/
public JavaMethod export(JavaClass source, JavaClass target)
{
JavaMethod method = new JavaMethod(_loader);
method.setName(_name);
method.setDescriptor(_descriptor);
method.setAccessFlags(_accessFlags);
target.getConstantPool().addUTF8(_name);
target.getConstantPool().addUTF8(_descriptor);
for (int i = 0; i < _attributes.size(); i++) {
Attribute attr = _attributes.get(i);
method.addAttribute(attr.export(source, target));
}
return method;
}
/**
* Concatenates the method.
*/
public void concatenate(JavaMethod tail)
{
CodeAttribute codeAttr = getCode();
CodeAttribute tailCodeAttr = tail.getCode();
byte []code = codeAttr.getCode();
byte []tailCode = tailCodeAttr.getCode();
int codeLength = code.length;
if ((code[codeLength - 1] & 0xff) == CodeVisitor.RETURN)
codeLength = codeLength - 1;
byte []newCode = new byte[codeLength + tailCode.length];
System.arraycopy(code, 0, newCode, 0, codeLength);
System.arraycopy(tailCode, 0, newCode, codeLength, tailCode.length);
codeAttr.setCode(newCode);
if (codeAttr.getMaxStack() < tailCodeAttr.getMaxStack())
codeAttr.setMaxStack(tailCodeAttr.getMaxStack());
if (codeAttr.getMaxLocals() < tailCodeAttr.getMaxLocals())
codeAttr.setMaxLocals(tailCodeAttr.getMaxLocals());
ArrayList exns = tailCodeAttr.getExceptions();
for (int i = 0; i < exns.size(); i++) {
CodeAttribute.ExceptionItem exn = exns.get(i);
CodeAttribute.ExceptionItem newExn = new CodeAttribute.ExceptionItem();
newExn.setType(exn.getType());
newExn.setStart(exn.getStart() + codeLength);
newExn.setEnd(exn.getEnd() + codeLength);
newExn.setHandler(exn.getHandler() + codeLength);
}
}
public String toString()
{
return "JavaMethod[" + _name + "]";
}
}