001: /*
002: * Copyright 2005 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.attribute;
018:
019: import java.io.DataInput;
020: import java.io.DataOutput;
021: import java.io.IOException;
022: import java.util.Collections;
023: import java.util.Iterator;
024: import java.util.LinkedHashMap;
025: import java.util.Map;
026: import org.cojen.classfile.ConstantInfo;
027: import org.cojen.classfile.ConstantPool;
028: import org.cojen.classfile.TypeDesc;
029: import org.cojen.classfile.constant.ConstantClassInfo;
030: import org.cojen.classfile.constant.ConstantDoubleInfo;
031: import org.cojen.classfile.constant.ConstantFloatInfo;
032: import org.cojen.classfile.constant.ConstantIntegerInfo;
033: import org.cojen.classfile.constant.ConstantLongInfo;
034: import org.cojen.classfile.constant.ConstantUTFInfo;
035:
036: /**
037: * Defines the annotation structure used by Java 5 annotations attributes.
038: *
039: * @author Brian S O'Neill
040: */
041: public class Annotation {
042:
043: /** Member value is represented by a ConstantIntegerInfo */
044: public static final char MEMBER_TAG_BOOLEAN = 'Z';
045:
046: /** Member value is represented by a ConstantIntegerInfo */
047: public static final char MEMBER_TAG_BYTE = 'B';
048:
049: /** Member value is represented by a ConstantIntegerInfo */
050: public static final char MEMBER_TAG_SHORT = 'S';
051:
052: /** Member value is represented by a ConstantIntegerInfo */
053: public static final char MEMBER_TAG_CHAR = 'C';
054:
055: /** Member value is represented by a ConstantIntegerInfo */
056: public static final char MEMBER_TAG_INT = 'I';
057:
058: /** Member value is represented by a ConstantLongInfo */
059: public static final char MEMBER_TAG_LONG = 'J';
060:
061: /** Member value is represented by a ConstantFloatInfo */
062: public static final char MEMBER_TAG_FLOAT = 'F';
063:
064: /** Member value is represented by a ConstantDoubleInfo */
065: public static final char MEMBER_TAG_DOUBLE = 'D';
066:
067: /** Member value is represented by a ConstantUTFInfo */
068: public static final char MEMBER_TAG_STRING = 's';
069:
070: /** Member value is represented by a ConstantClassInfo */
071: public static final char MEMBER_TAG_CLASS = 'c';
072:
073: /** Member value is represented by an EnumConstValue */
074: public static final char MEMBER_TAG_ENUM = 'e';
075:
076: /** Member value is represented by a MemberValue array */
077: public static final char MEMBER_TAG_ARRAY = '[';
078:
079: /** Member value is represented by an Annotation */
080: public static final char MEMBER_TAG_ANNOTATION = '@';
081:
082: private final ConstantPool mCp;
083: private ConstantUTFInfo mType;
084: private final Map mMemberValues;
085:
086: public Annotation(ConstantPool cp) {
087: mCp = cp;
088: mMemberValues = new LinkedHashMap(2);
089: }
090:
091: public Annotation(ConstantPool cp, DataInput din)
092: throws IOException {
093: mCp = cp;
094: mType = (ConstantUTFInfo) cp.getConstant(din
095: .readUnsignedShort());
096:
097: int memberCount = din.readUnsignedShort();
098: mMemberValues = new LinkedHashMap(memberCount);
099:
100: for (int i = 0; i < memberCount; i++) {
101: String name = ((ConstantUTFInfo) cp.getConstant(din
102: .readUnsignedShort())).getValue();
103: mMemberValues.put(name, new MemberValue(cp, din));
104: }
105: }
106:
107: public ConstantUTFInfo getTypeConstant() {
108: return mType;
109: }
110:
111: public TypeDesc getType() {
112: return TypeDesc.forDescriptor(mType.getValue());
113: }
114:
115: public void setTypeConstant(ConstantUTFInfo type) {
116: mType = type;
117: }
118:
119: public void setType(TypeDesc type) {
120: setTypeConstant(mCp.addConstantUTF(type.getDescriptor()));
121: }
122:
123: /**
124: * Returns an unmodifiable map of member names (String) to MemberValue
125: * objects.
126: */
127: public Map getMemberValues() {
128: return Collections.unmodifiableMap(mMemberValues);
129: }
130:
131: public void putMemberValue(String name, MemberValue mv) {
132: mCp.addConstantUTF(name);
133: mMemberValues.put(name, mv);
134: }
135:
136: public void putMemberValue(String name, boolean value) {
137: mCp.addConstantUTF(name);
138: mMemberValues.put(name, makeMemberValue(value));
139: }
140:
141: public void putMemberValue(String name, byte value) {
142: mCp.addConstantUTF(name);
143: mMemberValues.put(name, makeMemberValue(value));
144: }
145:
146: public void putMemberValue(String name, short value) {
147: mCp.addConstantUTF(name);
148: mMemberValues.put(name, makeMemberValue(value));
149: }
150:
151: public void putMemberValue(String name, char value) {
152: mCp.addConstantUTF(name);
153: mMemberValues.put(name, makeMemberValue(value));
154: }
155:
156: public void putMemberValue(String name, int value) {
157: mCp.addConstantUTF(name);
158: mMemberValues.put(name, makeMemberValue(value));
159: }
160:
161: public void putMemberValue(String name, long value) {
162: mCp.addConstantUTF(name);
163: mMemberValues.put(name, makeMemberValue(value));
164: }
165:
166: public void putMemberValue(String name, float value) {
167: mCp.addConstantUTF(name);
168: mMemberValues.put(name, makeMemberValue(value));
169: }
170:
171: public void putMemberValue(String name, double value) {
172: mCp.addConstantUTF(name);
173: mMemberValues.put(name, makeMemberValue(value));
174: }
175:
176: public void putMemberValue(String name, String value) {
177: mCp.addConstantUTF(name);
178: mMemberValues.put(name, makeMemberValue(value));
179: }
180:
181: public void putMemberValue(String name, TypeDesc value) {
182: mCp.addConstantUTF(name);
183: mMemberValues.put(name, makeMemberValue(value));
184: }
185:
186: public void putMemberValue(String name, MemberValue[] value) {
187: mCp.addConstantUTF(name);
188: mMemberValues.put(name, makeMemberValue(value));
189: }
190:
191: public void putMemberValue(String name, TypeDesc enumType,
192: String enumName) {
193: mCp.addConstantUTF(name);
194: mMemberValues.put(name, makeMemberValue(enumType, enumName));
195: }
196:
197: /**
198: * @see #makeAnnotation
199: */
200: public void putMemberValue(String name, Annotation value) {
201: mCp.addConstantUTF(name);
202: mMemberValues.put(name, makeMemberValue(value));
203: }
204:
205: public MemberValue makeMemberValue(boolean value) {
206: return new MemberValue(MEMBER_TAG_BOOLEAN, mCp
207: .addConstantInteger(value ? 1 : 0));
208: }
209:
210: public MemberValue makeMemberValue(byte value) {
211: return new MemberValue(MEMBER_TAG_BYTE, mCp
212: .addConstantInteger(value));
213: }
214:
215: public MemberValue makeMemberValue(short value) {
216: return new MemberValue(MEMBER_TAG_SHORT, mCp
217: .addConstantInteger(value));
218: }
219:
220: public MemberValue makeMemberValue(char value) {
221: return new MemberValue(MEMBER_TAG_CHAR, mCp
222: .addConstantInteger(value));
223: }
224:
225: public MemberValue makeMemberValue(int value) {
226: return new MemberValue(MEMBER_TAG_INT, mCp
227: .addConstantInteger(value));
228: }
229:
230: public MemberValue makeMemberValue(long value) {
231: return new MemberValue(MEMBER_TAG_LONG, mCp
232: .addConstantLong(value));
233: }
234:
235: public MemberValue makeMemberValue(float value) {
236: return new MemberValue(MEMBER_TAG_FLOAT, mCp
237: .addConstantFloat(value));
238: }
239:
240: public MemberValue makeMemberValue(double value) {
241: return new MemberValue(MEMBER_TAG_DOUBLE, mCp
242: .addConstantDouble(value));
243: }
244:
245: public MemberValue makeMemberValue(String value) {
246: return new MemberValue(MEMBER_TAG_STRING, mCp
247: .addConstantUTF(value));
248: }
249:
250: public MemberValue makeMemberValue(TypeDesc value) {
251: return new MemberValue(MEMBER_TAG_CLASS, mCp
252: .addConstantUTF(value.getDescriptor()));
253: }
254:
255: public MemberValue makeMemberValue(TypeDesc enumType,
256: String enumName) {
257: return new MemberValue(MEMBER_TAG_ENUM, new EnumConstValue(mCp
258: .addConstantUTF(enumType.getDescriptor()), mCp
259: .addConstantUTF(enumName)));
260: }
261:
262: public MemberValue makeMemberValue(MemberValue[] value) {
263: return new MemberValue(MEMBER_TAG_ARRAY, value);
264: }
265:
266: /**
267: * @see #makeAnnotation
268: */
269: public MemberValue makeMemberValue(Annotation value) {
270: return new MemberValue(MEMBER_TAG_ANNOTATION, value);
271: }
272:
273: public Annotation makeAnnotation() {
274: return new Annotation(mCp);
275: }
276:
277: public int getLength() {
278: int length = 4;
279: Iterator it = mMemberValues.values().iterator();
280: while (it.hasNext()) {
281: length += 2 + ((MemberValue) it.next()).getLength();
282: }
283: return length;
284: }
285:
286: public void writeTo(DataOutput dout) throws IOException {
287: dout.writeShort(mType.getIndex());
288: int memberCount = mMemberValues.size();
289: dout.writeShort(memberCount);
290: Iterator it = mMemberValues.entrySet().iterator();
291: while (it.hasNext()) {
292: Map.Entry entry = (Map.Entry) it.next();
293: String name = (String) entry.getKey();
294: MemberValue value = (MemberValue) entry.getValue();
295: dout.writeShort(mCp.addConstantUTF(name).getIndex());
296: value.writeTo(dout);
297: }
298: }
299:
300: public static class MemberValue {
301: private final char mTag;
302: private final Object mValue;
303:
304: public MemberValue(char tag, Object value) {
305: switch (mTag = tag) {
306: default:
307: throw new IllegalArgumentException(
308: "Illegal annotation member value tag: " + mTag);
309:
310: case MEMBER_TAG_BOOLEAN:
311: case MEMBER_TAG_BYTE:
312: case MEMBER_TAG_SHORT:
313: case MEMBER_TAG_CHAR:
314: case MEMBER_TAG_INT:
315: if (value instanceof ConstantIntegerInfo) {
316: mValue = value;
317: } else {
318: throw new IllegalArgumentException(
319: "Value must be ConstantIntegerInfo");
320: }
321: break;
322:
323: case MEMBER_TAG_LONG:
324: if (value instanceof ConstantLongInfo) {
325: mValue = value;
326: } else {
327: throw new IllegalArgumentException(
328: "Value must be ConstantLongInfo");
329: }
330: break;
331:
332: case MEMBER_TAG_FLOAT:
333: if (value instanceof ConstantFloatInfo) {
334: mValue = value;
335: } else {
336: throw new IllegalArgumentException(
337: "Value must be ConstantFloatInfo");
338: }
339: break;
340:
341: case MEMBER_TAG_DOUBLE:
342: if (value instanceof ConstantDoubleInfo) {
343: mValue = value;
344: } else {
345: throw new IllegalArgumentException(
346: "Value must be ConstantDoubleInfo");
347: }
348: break;
349:
350: case MEMBER_TAG_CLASS:
351: if (value instanceof ConstantUTFInfo) {
352: mValue = value;
353: } else {
354: throw new IllegalArgumentException(
355: "Value must be ConstantUTFInfo");
356: }
357: break;
358:
359: case MEMBER_TAG_STRING:
360: if (value instanceof ConstantUTFInfo) {
361: mValue = value;
362: } else {
363: throw new IllegalArgumentException(
364: "Value must be ConstantUTFInfo");
365: }
366: break;
367:
368: case MEMBER_TAG_ENUM:
369: if (value instanceof EnumConstValue) {
370: mValue = value;
371: } else {
372: throw new IllegalArgumentException(
373: "Value must be EnumConstValue");
374: }
375: break;
376:
377: case MEMBER_TAG_ARRAY:
378: if (value instanceof MemberValue[]) {
379: mValue = value;
380: } else {
381: throw new IllegalArgumentException(
382: "Value must be MemberValue[]");
383: }
384: break;
385:
386: case MEMBER_TAG_ANNOTATION:
387: if (value instanceof Annotation) {
388: mValue = value;
389: } else {
390: throw new IllegalArgumentException(
391: "Value must be Annotation");
392: }
393: break;
394: }
395: }
396:
397: public MemberValue(ConstantPool cp, DataInput din)
398: throws IOException {
399: switch (mTag = (char) din.readUnsignedByte()) {
400: default:
401: throw new IllegalStateException(
402: "Illegal annotation member value tag: " + mTag);
403:
404: case MEMBER_TAG_BOOLEAN:
405: case MEMBER_TAG_BYTE:
406: case MEMBER_TAG_SHORT:
407: case MEMBER_TAG_CHAR:
408: case MEMBER_TAG_INT:
409: case MEMBER_TAG_LONG:
410: case MEMBER_TAG_FLOAT:
411: case MEMBER_TAG_DOUBLE:
412: case MEMBER_TAG_CLASS:
413: case MEMBER_TAG_STRING:
414: mValue = cp.getConstant(din.readUnsignedShort());
415: break;
416:
417: case MEMBER_TAG_ENUM:
418: mValue = new EnumConstValue(cp, din);
419: break;
420:
421: case MEMBER_TAG_ARRAY:
422: int length = din.readUnsignedShort();
423: MemberValue[] values = new MemberValue[length];
424: for (int i = 0; i < length; i++) {
425: values[i] = new MemberValue(cp, din);
426: }
427: mValue = values;
428: break;
429:
430: case MEMBER_TAG_ANNOTATION:
431: mValue = new Annotation(cp, din);
432: break;
433: }
434: }
435:
436: public char getTag() {
437: return mTag;
438: }
439:
440: public Object getValue() {
441: return mValue;
442: }
443:
444: public int getLength() {
445: switch (mTag) {
446: default:
447: return 1;
448:
449: case MEMBER_TAG_BOOLEAN:
450: case MEMBER_TAG_BYTE:
451: case MEMBER_TAG_SHORT:
452: case MEMBER_TAG_CHAR:
453: case MEMBER_TAG_INT:
454: case MEMBER_TAG_LONG:
455: case MEMBER_TAG_FLOAT:
456: case MEMBER_TAG_DOUBLE:
457: case MEMBER_TAG_CLASS:
458: case MEMBER_TAG_STRING:
459: return 3;
460:
461: case MEMBER_TAG_ENUM:
462: return 1 + ((EnumConstValue) mValue).getLength();
463:
464: case MEMBER_TAG_ARRAY: {
465: MemberValue[] values = (MemberValue[]) mValue;
466: int length = 3;
467: for (int i = 0; i < values.length; i++) {
468: length += values[i].getLength();
469: }
470: return length;
471: }
472:
473: case MEMBER_TAG_ANNOTATION:
474: return 1 + ((Annotation) mValue).getLength();
475: }
476: }
477:
478: public void writeTo(DataOutput dout) throws IOException {
479: dout.writeByte(mTag);
480:
481: switch (mTag) {
482: case MEMBER_TAG_BOOLEAN:
483: case MEMBER_TAG_BYTE:
484: case MEMBER_TAG_SHORT:
485: case MEMBER_TAG_CHAR:
486: case MEMBER_TAG_INT:
487: case MEMBER_TAG_LONG:
488: case MEMBER_TAG_FLOAT:
489: case MEMBER_TAG_DOUBLE:
490: case MEMBER_TAG_CLASS:
491: case MEMBER_TAG_STRING:
492: dout.writeShort(((ConstantInfo) mValue).getIndex());
493: break;
494:
495: case MEMBER_TAG_ENUM:
496: ((EnumConstValue) mValue).writeTo(dout);
497: break;
498:
499: case MEMBER_TAG_ARRAY:
500: MemberValue[] values = (MemberValue[]) mValue;
501: dout.writeShort(values.length);
502: for (int i = 0; i < values.length; i++) {
503: values[i].writeTo(dout);
504: }
505: break;
506:
507: case MEMBER_TAG_ANNOTATION:
508: ((Annotation) mValue).writeTo(dout);
509: break;
510: }
511: }
512: }
513:
514: public static class EnumConstValue {
515: private final ConstantUTFInfo mTypeName;
516: private final ConstantUTFInfo mConstName;
517:
518: public EnumConstValue(ConstantUTFInfo typeName,
519: ConstantUTFInfo constName) {
520: mTypeName = typeName;
521: mConstName = constName;
522: }
523:
524: public EnumConstValue(ConstantPool cp, DataInput din)
525: throws IOException {
526: mTypeName = (ConstantUTFInfo) cp.getConstant(din
527: .readUnsignedShort());
528: mConstName = (ConstantUTFInfo) cp.getConstant(din
529: .readUnsignedShort());
530: }
531:
532: public ConstantUTFInfo getTypeName() {
533: return mTypeName;
534: }
535:
536: public ConstantUTFInfo getConstName() {
537: return mConstName;
538: }
539:
540: public int getLength() {
541: return 4;
542: }
543:
544: public void writeTo(DataOutput dout) throws IOException {
545: dout.writeShort(mTypeName.getIndex());
546: dout.writeShort(mConstName.getIndex());
547: }
548: }
549: }
|