/** * */ package ecologylab.bigsemantics.metadata.scalar.types; import java.lang.reflect.Field; import ecologylab.bigsemantics.metadata.scalar.MetadataScalarBase; import ecologylab.generic.ReflectionTools; import ecologylab.serialization.ScalarUnmarshallingContext; import ecologylab.serialization.types.ScalarType; import ecologylab.serialization.types.TypeRegistry; import ecologylab.serialization.types.scalar.ReferenceType; /** * Basis for scalar types for classes that derive from MetadataScalarBase. * * M is the MetadataBase type, like MetadataString. * * T is the nested type, like String. * * @author andruid */ public abstract class MetadataScalarType<M, T> extends ReferenceType<M> { ScalarType<T> valueScalarType; Field valueField; private static boolean metadataScalarTypesRegistered = false; /** * Construct. * Use the simple name of the metadataScalarTypeClass as the javaTypeName. * Use the dbTypeName of the valueClass as the dbTypeName. * * @param metadataScalarTypeClass * @param valueClass * @param cSharpTypeName * @param objectiveCTypeName */ public MetadataScalarType(Class<M> metadataScalarTypeClass, Class valueClass, String cSharpTypeName, String objectiveCTypeName) { this(metadataScalarTypeClass, valueClass, metadataScalarTypeClass.getSimpleName(), cSharpTypeName, objectiveCTypeName); } public MetadataScalarType(Class<M> metadataScalarTypeClass, Class valueClass, String javaTypeName, String cSharpTypeName, String objectiveCTypeName) { super(metadataScalarTypeClass, javaTypeName, cSharpTypeName, objectiveCTypeName, TypeRegistry.getScalarType(valueClass).getDbTypeName()); this.valueScalarType = TypeRegistry.getScalarType(valueClass); valueField(); } Field valueField() { Field result = valueField; if (result == null) { Class typeClass = MetadataScalarBase.class; try { result = typeClass.getDeclaredField(MetadataScalarBase.VALUE_FIELD_NAME); result.setAccessible(true); valueField = result; } catch (SecurityException e) { error("Can't access value field for " + typeClass); } catch (NoSuchFieldException e) { error("Can't find value field for " + typeClass); } } return result; } /** * Set the value field inside the MetadataScalarBase subtype object that largerMetadataContext * refers to. Instantiate that MetadataScalarBase subtype object if necessary, and set it there. * * Used for deserializing. */ @Override public boolean setField(Object largerMetadataContext, Field field, String valueString, String[] format, ScalarUnmarshallingContext scalarUnmarshallingContext) { if (valueString == null) return true; boolean result = false; T valueObject; try { valueObject = valueScalarType.getInstance(valueString, format, scalarUnmarshallingContext); if (valueObject != null) { M metadataScalarContext = (M) field.get(largerMetadataContext); if (metadataScalarContext == null) { metadataScalarContext = (M) ReflectionTools.getInstance(field.getType()); field.set(largerMetadataContext, metadataScalarContext); } valueField().set(metadataScalarContext, valueObject); result = true; } } catch (Exception e) { setFieldError(field, valueString, e); } return result; } /** * Called during deserialization. * * Uses the valueScalarType stored inside the scalar type to get an instance of type T. Called * inside the various subtypes of this. * * @param value * @param formatStrings * @param scalarUnmarshallingContext * @return */ public T getValueInstance(String value, String[] formatStrings, ScalarUnmarshallingContext scalarUnmarshallingContext) { return valueScalarType.getInstance(value, formatStrings, scalarUnmarshallingContext); } public static synchronized void init() { if (!metadataScalarTypesRegistered) { metadataScalarTypesRegistered = true; new SemanticsTypes(); } } @Override public ScalarType operativeScalarType() { return valueScalarType; } @Override public Field operativeField(Field externalField) { return valueField; } @Override public String toString(Field field, Object largerMetadataContext) { String result = "COULDNT CONVERT!"; try { M metadataScalarContext = (M) field.get(largerMetadataContext); if (metadataScalarContext != null) { T instance = (T) valueField().get(metadataScalarContext); if (instance == null) result = null; else // result = toString(instance); result = instance.toString(); } else result = null; } catch (Exception e) { e.printStackTrace(); } return result; } public boolean isDefaultValue(String value) { return valueScalarType.isDefaultValue(value); } /** * True if the user should be able to express interest in fields of this type. * * @return true for Strings */ public boolean affordsInterestExpression() { return true; } }