package org.unsynchronized; import java.io.*; import java.util.*; /** * This class represents a field within a class description/declaration (classdesc). It * contains information about the type and name of the field. Fields themselves don't * have a handle; inside the stream, they exist only as part of a class description. */ public class Field { /** * The type of the field. */ public FieldType type; /** * The name of the field. */ public String name; /** * The string object representing the class name. */ public StringObject classname; private boolean isInnerClassReference = false; /** * Tells whether or not this class is an inner class reference. This value is set by * connectMemberClasses() -- if this hasn't been called, or if the field hasn't been * otherwise set by setIsInnerClassReference(), it will be false; * * @return true if the class is an inner class reference */ public boolean isInnerClassReference() { return isInnerClassReference; } /** * Sets the flag that denotes whether this class is an inner class reference. * * @param nis the value to set; true iff the class is an inner class reference. */ public void setIsInnerClassReference(boolean nis) { this.isInnerClassReference = nis; } /** * Constructor. * * @param type the field type * @param name the field name * @param classname the class name */ public Field(FieldType type, String name, StringObject classname) throws ValidityException { this.type = type; this.name = name; this.classname = classname; if(classname != null) { validate(classname.value); } } /** * Constructor for simple fields. * * @param type the field type * @param name the field name */ public Field(FieldType type, String name) throws ValidityException { this(type, name, null); } /** * Get a string representing the type for this field in Java (the language) * format. * @return a string representing the fully-qualified type of the field * @throws IOException if a validity or I/O error occurs */ public String getJavaType() throws IOException { return JDeserialize.resolveJavaType(this.type, this.classname == null ? null : this.classname.value, true, false); } /** * Changes the name of an object reference to the name specified. This is used by * the inner-class-connection code to fix up field references. * @param newname the fully-qualified class * @throws ValidityException if the field isn't a reference type, or another * validity error occurs */ public void setReferenceTypeName(String newname) throws ValidityException { if(this.type != FieldType.OBJECT) { throw new ValidityException("can't fix up a non-reference field!"); } String nname = "L" + newname.replace('.', '/') + ";"; this.classname.value = nname; } public void validate(String jt) throws ValidityException { if(this.type == FieldType.OBJECT) { if(jt == null) { throw new ValidityException("classname can't be null"); } if(jt.charAt(0) != 'L') { throw new ValidityException("invalid object field type descriptor: " + classname.value); } int end = jt.indexOf(';'); if(end == -1 || end != (jt.length()-1)) { throw new ValidityException("invalid object field type descriptor (must end with semicolon): " + classname.value); } } } }