/** * AnnotationElement are used by Annotation attributes * @author $Author: Iouri Kharon $ * @version $Revision: 1.0 $ */ package jas; import java.io.*; import java.util.Vector; import java.util.Enumeration; public class AnnotationElement { private boolean array; private char sign; private CP name, exttype; private Vector values; private static final char type_int = 'I'; // integer private static final char type_byte = 'B'; // signed byte private static final char type_char = 'C'; // unicode character private static final char type_short = 'S'; // signed short private static final char type_bool = 'Z'; // boolean true or false // end of int types private static final char type_float = 'F'; // single precision IEEE foat private static final char type_double = 'D'; // double precision IEEE float private static final char type_long = 'J'; // long integer //prefix private static final char type_array = '['; //annotation special private static final char type_string = 's'; // constant string private static final char type_class = 'c'; // return type descriptor //complex types private static final char type_enum = 'e'; // enum constant (type + name) private static final char type_annot = '@'; // nested annotation private static void badsignature() throws jasError { throw new jasError("invalid type signature for annotation field"); } public AnnotationElement(String name, String type, String exttype) throws jasError { this.name = null; if(name != null) this.name = new AsciiCP(name); values = new Vector(); array = false; sign = type.charAt(0); if(sign != type_array) { if(type.length() != 1) badsignature(); } else { array = true; if(type.length() != 2) badsignature(); sign = type.charAt(1); } switch(sign) { default: badsignature(); case type_enum: case type_annot: if(exttype == null) badsignature(); this.exttype = new AsciiCP(exttype); break; case type_int: case type_byte: case type_char: case type_short: case type_bool: case type_float: case type_double: case type_long: case type_string: case type_class: if(exttype != null) badsignature(); this.exttype = null; break; } } void addValue(Object value) throws jasError { if(value == null) Annotation.ParserError(); if(!array && values.size() != 0) throw new jasError("too many values for nonarray annotation field type"); CP cp = null; switch(sign) { case type_char: case type_bool: case type_byte: case type_short: case type_int: if(value instanceof Integer) { int val = ((Integer)value).intValue(); boolean badval = false; switch(sign) { case type_bool: if(val < 0 || val > 1) badval = true; break; case type_char: if(val < 0 || val > 0xFFFF) badval = true; break; case type_byte: if(val < -128 || val > 127) badval = true; case type_short: if(val < -32768 || val > 32767) badval = true; default: // type_int break; } if(badval) throw new jasError("annotation field value exceed range of type", true); cp = new IntegerCP(val); } break; case type_float: if(value instanceof Float) cp = new FloatCP(((Float)value).floatValue()); break; case type_double: if(value instanceof Double) { cp = new DoubleCP(((Double)value).doubleValue()); } else if(value instanceof Float) { cp = new DoubleCP(((Float)value).floatValue()); } break; case type_long: if(value instanceof Long) { cp = new LongCP(((Long)value).longValue()); } else if(value instanceof Integer) { cp = new LongCP(((Integer)value).intValue()); } break; case type_string: case type_class: case type_enum: if(value instanceof String) cp = new AsciiCP((String)value); break; case type_annot: if(value instanceof Annotation) cp = (Annotation)value; default: break; } if(cp == null) throw new jasError("incompatible value for annotation field type"); values.add(cp); } public AsciiCP nestType() throws jasError { if(sign != type_annot) Annotation.ParserError(); return((AsciiCP)exttype); } public void done() throws jasError { switch(values.size()) { case 1: return; default: if(array) return; //pass thru case 0: Annotation.ParserError(); } } void resolve(ClassEnv e) { if(name != null) e.addCPItem(name); if(sign == type_enum) e.addCPItem(exttype); for(Enumeration en = values.elements(); en.hasMoreElements(); ) { CP cp = ((CP)en.nextElement()); if(sign != type_annot) e.addCPItem(cp); else cp.resolve(e); } } int size() throws jasError { done(); int len; if(sign == type_annot) { len = values.size(); // tags for(Enumeration en = values.elements(); en.hasMoreElements(); ) len += ((Annotation)en.nextElement()).size(); } else { len = 1+2; if(sign == type_enum) len += 2; len *= values.size(); } if(array) len += 1+2; if(name != null) len += 2; return(len); } void write(ClassEnv e, DataOutputStream out) throws IOException, jasError { done(); if(name != null) out.writeShort(e.getCPIndex(name)); if(array) { out.writeByte(type_array); out.writeShort((short)values.size()); } short id = 0; if(sign == type_enum) id = e.getCPIndex(exttype); for(Enumeration en = values.elements(); en.hasMoreElements(); ) { out.writeByte(sign); CP cp = ((CP)en.nextElement()); switch(sign) { case type_annot: ((Annotation)cp).write(e, out); break; case type_enum: out.writeShort(id); //pass thru default: out.writeShort(e.getCPIndex(cp)); break; } } } }