// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.library; import java.io.IOException; import java.lang.reflect.Constructor; /** * A simple field value. Unlike complex elements, which are * stored as child objects of their parent, simple fields (i.e. attributes or * elements that have no children) are wrapped in a SimpleField instance and * stored in the field table of their parent object. * * @author Eric Petersen * @version 1.0 */ public class SimpleField<T> extends Element { /** * */ private static final long serialVersionUID = -384984737821123229L; /** * The SIF datatype wrapper */ private SIFSimpleType<T> fValue; /** * @param parent The SIFElement that is the parent of this field * @param def The metadata definition of this field * @param value A typed subclass of SIFSimpleType */ public SimpleField( SIFElement parent, ElementDef def, SIFSimpleType<T> value ) { super(def); if( value == null ) { throw new IllegalArgumentException( "Cannot construct an instance of " + this.getClass().getCanonicalName() + " with a null value. " + "Create an appropriate SifSimpleType subclass to wrap the null value." ); } fParent = parent; fValue = value; } /* (non-Javadoc) * @see openadk.library.SimpleField#getTextValue(openadk.library.SIFFormatter) */ public String getTextValue( SIFFormatter formatter ) { return fValue.toString( formatter ); } /** * @param value * @param formatter * @throws ADKParsingException */ public void setTextValue( String value, SIFFormatter formatter ) throws ADKParsingException { fValue = fValue.getTypeConverter().parse( formatter, value ); } /* (non-Javadoc) * @see openadk.library.Element#getTextValue() */ @Override public String getTextValue() { return fValue.toString( ADK.getTextFormatter() ); } /** * Sets the datatype of this field as a string value. The string is parsed * using the default SIF formatter, which is the SIF 1.x formatter by default * @see openadk.library.Element#setTextValue(java.lang.String) * @throws NumberFormatException if the value being set cannot be parsed into * the datatype being stored for this field */ @Override public void setTextValue(String value) { try { setTextValue( value, ADK.getTextFormatter() ); } catch( ADKParsingException adkpe ){ // TODO: Determine if this is the right way to handle it... throw new NumberFormatException( adkpe.getMessage()); } } @SuppressWarnings("unchecked") // Not sure how to work around this warning @Override public void setSIFValue( SIFSimpleType value ){ fValue = value; } /** * Returns the SIFSimpleType value of this field * @return the SIFSimpleType value of this field * @see openadk.library.Element#getSIFValue() */ public SIFSimpleType<T> getSIFValue() { return fValue; } /** * Returns the native datatype value of this field * @return the native datatype value of this field */ public T getValue() { return fValue.getValue(); } /** * Checks the underlying data type and flags to determine if XML encoding * should be turned off for this field * @see openadk.library.Element#isDoNotEncode() */ @Override public boolean isDoNotEncode() { boolean isDoNotEncode = false; if( fValue != null ){ isDoNotEncode = fValue.isDoNotEncode(); } return isDoNotEncode | super.isDoNotEncode(); } /* (non-Javadoc) * @see java.lang.Object#clone() */ @Override public Object clone() throws CloneNotSupportedException { try{ Constructor constructor = this.getClass().getConstructor( new Class[] { SIFElement.class, ElementDef.class, SIFSimpleType.class } ); // Do not clone the parent reference SimpleField<T> fieldCopy = (SimpleField<T>)constructor.newInstance( null, fElementDef, fValue ); return fieldCopy; } catch( RuntimeException re ) { throw re; } catch( Exception iae ){ throw new CloneNotSupportedException( iae.getMessage() ); } } private void writeObject( java.io.ObjectOutputStream out ) throws IOException { out.defaultWriteObject(); // // Write the path to the ElementDef // String path = null; if( fElementDef.isField() ) { // This SimpleField represents a field on an object path = fElementDef.getSDOPath(); } else { // This SimpleField must represent the text value of an object path = "TEXT_VALUE"; } out.writeUTF( path ); } private void readObject( java.io.ObjectInputStream in ) throws IOException, ClassNotFoundException { in.defaultReadObject(); // // Read the path to the ElementDef // String path = in.readUTF(); ElementDef foundElementDef = null; if( path.equals( "TEXT_VALUE" ) ) { if( fParent != null ){ // TODO: MLW - I consider this a hack. On deserialization, the no-arguments constructor is // not called. Also, SIFElements that were serialized without a parent but normally do have a parent // are not returned by the lookupElementDef() call above. To fix this, I instantiate // a new object of this type, and then see what the elementdef of that object is. try { SIFElement parentInstance = (SIFElement) fParent.getClass().newInstance(); foundElementDef = parentInstance.getElementDef(); } catch (InstantiationException ex) { throw new RuntimeException("Deserialization failed: " + ex.getMessage(), ex); } catch (IllegalAccessException ex) { throw new RuntimeException("Deserialization failed" + ex.getMessage(), ex); } } } else if ( path.length() > 0 ) { foundElementDef = ADK.DTD().lookupElementDef(path); } if( foundElementDef == null ) { String errorInfo = null; if( fParent == null ){ errorInfo = getClass().getCanonicalName() + "=" + this.fValue.getValue(); } else { errorInfo = fParent.getClass().getCanonicalName() + "/" + getClass().getCanonicalName(); } throw new RuntimeException( "Unable to deserialize field of object: " + errorInfo); } fElementDef = foundElementDef; } }