001 package edu.rice.cs.cunit.classFile.attributes; 002 003 import edu.rice.cs.cunit.classFile.constantPool.AUTFPoolInfo; 004 import edu.rice.cs.cunit.classFile.constantPool.ConstantPool; 005 import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckUTFVisitor; 006 import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable; 007 import edu.rice.cs.cunit.util.Types; 008 009 import java.io.ByteArrayOutputStream; 010 import java.io.IOException; 011 012 /** 013 * @author Mathias Ricken 014 */ 015 public abstract class AMultipleNamedAnnotationsAttributeInfo extends AAnnotationsAttributeInfo { 016 /** 017 * Storage class for name and annotations. 018 */ 019 public static class NamedAnnotationsRecord { 020 private final AUTFPoolInfo name; 021 private final AAnnotationsAttributeInfo.Annotation[] annotations; 022 023 public NamedAnnotationsRecord(AUTFPoolInfo name, 024 AAnnotationsAttributeInfo.Annotation[] annotations) { 025 this.name = name; 026 this.annotations = new AAnnotationsAttributeInfo.Annotation[annotations.length]; 027 System.arraycopy(annotations,0,this.annotations,0,annotations.length); 028 } 029 030 public AUTFPoolInfo getName() { 031 return name; 032 } 033 034 public Annotation[] getAnnotations() { 035 AAnnotationsAttributeInfo.Annotation[] as = new AAnnotationsAttributeInfo.Annotation[annotations.length]; 036 System.arraycopy(annotations,0,as,0,annotations.length); 037 return as; 038 } 039 } 040 041 public AMultipleNamedAnnotationsAttributeInfo(AUTFPoolInfo name, byte data[], ConstantPool cp) { 042 super(name, data, cp); 043 } 044 045 /** 046 * Return the number of entities. 047 * 048 * @return number of entities 049 * 050 * @throws ClassFormatError 051 */ 052 public int getEntityCount() { 053 return _data[0]; 054 } 055 056 /** 057 * Return an array of entity annotations records. 058 * 059 * @return array of entity annotations records. 060 * 061 * @throws ClassFormatError if the attribute has an incorrect format 062 */ 063 public NamedAnnotationsRecord[] getEntityAnnotations() throws ClassFormatError { 064 int count = getEntityCount(); 065 NamedAnnotationsRecord[] nar = new NamedAnnotationsRecord[count]; 066 int index = 1; 067 for(int i = 0; i < count; ++i) { 068 AUTFPoolInfo name = _constantPool.get(Types.ushortFromBytes(_data, index+0)).execute(CheckUTFVisitor.singleton(), null); 069 short annCount = (short)(0xffff & Types.ushortFromBytes(_data, index+2)); 070 071 index += 4; 072 073 AAnnotationsAttributeInfo.Annotation[] ann = new AAnnotationsAttributeInfo.Annotation[annCount]; 074 for(short annIndex = 0; annIndex < annCount; ++annIndex) { 075 ann[annIndex] = new AAnnotationsAttributeInfo.Annotation(_constantPool,_data,index); 076 index += ann[annIndex].getSize(); 077 } 078 079 nar[i] = new NamedAnnotationsRecord(name, ann); 080 } 081 return nar; 082 } 083 084 /** 085 * Set the array of entity annotations records. 086 * 087 * @param nars array of entity annotations records 088 */ 089 public void setLocalVariableAnnotations(NamedAnnotationsRecord[] nars) { 090 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 091 baos.write((byte)nars.length); 092 for(NamedAnnotationsRecord r: nars) { 093 byte[] header = new byte[10]; 094 Types.bytesFromShort((short)(0xffff & _constantPool.indexOf(r.name)), header, 0); 095 Types.bytesFromShort((short)(0xffff & r.annotations.length), header, 2); 096 baos.write(header, 0, 4); 097 for(int i = 0; i < r.annotations.length; ++i) { 098 try { 099 r.annotations[i].writeToByteArrayOutputStream(_constantPool,baos); 100 } 101 catch(IOException e) { 102 throw new ClassFormatError("Error while writing out annotations"); 103 } 104 } 105 } 106 setData(baos.toByteArray()); 107 } 108 109 /** 110 * Return a human-readable version of this attribute. 111 * 112 * @return string 113 */ 114 public String toString() { 115 StringBuilder x = new StringBuilder(); 116 x.append(_name); 117 x.append(" <"); 118 x.append(getEntityCount()); 119 x.append(' '); 120 x.append(getEntityName()); 121 x.append("(s) { "); 122 boolean first = true; 123 for(NamedAnnotationsRecord nars : getEntityAnnotations()) { 124 if (first) { 125 first = false; 126 } 127 else { 128 x.append(", "); 129 } 130 x.append("(name="); 131 x.append(nars.name.toString()); 132 x.append(", annotations "); 133 x.append(nars.annotations.length); 134 x.append(": {"); 135 136 boolean firstAnn = true; 137 for(AAnnotationsAttributeInfo.Annotation ann : nars.annotations) { 138 if (firstAnn) { 139 firstAnn = false; 140 } 141 else { 142 x.append(", "); 143 } 144 x.append(ann.toString()); 145 } 146 x.append(" }"); 147 } 148 x.append(" } >"); 149 return x.toString(); 150 } 151 152 /** 153 * Return the name of the entity, e.g. "parameter" or "local variable". 154 * @return name of tne entity 155 */ 156 public abstract String getEntityName(); 157 158 /** 159 * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them. 160 * 161 * @param startPC program counter to start at 162 * @param deltaPC change in program counter values 163 */ 164 public void adjustPC(int startPC, int deltaPC) { 165 // nothing to do 166 } 167 168 /** 169 * Translate the program counter values contained in this attribute from an old line number table to a new one. 170 * 171 * @param index critical point (insertion or deletion point) 172 * @param deltaIndex delta value to add to all old line numbers greater than the critical point 173 * @param oldLnt old line number table 174 * @param newLnt new line number table 175 */ 176 public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) { 177 // nothing to do 178 } 179 180 /** 181 * Creates and returns a copy of this object. 182 */ 183 public Object clone() throws CloneNotSupportedException { 184 return super.clone(); 185 } 186 }