/*
* Copyright 2004-2010 Brian S O'Neill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cojen.classfile;
import java.util.ArrayList;
import java.util.List;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.reflect.Modifier;
import org.cojen.classfile.attribute.Annotation;
import org.cojen.classfile.attribute.AnnotationsAttr;
import org.cojen.classfile.attribute.ConstantValueAttr;
import org.cojen.classfile.attribute.DeprecatedAttr;
import org.cojen.classfile.attribute.RuntimeInvisibleAnnotationsAttr;
import org.cojen.classfile.attribute.RuntimeVisibleAnnotationsAttr;
import org.cojen.classfile.attribute.SignatureAttr;
import org.cojen.classfile.attribute.SyntheticAttr;
import org.cojen.classfile.constant.ConstantUTFInfo;
/**
* This class corresponds to the field_info structure as defined in
* section 4.5 of <i>The Java Virtual Machine Specification</i>.
*
* @author Brian S O'Neill
* @see ClassFile
*/
public class FieldInfo {
private ClassFile mParent;
private ConstantPool mCp;
private String mName;
private TypeDesc mType;
private Modifiers mModifiers;
private ConstantUTFInfo mNameConstant;
private ConstantUTFInfo mDescriptorConstant;
private List<Attribute> mAttributes = new ArrayList<Attribute>(2);
private ConstantValueAttr mConstant;
FieldInfo(ClassFile parent,
Modifiers modifiers,
String name,
TypeDesc type) {
mParent = parent;
mCp = parent.getConstantPool();
mName = name;
mType = type;
mModifiers = modifiers;
mNameConstant = mCp.addConstantUTF(name);
mDescriptorConstant = mCp.addConstantUTF(type.getDescriptor());
}
private FieldInfo(ClassFile parent,
int modifier,
ConstantUTFInfo nameConstant,
ConstantUTFInfo descConstant) {
mParent = parent;
mCp = parent.getConstantPool();
mName = nameConstant.getValue();
mType = TypeDesc.forDescriptor(descConstant.getValue());
mModifiers = Modifiers.getInstance(modifier);
mNameConstant = nameConstant;
mDescriptorConstant = descConstant;
}
/**
* Returns the parent ClassFile for this FieldInfo.
*/
public ClassFile getClassFile() {
return mParent;
}
/**
* Returns the name of this field.
*/
public String getName() {
return mName;
}
/**
* Returns the type of this field.
*/
public TypeDesc getType() {
return mType;
}
/**
* Returns this field's modifiers.
*/
public Modifiers getModifiers() {
return mModifiers;
}
public void setModifiers(Modifiers modifiers) {
mModifiers = modifiers;
}
/**
* Returns a constant from the constant pool with this field's name.
*/
public ConstantUTFInfo getNameConstant() {
return mNameConstant;
}
/**
* Returns a constant from the constant pool with this field's type
* descriptor string.
* @see TypeDesc
*/
public ConstantUTFInfo getDescriptorConstant() {
return mDescriptorConstant;
}
/**
* Returns the constant value for this field or null if no constant set.
*/
public ConstantInfo getConstantValue() {
if (mConstant == null) {
return null;
} else {
return mConstant.getConstant();
}
}
public boolean isSynthetic() {
for (int i = mAttributes.size(); --i >= 0; ) {
Attribute attr = mAttributes.get(i);
if (attr instanceof SyntheticAttr) {
return true;
}
}
return false;
}
public boolean isDeprecated() {
for (int i = mAttributes.size(); --i >= 0; ) {
Attribute attr = mAttributes.get(i);
if (attr instanceof DeprecatedAttr) {
return true;
}
}
return false;
}
/**
* Returns all the runtime invisible annotations defined for this class
* file, or an empty array if none.
*/
public Annotation[] getRuntimeInvisibleAnnotations() {
for (int i = mAttributes.size(); --i >= 0; ) {
Attribute attr = mAttributes.get(i);
if (attr instanceof RuntimeInvisibleAnnotationsAttr) {
return ((AnnotationsAttr) attr).getAnnotations();
}
}
return new Annotation[0];
}
/**
* Returns all the runtime visible annotations defined for this class file,
* or an empty array if none.
*/
public Annotation[] getRuntimeVisibleAnnotations() {
for (int i = mAttributes.size(); --i >= 0; ) {
Attribute attr = mAttributes.get(i);
if (attr instanceof RuntimeVisibleAnnotationsAttr) {
return ((AnnotationsAttr) attr).getAnnotations();
}
}
return new Annotation[0];
}
/**
* Add a runtime invisible annotation.
*/
public Annotation addRuntimeInvisibleAnnotation(TypeDesc type) {
AnnotationsAttr attr = null;
for (int i = mAttributes.size(); --i >= 0; ) {
Attribute a = mAttributes.get(i);
if (a instanceof RuntimeInvisibleAnnotationsAttr) {
attr = (AnnotationsAttr) a;
}
}
if (attr == null) {
attr = new RuntimeInvisibleAnnotationsAttr(mCp);
addAttribute(attr);
}
Annotation ann = new Annotation(mCp);
ann.setType(type);
attr.addAnnotation(ann);
return ann;
}
/**
* Add a runtime visible annotation.
*/
public Annotation addRuntimeVisibleAnnotation(TypeDesc type) {
AnnotationsAttr attr = null;
for (int i = mAttributes.size(); --i >= 0; ) {
Attribute a = mAttributes.get(i);
if (a instanceof RuntimeVisibleAnnotationsAttr) {
attr = (AnnotationsAttr) a;
}
}
if (attr == null) {
attr = new RuntimeVisibleAnnotationsAttr(mCp);
addAttribute(attr);
}
Annotation ann = new Annotation(mCp);
ann.setType(type);
attr.addAnnotation(ann);
return ann;
}
/**
* Returns the signature attribute of this field, or null if none is
* defined.
*/
// TODO: Eventually remove this method
public SignatureAttr getSignatureAttr() {
for (int i = mAttributes.size(); --i >= 0; ) {
Attribute attr = mAttributes.get(i);
if (attr instanceof SignatureAttr) {
return (SignatureAttr) attr;
}
}
return null;
}
/**
* Set the constant value for this field as an int.
*/
public void setConstantValue(int value) {
addAttribute(new ConstantValueAttr(mCp, mCp.addConstantInteger(value)));
}
/**
* Set the constant value for this field as a float.
*/
public void setConstantValue(float value) {
addAttribute(new ConstantValueAttr(mCp, mCp.addConstantFloat(value)));
}
/**
* Set the constant value for this field as a long.
*/
public void setConstantValue(long value) {
addAttribute(new ConstantValueAttr(mCp, mCp.addConstantLong(value)));
}
/**
* Set the constant value for this field as a double.
*/
public void setConstantValue(double value) {
addAttribute(new ConstantValueAttr(mCp, mCp.addConstantDouble(value)));
}
/**
* Set the constant value for this field as a string.
*/
public void setConstantValue(String value) {
addAttribute(new ConstantValueAttr(mCp, mCp.addConstantString(value)));
}
/**
* Mark this field as being synthetic by adding a special attribute.
*/
public void markSynthetic() {
addAttribute(new SyntheticAttr(mCp));
}
/**
* Mark this field as being deprecated by adding a special attribute.
*/
public void markDeprecated() {
addAttribute(new DeprecatedAttr(mCp));
}
public void addAttribute(Attribute attr) {
if (attr instanceof ConstantValueAttr) {
if (mConstant != null) {
mAttributes.remove(mConstant);
}
mConstant = (ConstantValueAttr)attr;
}
mAttributes.add(attr);
}
public Attribute[] getAttributes() {
return mAttributes.toArray(new Attribute[mAttributes.size()]);
}
/**
* Returns the length (in bytes) of this object in the class file.
*/
public int getLength() {
int length = 8;
int size = mAttributes.size();
for (int i=0; i<size; i++) {
length += mAttributes.get(i).getLength();
}
return length;
}
public void writeTo(DataOutput dout) throws IOException {
dout.writeShort(mModifiers.getBitmask());
dout.writeShort(mNameConstant.getIndex());
dout.writeShort(mDescriptorConstant.getIndex());
int size = mAttributes.size();
dout.writeShort(size);
for (int i=0; i<size; i++) {
Attribute attr = mAttributes.get(i);
attr.writeTo(dout);
}
}
public String toString() {
String modStr = mModifiers.toString();
String typeStr;
if (modStr.length() == 0) {
return mType.getFullName() + ' ' + getName();
} else {
return modStr + ' ' + mType.getFullName() + ' ' + getName();
}
}
static FieldInfo readFrom(ClassFile parent,
DataInput din,
AttributeFactory attrFactory)
throws IOException
{
ConstantPool cp = parent.getConstantPool();
int modifier = din.readUnsignedShort();
int index = din.readUnsignedShort();
ConstantUTFInfo nameConstant = (ConstantUTFInfo)cp.getConstant(index);
index = din.readUnsignedShort();
ConstantUTFInfo descConstant = (ConstantUTFInfo)cp.getConstant(index);
FieldInfo info = new FieldInfo(parent, modifier, nameConstant, descConstant);
// Read attributes.
int size = din.readUnsignedShort();
for (int i=0; i<size; i++) {
info.addAttribute(Attribute.readFrom(cp, din, attrFactory));
}
return info;
}
}