123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
- package javassist.bytecode;
-
- import java.util.Map;
- import java.io.IOException;
- import java.io.DataInputStream;
- import java.io.ByteArrayOutputStream;
- import javassist.bytecode.annotation.*;
-
- /**
- * A class representing
- * <code>RuntimeVisibleAnnotations_attribute</code> and
- * <code>RuntimeInvisibleAnnotations_attribute</code>.
- *
- * <p>To obtain an AnnotationAttribute object, invoke
- * <code>getAttribute(AnnotationsAttribute.visibleTag)</code>
- * in <code>ClassFile</code>, <code>MethodInfo</code>,
- * or <code>FieldInfo</code>. The obtained attribute is a
- * runtime visible annotations attribute.
- * If the parameter is
- * <code>AnnotationAttribute.invisibleTag</code>, then the obtained
- * attribute is a runtime invisible one.
- *
- * <p>For example,
- *
- * <ul><pre>
- * import javassist.bytecode.annotation.Annotation;
- * :
- * CtMethod m = ... ;
- * MethodInfo minfo = m.getMethodInfo();
- * AnnotationsAttribute attr = (AnnotationsAttribute)
- * minfo.getAttribute(AnnotationsAttribute.invisibleTag);
- * Annotation an = attr.getAnnotation("Author");
- * String s = ((StringMemberValue)an.getMemberValue("name")).getValue();
- * System.out.println("@Author(name=" + s + ")");
- * </pre></ul>
- *
- * <p>This code snippet retrieves an annotation of the type <code>Author</code>
- * from the <code>MethodInfo</code> object specified by <code>minfo</code>.
- * Then, it prints the value of <code>name</code> in <code>Author</code>.
- *
- * <p>If the annotation type <code>Author</code> is annotated by a meta annotation:
- *
- * <ul><pre>
- * @Retention(RetentionPolicy.RUNTIME)
- * </pre></ul>
- *
- * <p>Then <code>Author</code> is visible at runtime. Therefore, the third
- * statement of the code snippet above must be changed into:
- *
- * <ul><pre>
- * AnnotationsAttribute attr = (AnnotationsAttribute)
- * minfo.getAttribute(AnnotationsAttribute.visibleTag);
- * </pre></ul>
- *
- * <p>The attribute tag must be <code>visibleTag</code> instead of
- * <code>invisibleTag</code>.
- *
- * <p>If the member value of an annotation is not specified, the default value
- * is used as that member value. If so, <code>getMemberValue()</code> in
- * <code>Annotation</code> returns <code>null</code>
- * since the default value is not included in the
- * <code>AnnotationsAttribute</code>. It is included in the
- * <code>AnnotationDefaultAttribute</code> of the method declared in the
- * annotation type.
- *
- * <p>If you want to record a new AnnotationAttribute object, execute the
- * following snippet:
- *
- * <ul><pre>
- * ClassFile cf = ... ;
- * ConstPool cp = cf.getConstPool();
- * AnnotationsAttribute attr
- * = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
- * Annotation a = new Annotation("Author", cp);
- * a.addMemberValue("name", new StringMemberValue("Chiba", cp));
- * attr.setAnnotation(a);
- * cf.addAttribute(attr);
- * cf.setVersionToJava5();
- * </pre></ul>
- *
- * <p>The last statement is necessary if the class file was produced by
- * Javassist or JDK 1.4. Otherwise, it is not necessary.
- *
- * @see AnnotationDefaultAttribute
- * @see javassist.bytecode.annotation.Annotation
- */
- public class AnnotationsAttribute extends AttributeInfo {
- /**
- * The name of the <code>RuntimeVisibleAnnotations</code> attribute.
- */
- public static final String visibleTag = "RuntimeVisibleAnnotations";
-
- /**
- * The name of the <code>RuntimeInvisibleAnnotations</code> attribute.
- */
- public static final String invisibleTag = "RuntimeInvisibleAnnotations";
-
- /**
- * Constructs a <code>Runtime(In)VisisbleAnnotations_attribute</code>.
- *
- * @param cp constant pool
- * @param attrname attribute name (<code>visibleTag</code> or
- * <code>invisibleTag</code>).
- * @param info the contents of this attribute. It does not
- * include <code>attribute_name_index</code> or
- * <code>attribute_length</code>.
- */
- public AnnotationsAttribute(ConstPool cp, String attrname, byte[] info) {
- super(cp, attrname, info);
- }
-
- /**
- * Constructs an empty
- * <code>Runtime(In)VisisbleAnnotations_attribute</code>.
- * A new annotation can be later added to the created attribute
- * by <code>setAnnotations()</code>.
- *
- * @param cp constant pool
- * @param attrname attribute name (<code>visibleTag</code> or
- * <code>invisibleTag</code>).
- * @see #setAnnotations(Annotation[])
- */
- public AnnotationsAttribute(ConstPool cp, String attrname) {
- this(cp, attrname, new byte[] { 0, 0 });
- }
-
- /**
- * @param n the attribute name.
- */
- AnnotationsAttribute(ConstPool cp, int n, DataInputStream in)
- throws IOException
- {
- super(cp, n, in);
- }
-
- /**
- * Returns <code>num_annotations</code>.
- */
- public int numAnnotations() {
- return ByteArray.readU16bit(info, 0);
- }
-
- /**
- * Copies this attribute and returns a new copy.
- */
- public AttributeInfo copy(ConstPool newCp, Map classnames) {
- Copier copier = new Copier(info, constPool, newCp, classnames);
- try {
- copier.annotationArray();
- return new AnnotationsAttribute(newCp, getName(), copier.close());
- }
- catch (Exception e) {
- throw new RuntimeException(e.toString());
- }
- }
-
- /**
- * Parses the annotations and returns a data structure representing
- * the annotation with the specified type. See also
- * <code>getAnnotations()</code> as to the returned data structure.
- *
- * @param type the annotation type.
- * @return null if the specified annotation type is not included.
- * @see #getAnnotations()
- */
- public Annotation getAnnotation(String type) {
- Annotation[] annotations = getAnnotations();
- for (int i = 0; i < annotations.length; i++) {
- if (annotations[i].getTypeName().equals(type))
- return annotations[i];
- }
-
- return null;
- }
-
- /**
- * Adds an annotation. If there is an annotation with the same type,
- * it is removed before the new annotation is added.
- *
- * @param annotation the added annotation.
- */
- public void addAnnotation(Annotation annotation) {
- String type = annotation.getTypeName();
- Annotation[] annotations = getAnnotations();
- for (int i = 0; i < annotations.length; i++) {
- if (annotations[i].getTypeName().equals(type)) {
- annotations[i] = annotation;
- setAnnotations(annotations);
- return;
- }
- }
-
- Annotation[] newlist = new Annotation[annotations.length + 1];
- System.arraycopy(annotations, 0, newlist, 0, annotations.length);
- newlist[annotations.length] = annotation;
- setAnnotations(newlist);
- }
-
- /**
- * Parses the annotations and returns a data structure representing
- * that parsed annotations. Note that changes of the node values of the
- * returned tree are not reflected on the annotations represented by
- * this object unless the tree is copied back to this object by
- * <code>setAnnotations()</code>.
- *
- * @see #setAnnotations(Annotation[])
- */
- public Annotation[] getAnnotations() {
- try {
- return new Parser(info, constPool).parseAnnotations();
- }
- catch (Exception e) {
- throw new RuntimeException(e.toString());
- }
- }
-
- /**
- * Changes the annotations represented by this object according to
- * the given array of <code>Annotation</code> objects.
- *
- * @param annotations the data structure representing the
- * new annotations.
- */
- public void setAnnotations(Annotation[] annotations) {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- AnnotationsWriter writer = new AnnotationsWriter(output, constPool);
- try {
- int n = annotations.length;
- writer.numAnnotations(n);
- for (int i = 0; i < n; ++i)
- annotations[i].write(writer);
-
- writer.close();
- }
- catch (IOException e) {
- throw new RuntimeException(e); // should never reach here.
- }
-
- set(output.toByteArray());
- }
-
- /**
- * Changes the annotations. A call to this method is equivalent to:
- * <ul><pre>setAnnotations(new Annotation[] { annotation })</pre></ul>
- *
- * @param annotation the data structure representing
- * the new annotation.
- */
- public void setAnnotation(Annotation annotation) {
- setAnnotations(new Annotation[] { annotation });
- }
-
- /**
- * Returns a string representation of this object.
- */
- public String toString() {
- Annotation[] a = getAnnotations();
- StringBuffer sbuf = new StringBuffer();
- int i = 0;
- while (i < a.length) {
- sbuf.append(a[i++].toString());
- if (i != a.length)
- sbuf.append(", ");
- }
-
- return sbuf.toString();
- }
-
- static class Walker {
- byte[] info;
-
- Walker(byte[] attrInfo) {
- info = attrInfo;
- }
-
- final void parameters() throws Exception {
- int numParam = info[0] & 0xff;
- parameters(numParam, 1);
- }
-
- void parameters(int numParam, int pos) throws Exception {
- for (int i = 0; i < numParam; ++i)
- pos = annotationArray(pos);
- }
-
- final void annotationArray() throws Exception {
- annotationArray(0);
- }
-
- final int annotationArray(int pos) throws Exception {
- int num = ByteArray.readU16bit(info, pos);
- return annotationArray(pos + 2, num);
- }
-
- int annotationArray(int pos, int num) throws Exception {
- for (int i = 0; i < num; ++i)
- pos = annotation(pos);
-
- return pos;
- }
-
- final int annotation(int pos) throws Exception {
- int type = ByteArray.readU16bit(info, pos);
- int numPairs = ByteArray.readU16bit(info, pos + 2);
- return annotation(pos + 4, type, numPairs);
- }
-
- int annotation(int pos, int type, int numPairs) throws Exception {
- for (int j = 0; j < numPairs; ++j)
- pos = memberValuePair(pos);
-
- return pos;
- }
-
- final int memberValuePair(int pos) throws Exception {
- int nameIndex = ByteArray.readU16bit(info, pos);
- return memberValuePair(pos + 2, nameIndex);
- }
-
- int memberValuePair(int pos, int nameIndex) throws Exception {
- return memberValue(pos);
- }
-
- final int memberValue(int pos) throws Exception {
- int tag = info[pos] & 0xff;
- if (tag == 'e') {
- int typeNameIndex = ByteArray.readU16bit(info, pos + 1);
- int constNameIndex = ByteArray.readU16bit(info, pos + 3);
- enumMemberValue(typeNameIndex, constNameIndex);
- return pos + 5;
- }
- else if (tag == 'c') {
- int index = ByteArray.readU16bit(info, pos + 1);
- classMemberValue(index);
- return pos + 3;
- }
- else if (tag == '@')
- return annotationMemberValue(pos + 1);
- else if (tag == '[') {
- int num = ByteArray.readU16bit(info, pos + 1);
- return arrayMemberValue(pos + 3, num);
- }
- else { // primitive types or String.
- int index = ByteArray.readU16bit(info, pos + 1);
- constValueMember(tag, index);
- return pos + 3;
- }
- }
-
- void constValueMember(int tag, int index) throws Exception {}
-
- void enumMemberValue(int typeNameIndex, int constNameIndex)
- throws Exception {
- }
-
- void classMemberValue(int index) throws Exception {}
-
- int annotationMemberValue(int pos) throws Exception {
- return annotation(pos);
- }
-
- int arrayMemberValue(int pos, int num) throws Exception {
- for (int i = 0; i < num; ++i) {
- pos = memberValue(pos);
- }
-
- return pos;
- }
- }
-
- static class Copier extends Walker {
- ByteArrayOutputStream output;
- AnnotationsWriter writer;
- ConstPool srcPool, destPool;
- Map classnames;
-
- /**
- * Constructs a copier. This copier renames some class names
- * into the new names specified by <code>map</code> when it copies
- * an annotation attribute.
- *
- * @param info the source attribute.
- * @param src the constant pool of the source class.
- * @param dest the constant pool of the destination class.
- * @param map pairs of replaced and substituted class names.
- * It can be null.
- */
- Copier(byte[] info, ConstPool src, ConstPool dest, Map map) {
- super(info);
- output = new ByteArrayOutputStream();
- writer = new AnnotationsWriter(output, dest);
- srcPool = src;
- destPool = dest;
- classnames = map;
- }
-
- byte[] close() throws IOException {
- writer.close();
- return output.toByteArray();
- }
-
- void parameters(int numParam, int pos) throws Exception {
- writer.numParameters(numParam);
- super.parameters(numParam, pos);
- }
-
- int annotationArray(int pos, int num) throws Exception {
- writer.numAnnotations(num);
- return super.annotationArray(pos, num);
- }
-
- int annotation(int pos, int type, int numPairs) throws Exception {
- writer.annotation(copy(type), numPairs);
- return super.annotation(pos, type, numPairs);
- }
-
- int memberValuePair(int pos, int nameIndex) throws Exception {
- writer.memberValuePair(copy(nameIndex));
- return super.memberValuePair(pos, nameIndex);
- }
-
- void constValueMember(int tag, int index) throws Exception {
- writer.constValueIndex(tag, copy(index));
- super.constValueMember(tag, index);
- }
-
- void enumMemberValue(int typeNameIndex, int constNameIndex)
- throws Exception
- {
- writer.enumConstValue(copy(typeNameIndex), copy(constNameIndex));
- super.enumMemberValue(typeNameIndex, constNameIndex);
- }
-
- void classMemberValue(int index) throws Exception {
- writer.classInfoIndex(copy(index));
- super.classMemberValue(index);
- }
-
- int annotationMemberValue(int pos) throws Exception {
- writer.annotationValue();
- return super.annotationMemberValue(pos);
- }
-
- int arrayMemberValue(int pos, int num) throws Exception {
- writer.arrayValue(num);
- return super.arrayMemberValue(pos, num);
- }
-
- /**
- * Copies a constant pool entry into the destination constant pool
- * and returns the index of the copied entry.
- *
- * @param srcIndex the index of the copied entry into the source
- * constant pool.
- * @return the index of the copied item into the destination
- * constant pool.
- */
- int copy(int srcIndex) {
- return srcPool.copy(srcIndex, destPool, classnames);
- }
- }
-
- static class Parser extends Walker {
- ConstPool pool;
- Annotation[][] allParams; // all parameters
- Annotation[] allAnno; // all annotations
- Annotation currentAnno; // current annotation
- MemberValue currentMember; // current member
-
- /**
- * Constructs a parser. This parser constructs a parse tree of
- * the annotations.
- *
- * @param info the attribute.
- * @param src the constant pool.
- */
- Parser(byte[] info, ConstPool cp) {
- super(info);
- pool = cp;
- }
-
- Annotation[][] parseParameters() throws Exception {
- parameters();
- return allParams;
- }
-
- Annotation[] parseAnnotations() throws Exception {
- annotationArray();
- return allAnno;
- }
-
- MemberValue parseMemberValue() throws Exception {
- memberValue(0);
- return currentMember;
- }
-
- void parameters(int numParam, int pos) throws Exception {
- Annotation[][] params = new Annotation[numParam][];
- for (int i = 0; i < numParam; ++i) {
- pos = annotationArray(pos);
- params[i] = allAnno;
- }
-
- allParams = params;
- }
-
- int annotationArray(int pos, int num) throws Exception {
- Annotation[] array = new Annotation[num];
- for (int i = 0; i < num; ++i) {
- pos = annotation(pos);
- array[i] = currentAnno;
- }
-
- allAnno = array;
- return pos;
- }
-
- int annotation(int pos, int type, int numPairs) throws Exception {
- currentAnno = new Annotation(type, pool);
- return super.annotation(pos, type, numPairs);
- }
-
- int memberValuePair(int pos, int nameIndex) throws Exception {
- pos = super.memberValuePair(pos, nameIndex);
- currentAnno.addMemberValue(nameIndex, currentMember);
- return pos;
- }
-
- void constValueMember(int tag, int index) throws Exception {
- MemberValue m;
- ConstPool cp = pool;
- switch (tag) {
- case 'B' :
- m = new ByteMemberValue(index, cp);
- break;
- case 'C' :
- m = new CharMemberValue(index, cp);
- break;
- case 'D' :
- m = new DoubleMemberValue(index, cp);
- break;
- case 'F' :
- m = new FloatMemberValue(index, cp);
- break;
- case 'I' :
- m = new IntegerMemberValue(index, cp);
- break;
- case 'J' :
- m = new LongMemberValue(index, cp);
- break;
- case 'S' :
- m = new ShortMemberValue(index, cp);
- break;
- case 'Z' :
- m = new BooleanMemberValue(index, cp);
- break;
- case 's' :
- m = new StringMemberValue(index, cp);
- break;
- default :
- throw new RuntimeException("unknown tag:" + tag);
- }
-
- currentMember = m;
- super.constValueMember(tag, index);
- }
-
- void enumMemberValue(int typeNameIndex, int constNameIndex)
- throws Exception
- {
- currentMember = new EnumMemberValue(typeNameIndex,
- constNameIndex, pool);
- super.enumMemberValue(typeNameIndex, constNameIndex);
- }
-
- void classMemberValue(int index) throws Exception {
- currentMember = new ClassMemberValue(index, pool);
- super.classMemberValue(index);
- }
-
- int annotationMemberValue(int pos) throws Exception {
- Annotation anno = currentAnno;
- pos = super.annotationMemberValue(pos);
- currentMember = new AnnotationMemberValue(currentAnno, pool);
- currentAnno = anno;
- return pos;
- }
-
- int arrayMemberValue(int pos, int num) throws Exception {
- ArrayMemberValue amv = new ArrayMemberValue(pool);
- MemberValue[] elements = new MemberValue[num];
- for (int i = 0; i < num; ++i) {
- pos = memberValue(pos);
- elements[i] = currentMember;
- }
-
- amv.setValue(elements);
- currentMember = amv;
- return pos;
- }
- }
- }
|