001: /*
002: * Copyright 2004 Brian S O'Neill
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.cojen.classfile;
018:
019: import java.io.DataInput;
020: import java.io.DataOutput;
021: import java.io.IOException;
022: import org.cojen.classfile.attribute.CodeAttr;
023: import org.cojen.classfile.attribute.ConstantValueAttr;
024: import org.cojen.classfile.attribute.DeprecatedAttr;
025: import org.cojen.classfile.attribute.EnclosingMethodAttr;
026: import org.cojen.classfile.attribute.ExceptionsAttr;
027: import org.cojen.classfile.attribute.InnerClassesAttr;
028: import org.cojen.classfile.attribute.LineNumberTableAttr;
029: import org.cojen.classfile.attribute.LocalVariableTableAttr;
030: import org.cojen.classfile.attribute.RuntimeInvisibleAnnotationsAttr;
031: import org.cojen.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttr;
032: import org.cojen.classfile.attribute.RuntimeVisibleAnnotationsAttr;
033: import org.cojen.classfile.attribute.RuntimeVisibleParameterAnnotationsAttr;
034: import org.cojen.classfile.attribute.SignatureAttr;
035: import org.cojen.classfile.attribute.SourceFileAttr;
036: import org.cojen.classfile.attribute.SyntheticAttr;
037: import org.cojen.classfile.attribute.UnknownAttr;
038: import org.cojen.classfile.constant.ConstantUTFInfo;
039:
040: /**
041: * This class corresponds to the attribute_info structure defined in section
042: * 4.7 of <i>The Java Virtual Machine Specification</i>.
043: *
044: * @author Brian S O'Neill
045: * @see ClassFile
046: */
047: public abstract class Attribute {
048: final static Attribute[] NO_ATTRIBUTES = new Attribute[0];
049:
050: public static final String CODE = "Code";
051: public static final String CONSTANT_VALUE = "ConstantValue";
052: public static final String DEPRECATED = "Deprecated";
053: public static final String EXCEPTIONS = "Exceptions";
054: public static final String INNER_CLASSES = "InnerClasses";
055: public static final String LINE_NUMBER_TABLE = "LineNumberTable";
056: public static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable";
057: public static final String SOURCE_FILE = "SourceFile";
058: public static final String SYNTHETIC = "Synthetic";
059: public static final String SIGNATURE = "Signature";
060: public static final String ENCLOSING_METHOD = "EnclosingMethod";
061: public static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
062: public static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
063: public static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParamaterAnnotations";
064: public static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParamaterAnnotations";
065:
066: /** The ConstantPool that this attribute is defined against. */
067: private final ConstantPool mCp;
068:
069: private String mName;
070: private ConstantUTFInfo mNameConstant;
071:
072: protected Attribute(ConstantPool cp, String name) {
073: mCp = cp;
074: mName = name;
075: mNameConstant = cp.addConstantUTF(name);
076: }
077:
078: /**
079: * Returns the ConstantPool that this attribute is defined against.
080: */
081: public ConstantPool getConstantPool() {
082: return mCp;
083: }
084:
085: /**
086: * Returns the name of this attribute.
087: */
088: public String getName() {
089: return mName;
090: }
091:
092: public ConstantUTFInfo getNameConstant() {
093: return mNameConstant;
094: }
095:
096: /**
097: * Some attributes have sub-attributes. Default implementation returns an
098: * empty array.
099: */
100: public Attribute[] getAttributes() {
101: return NO_ATTRIBUTES;
102: }
103:
104: /**
105: * Returns the length (in bytes) of this attribute in the class file.
106: */
107: public abstract int getLength();
108:
109: /**
110: * This method writes the 16 bit name constant index followed by the
111: * 32 bit attribute length, followed by the attribute specific data.
112: */
113: public final void writeTo(DataOutput dout) throws IOException {
114: dout.writeShort(mNameConstant.getIndex());
115: dout.writeInt(getLength());
116: writeDataTo(dout);
117: }
118:
119: /**
120: * Write just the attribute specific data. The default implementation
121: * writes nothing.
122: */
123: public void writeDataTo(DataOutput dout) throws IOException {
124: }
125:
126: /**
127: * @param attrFactory optional factory for reading custom attributes
128: */
129: public static Attribute readFrom(ConstantPool cp, DataInput din,
130: AttributeFactory attrFactory) throws IOException {
131: int index = din.readUnsignedShort();
132: String name = ((ConstantUTFInfo) cp.getConstant(index))
133: .getValue();
134: int length = din.readInt();
135:
136: attrFactory = new Factory(attrFactory);
137: return attrFactory.createAttribute(cp, name, length, din);
138: }
139:
140: private static class Factory implements AttributeFactory {
141: private final AttributeFactory mAttrFactory;
142:
143: public Factory(AttributeFactory attrFactory) {
144: mAttrFactory = attrFactory;
145: }
146:
147: public Attribute createAttribute(ConstantPool cp, String name,
148: int length, DataInput din) throws IOException {
149: if (name.length() > 0) {
150: switch (name.charAt(0)) {
151: case 'C':
152: if (name.equals(CODE)) {
153: return new CodeAttr(cp, name, length, din,
154: mAttrFactory);
155: } else if (name.equals(CONSTANT_VALUE)) {
156: return new ConstantValueAttr(cp, name, length,
157: din);
158: }
159: break;
160: case 'D':
161: if (name.equals(DEPRECATED)) {
162: return new DeprecatedAttr(cp, name, length, din);
163: }
164: break;
165: case 'E':
166: if (name.equals(EXCEPTIONS)) {
167: return new ExceptionsAttr(cp, name, length, din);
168: } else if (name.equals(ENCLOSING_METHOD)) {
169: return new EnclosingMethodAttr(cp, name,
170: length, din);
171: }
172: break;
173: case 'I':
174: if (name.equals(INNER_CLASSES)) {
175: return new InnerClassesAttr(cp, name, length,
176: din);
177: }
178: break;
179: case 'L':
180: if (name.equals(LINE_NUMBER_TABLE)) {
181: return new LineNumberTableAttr(cp, name,
182: length, din);
183: } else if (name.equals(LOCAL_VARIABLE_TABLE)) {
184: return new LocalVariableTableAttr(cp, name,
185: length, din);
186: }
187: break;
188: case 'R':
189: if (name.equals(RUNTIME_VISIBLE_ANNOTATIONS)) {
190: return new RuntimeVisibleAnnotationsAttr(cp,
191: name, length, din);
192: } else if (name
193: .equals(RUNTIME_INVISIBLE_ANNOTATIONS)) {
194: return new RuntimeInvisibleAnnotationsAttr(cp,
195: name, length, din);
196: } else if (name
197: .equals(RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS)) {
198: return new RuntimeVisibleParameterAnnotationsAttr(
199: cp, name, length, din);
200: } else if (name
201: .equals(RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS)) {
202: return new RuntimeInvisibleParameterAnnotationsAttr(
203: cp, name, length, din);
204: }
205: break;
206: case 'S':
207: if (name.equals(SOURCE_FILE)) {
208: return new SourceFileAttr(cp, name, length, din);
209: } else if (name.equals(SYNTHETIC)) {
210: return new SyntheticAttr(cp, name, length, din);
211: } else if (name.equals(SIGNATURE)) {
212: return new SignatureAttr(cp, name, length, din);
213: }
214: break;
215: }
216: }
217:
218: if (mAttrFactory != null) {
219: Attribute attr = mAttrFactory.createAttribute(cp, name,
220: length, din);
221: if (attr != null) {
222: return attr;
223: }
224: }
225:
226: // Default case, return attribute that captures the data, but
227: // doesn't decode it.
228: return new UnknownAttr(cp, name, length, din);
229: }
230: }
231: }
|