All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.bytecode.AnnotationsAttribute Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.3.0
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- 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,
 * or the Apache License Version 2.0.
 *
 * 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 com.feilong.lib.javassist.bytecode;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.feilong.lib.javassist.bytecode.annotation.Annotation;
import com.feilong.lib.javassist.bytecode.annotation.AnnotationMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.AnnotationsWriter;
import com.feilong.lib.javassist.bytecode.annotation.ArrayMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.BooleanMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.ByteMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.CharMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.ClassMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.DoubleMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.EnumMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.FloatMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.IntegerMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.LongMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.MemberValue;
import com.feilong.lib.javassist.bytecode.annotation.ShortMemberValue;
import com.feilong.lib.javassist.bytecode.annotation.StringMemberValue;

/**
 * A class representing
 * RuntimeVisibleAnnotations_attribute and
 * RuntimeInvisibleAnnotations_attribute.
 *
 * 

* To obtain an AnnotationAttribute object, invoke * getAttribute(AnnotationsAttribute.visibleTag) * in ClassFile, MethodInfo, * or FieldInfo. The obtained attribute is a * runtime visible annotations attribute. * If the parameter is * AnnotationAttribute.invisibleTag, then the obtained * attribute is a runtime invisible one. * *

* For example, * *

 * 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 + ")");
 * 
* *

* This code snippet retrieves an annotation of the type Author * from the MethodInfo object specified by minfo. * Then, it prints the value of name in Author. * *

* If the annotation type Author is annotated by a meta annotation: * *

 * @Retention(RetentionPolicy.RUNTIME)
 * 
* *

* Then Author is visible at runtime. Therefore, the third * statement of the code snippet above must be changed into: * *

 * 
 * AnnotationsAttribute attr = (AnnotationsAttribute) minfo.getAttribute(AnnotationsAttribute.visibleTag);
 * 
* *

* The attribute tag must be visibleTag instead of * invisibleTag. * *

* If the member value of an annotation is not specified, the default value * is used as that member value. If so, getMemberValue() in * Annotation returns null * since the default value is not included in the * AnnotationsAttribute. It is included in the * AnnotationDefaultAttribute of the method declared in the * annotation type. * *

* If you want to record a new AnnotationAttribute object, execute the * following snippet: * *

 * 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();
 * 
* *

* The last statement is necessary if the class file was produced by * javac of JDK 1.4 or earlier. Otherwise, it is not necessary. * * @see AnnotationDefaultAttribute * @see com.feilong.lib.javassist.bytecode.annotation.Annotation */ public class AnnotationsAttribute extends AttributeInfo{ /** * The name of the RuntimeVisibleAnnotations attribute. */ public static final String visibleTag = "RuntimeVisibleAnnotations"; /** * The name of the RuntimeInvisibleAnnotations attribute. */ public static final String invisibleTag = "RuntimeInvisibleAnnotations"; /** * Constructs a Runtime(In)VisibleAnnotations_attribute. * * @param cp * constant pool * @param attrname * attribute name (visibleTag or * invisibleTag). * @param info * the contents of this attribute. It does not * include attribute_name_index or * attribute_length. */ public AnnotationsAttribute(ConstPool cp, String attrname, byte[] info){ super(cp, attrname, info); } /** * @param n * the attribute name. */ AnnotationsAttribute(ConstPool cp, int n, DataInputStream in) throws IOException{ super(cp, n, in); } /** * Returns num_annotations. */ public int numAnnotations(){ return ByteArray.readU16bit(info, 0); } /** * Copies this attribute and returns a new copy. */ @Override 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); } } /** * Parses the annotations and returns a data structure representing * the annotation with the specified type. See also * getAnnotations() 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 (Annotation annotation : annotations){ if (annotation.getTypeName().equals(type)){ return annotation; } } 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); } /** * Removes an annotation by type. * After removing an annotation, if {@link #numAnnotations()} returns 0, * this annotations attribute has to be removed. * * @param type * of annotation to remove * @return whether an annotation with the given type has been removed * @since 3.21 */ public boolean removeAnnotation(String type){ Annotation[] annotations = getAnnotations(); for (int i = 0; i < annotations.length; i++){ if (annotations[i].getTypeName().equals(type)){ Annotation[] newlist = new Annotation[annotations.length - 1]; System.arraycopy(annotations, 0, newlist, 0, i); if (i < annotations.length - 1){ System.arraycopy(annotations, i + 1, newlist, i, annotations.length - i - 1); } setAnnotations(newlist); return true; } } return false; } /** * 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 * setAnnotations(). * * @see #setAnnotations(Annotation[]) */ public Annotation[] getAnnotations(){ try{ return new Parser(info, constPool).parseAnnotations(); }catch (Exception e){ throw new RuntimeException(e); } } /** * Changes the annotations represented by this object according to * the given array of Annotation 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: * *

     * setAnnotations(new Annotation[] { annotation })
     * 
* * @param annotation * the data structure representing * the new annotation. */ public void setAnnotation(Annotation annotation){ setAnnotations(new Annotation[] { annotation }); } /** * @param oldname * a JVM class name. * @param newname * a JVM class name. */ @Override void renameClass(String oldname,String newname){ Map map = new HashMap<>(); map.put(oldname, newname); renameClass(map); } @Override void renameClass(Map classnames){ Renamer renamer = new Renamer(info, getConstPool(), classnames); try{ renamer.annotationArray(); }catch (Exception e){ throw new RuntimeException(e); } } @Override void getRefClasses(Map classnames){ renameClass(classnames); } /** * Returns a string representation of this object. */ @Override public String toString(){ Annotation[] a = getAnnotations(); StringBuilder sbuf = new StringBuilder(); 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; } /** * {@code element_value_paris} */ final int memberValuePair(int pos) throws Exception{ int nameIndex = ByteArray.readU16bit(info, pos); return memberValuePair(pos + 2, nameIndex); } /** * {@code element_value_paris[]} */ int memberValuePair(int pos,int nameIndex) throws Exception{ return memberValue(pos); } /** * {@code element_value} */ 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(pos, typeNameIndex, constNameIndex); return pos + 5; }else if (tag == 'c'){ int index = ByteArray.readU16bit(info, pos + 1); classMemberValue(pos, 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; } } /** * {@code const_value_index} */ void constValueMember(int tag,int index) throws Exception{ } /** * {@code enum_const_value} */ void enumMemberValue(int pos,int typeNameIndex,int constNameIndex) throws Exception{ } /** * {@code class_info_index} */ void classMemberValue(int pos,int index) throws Exception{ } /** * {@code annotation_value} */ int annotationMemberValue(int pos) throws Exception{ return annotation(pos); } /** * {@code array_value} */ int arrayMemberValue(int pos,int num) throws Exception{ for (int i = 0; i < num; ++i){ pos = memberValue(pos); } return pos; } } static class Renamer extends Walker{ ConstPool cpool; Map classnames; /** * Constructs a renamer. It renames some class names * into the new names specified by map. * * @param info * the annotations attribute. * @param cp * the constant pool. * @param map * pairs of replaced and substituted class names. * It can be null. */ Renamer(byte[] info, ConstPool cp, Map map){ super(info); cpool = cp; classnames = map; } @Override int annotation(int pos,int type,int numPairs) throws Exception{ renameType(pos - 4, type); return super.annotation(pos, type, numPairs); } @Override void enumMemberValue(int pos,int typeNameIndex,int constNameIndex) throws Exception{ renameType(pos + 1, typeNameIndex); super.enumMemberValue(pos, typeNameIndex, constNameIndex); } @Override void classMemberValue(int pos,int index) throws Exception{ renameType(pos + 1, index); super.classMemberValue(pos, index); } private void renameType(int pos,int index){ String name = cpool.getUtf8Info(index); String newName = Descriptor.rename(name, classnames); if (!name.equals(newName)){ int index2 = cpool.addUtf8Info(newName); ByteArray.write16bit(index2, info, 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 map 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){ this(info, src, dest, map, true); } Copier(byte[] info, ConstPool src, ConstPool dest, Map map, boolean makeWriter){ super(info); output = new ByteArrayOutputStream(); if (makeWriter){ writer = new AnnotationsWriter(output, dest); } srcPool = src; destPool = dest; classnames = map; } byte[] close() throws IOException{ writer.close(); return output.toByteArray(); } @Override void parameters(int numParam,int pos) throws Exception{ writer.numParameters(numParam); super.parameters(numParam, pos); } @Override int annotationArray(int pos,int num) throws Exception{ writer.numAnnotations(num); return super.annotationArray(pos, num); } @Override int annotation(int pos,int type,int numPairs) throws Exception{ writer.annotation(copyType(type), numPairs); return super.annotation(pos, type, numPairs); } @Override int memberValuePair(int pos,int nameIndex) throws Exception{ writer.memberValuePair(copy(nameIndex)); return super.memberValuePair(pos, nameIndex); } @Override void constValueMember(int tag,int index) throws Exception{ writer.constValueIndex(tag, copy(index)); super.constValueMember(tag, index); } @Override void enumMemberValue(int pos,int typeNameIndex,int constNameIndex) throws Exception{ writer.enumConstValue(copyType(typeNameIndex), copy(constNameIndex)); super.enumMemberValue(pos, typeNameIndex, constNameIndex); } @Override void classMemberValue(int pos,int index) throws Exception{ writer.classInfoIndex(copyType(index)); super.classMemberValue(pos, index); } @Override int annotationMemberValue(int pos) throws Exception{ writer.annotationValue(); return super.annotationMemberValue(pos); } @Override 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); } /** * Copies a constant pool entry into the destination constant pool * and returns the index of the copied entry. That entry must be * a Utf8Info representing a class name in the L; form. * * @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 copyType(int srcIndex){ String name = srcPool.getUtf8Info(srcIndex); String newName = Descriptor.rename(name, classnames); return destPool.addUtf8Info(newName); } } 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; } @Override 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; } @Override 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; } @Override int annotation(int pos,int type,int numPairs) throws Exception{ currentAnno = new Annotation(type, pool); return super.annotation(pos, type, numPairs); } @Override int memberValuePair(int pos,int nameIndex) throws Exception{ pos = super.memberValuePair(pos, nameIndex); currentAnno.addMemberValue(nameIndex, currentMember); return pos; } @Override 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); } @Override void enumMemberValue(int pos,int typeNameIndex,int constNameIndex) throws Exception{ currentMember = new EnumMemberValue(typeNameIndex, constNameIndex, pool); super.enumMemberValue(pos, typeNameIndex, constNameIndex); } @Override void classMemberValue(int pos,int index) throws Exception{ currentMember = new ClassMemberValue(index, pool); super.classMemberValue(pos, index); } @Override int annotationMemberValue(int pos) throws Exception{ Annotation anno = currentAnno; pos = super.annotationMemberValue(pos); currentMember = new AnnotationMemberValue(currentAnno, pool); currentAnno = anno; return pos; } @Override 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; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy