From 9ad54df1a4a57323a2784b83711b5379fe6483c9 Mon Sep 17 00:00:00 2001 From: "Zachary O. Toups" Date: Fri, 1 Nov 2013 12:42:34 -0600 Subject: [PATCH 1/2] attempt to correct circular dependency in PrefSet where the PrefSet class descriptor requires the Prefs translation scope (which requires the PrefSet class descriptor). Move PrefSet to the end of the list, so that all Prefs are loaded into the translation scope prior to loading in PrefSet. --- .../appframework/ApplicationEnvironment.java | 2 +- .../types/prefs/PrefSetBaseClassProvider.java | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/simplCore/src/ecologylab/appframework/ApplicationEnvironment.java b/simplCore/src/ecologylab/appframework/ApplicationEnvironment.java index b0f68e15..8f823dcd 100644 --- a/simplCore/src/ecologylab/appframework/ApplicationEnvironment.java +++ b/simplCore/src/ecologylab/appframework/ApplicationEnvironment.java @@ -242,7 +242,7 @@ protected static final SimplTypesScope prefsClassArrayToTranslationScope( Class>[] customPrefs) { // configure the PrefSet translation scope, incorporating custom translations, if any - if (customPrefs == null) + if (customPrefs == null || customPrefs.length == 0) customPrefs = PrefSetBaseClassProvider.STATIC_INSTANCE.provideClasses(); return SimplTypesScope.get(PrefSet.PREFS_TRANSLATION_SCOPE, customPrefs); diff --git a/simplCore/src/ecologylab/appframework/types/prefs/PrefSetBaseClassProvider.java b/simplCore/src/ecologylab/appframework/types/prefs/PrefSetBaseClassProvider.java index 81d6b613..c5b447ae 100644 --- a/simplCore/src/ecologylab/appframework/types/prefs/PrefSetBaseClassProvider.java +++ b/simplCore/src/ecologylab/appframework/types/prefs/PrefSetBaseClassProvider.java @@ -17,6 +17,7 @@ public class PrefSetBaseClassProvider extends TranslationsClassProvider protected PrefSetBaseClassProvider() { + super(); } /** @@ -26,13 +27,15 @@ protected PrefSetBaseClassProvider() protected Class>[] specificSuppliedClasses() { Class[] prefSetClasses = - { MetaPref.class, MetaPrefSet.class, MetaPrefBoolean.class, MetaPrefFloat.class, - MetaPrefInt.class, MetaPrefString.class, - - Pref.class, PrefSet.class, PrefBoolean.class, PrefDouble.class, PrefFloat.class, + { + Pref.class, PrefBoolean.class, PrefDouble.class, PrefFloat.class, PrefInt.class, PrefLong.class, PrefString.class, PrefElementState.class, PrefFile.class, PrefOp.class, + // XXX THIS MAY NOT SOLVE PROBLEMS WITH CUSTOM PREF TRANSLATIONS! + // XXX Putting PrefSet last helps with a circular dependency where PrefSet's ClassDescriptor + // needs the PrefSetBaseClassProvider's list of classes to compute its scope + PrefSet.class }; return prefSetClasses; From a5564fbeb44cbff85357224ba809531538308ea0 Mon Sep 17 00:00:00 2001 From: "Zachary O. Toups" Date: Wed, 12 Feb 2014 14:25:53 -0700 Subject: [PATCH 2/2] Add Calendar and GregorianCalendar types with ability to specify de-/serialization format. --- simplCore/NIOLoggingServer.launch | 3 +- .../src/ecologylab/io/XMLFileFilter.java | 2 +- .../stringformats/XMLPullDeserializer.java | 284 +++++++++--------- .../types/CrossLanguageTypeConstants.java | 2 + .../serialization/types/FundamentalTypes.java | 40 ++- .../types/scalar/CalendarType.java | 265 ++++++++++++++++ .../types/scalar/GregorianCalendarType.java | 217 +++++++++++++ 7 files changed, 673 insertions(+), 140 deletions(-) create mode 100644 simplCore/src/ecologylab/serialization/types/scalar/CalendarType.java create mode 100644 simplCore/src/ecologylab/serialization/types/scalar/GregorianCalendarType.java diff --git a/simplCore/NIOLoggingServer.launch b/simplCore/NIOLoggingServer.launch index 0ff3e103..d263407d 100644 --- a/simplCore/NIOLoggingServer.launch +++ b/simplCore/NIOLoggingServer.launch @@ -1,12 +1,13 @@ - + + diff --git a/simplCore/src/ecologylab/io/XMLFileFilter.java b/simplCore/src/ecologylab/io/XMLFileFilter.java index 0f019235..c4846843 100644 --- a/simplCore/src/ecologylab/io/XMLFileFilter.java +++ b/simplCore/src/ecologylab/io/XMLFileFilter.java @@ -7,7 +7,7 @@ public class XMLFileFilter implements FileFilter { static XMLFileFilter singleton; - static XMLFileFilter get() + public static XMLFileFilter get() { XMLFileFilter result = singleton; if (result == null) diff --git a/simplCore/src/ecologylab/serialization/deserializers/pullhandlers/stringformats/XMLPullDeserializer.java b/simplCore/src/ecologylab/serialization/deserializers/pullhandlers/stringformats/XMLPullDeserializer.java index 64e8a3a8..9c43aec5 100644 --- a/simplCore/src/ecologylab/serialization/deserializers/pullhandlers/stringformats/XMLPullDeserializer.java +++ b/simplCore/src/ecologylab/serialization/deserializers/pullhandlers/stringformats/XMLPullDeserializer.java @@ -19,6 +19,7 @@ import ecologylab.serialization.SIMPLTranslationException; import ecologylab.serialization.SimplTypesScope; import ecologylab.serialization.TranslationContext; +import ecologylab.serialization.annotations.simpl_nowrap; import ecologylab.serialization.types.element.IMappable; /** @@ -32,8 +33,8 @@ public class XMLPullDeserializer extends StringPullDeserializer // private CharSequence test; - XMLParser xmlParser; - + XMLParser xmlParser; + /** * * @param translationScope @@ -68,36 +69,38 @@ public Object parse(InputStream inputStream, Charset charSet) throws SIMPLTransl result = parse(); return result; } - catch(SIMPLTranslationException ex) + catch (SIMPLTranslationException ex) { - throw ex; + throw ex; } catch (Exception ex) { - SIMPLTranslationException ste = new SIMPLTranslationException("exception occurred in deserialzation ", ex); + SIMPLTranslationException ste = new SIMPLTranslationException( + "exception occurred in deserialzation ", ex); ste.setRemnantObject(result); throw ste; } } - + @Override public Object parse(InputStream inputStream) throws SIMPLTranslationException { - // hold onto a black result to return. - Object result = null; + // hold onto a black result to return. + Object result = null; try { configure(inputStream); result = parse(); return result; } - catch(SIMPLTranslationException ex) + catch (SIMPLTranslationException ex) { - throw ex; + throw ex; } catch (Exception ex) { - SIMPLTranslationException toThrow = new SIMPLTranslationException("exception occurred in deserialzation ", ex); + SIMPLTranslationException toThrow = new SIMPLTranslationException( + "exception occurred in deserialzation ", ex); toThrow.setRemnantObject(result); throw toThrow; } @@ -117,21 +120,22 @@ public Object parse(InputStream inputStream) throws SIMPLTranslationException @Override public Object parse(CharSequence charSequence) throws SIMPLTranslationException { - // hold onto a black result to return. - Object result = null; + // hold onto a black result to return. + Object result = null; try { configure(charSequence); result = parse(); return result; } - catch(SIMPLTranslationException ex) + catch (SIMPLTranslationException ex) { - throw ex; + throw ex; } catch (Exception ex) { - SIMPLTranslationException ste = new SIMPLTranslationException("exception occurred in deserialzation ", ex); + SIMPLTranslationException ste = new SIMPLTranslationException( + "exception occurred in deserialzation ", ex); ste.setRemnantObject(result); throw ste; } @@ -149,7 +153,7 @@ private void configure(InputStream inputStream, Charset charSet) throws SIMPLTra { xmlParser = FundamentalPlatformSpecifics.get().getXMLParser(inputStream, charSet); } - + /** * * @param inputStream @@ -181,12 +185,11 @@ private void configure(CharSequence charSequence) throws SIMPLTranslationExcepti */ private Object parse() throws SIMPLTranslationException, IOException { - Object root = null; nextEvent(); - // We should expect the first element to be the START + // We should expect the first element to be the START if (xmlParser.getEventType() != XMLParser.START_ELEMENT) { throw new SIMPLTranslationException("start of an element expected"); @@ -204,16 +207,21 @@ private Object parse() throws SIMPLTranslationException, IOException } root = rootClassDescriptor.getInstance(); - - // Logic to set all field descritpro scalars to defaults. - for(FieldDescriptor fd : rootClassDescriptor.allFieldDescriptors()) + + // Logic to set all field descriptors scalars to defaults. + // Logic to identify no_wrap collections at root level + for (FieldDescriptor fd : rootClassDescriptor.allFieldDescriptors()) { - if(fd.isScalar() && (fd.isEnum() == false)) + if (fd.isScalar() && (fd.isEnum() == false)) { fd.setFieldToScalarDefault(root, translationContext); } - } + if (fd.isCollection() && fd.getField().isAnnotationPresent(simpl_nowrap.class)) + { + // rootClassDescriptor. + } + } deserializationPreHook(root, translationContext); if (deserializationHookStrategy != null) @@ -224,12 +232,12 @@ private Object parse() throws SIMPLTranslationException, IOException deserializationInHook(root, translationContext); if (deserializationHookStrategy != null) deserializationHookStrategy.deserializationInHook(root, null); - + createObjectModel(root, rootClassDescriptor, rootTag); - // Post hook is called at the end of createObjectModel. - // That should be pulled here at some point. - + // Post hook is called at the end of createObjectModel. + // That should be pulled here at some point. + return root; } @@ -252,103 +260,104 @@ private void createObjectModel(Object root, ClassDescriptor rootClassDescriptor, String rootTag) throws IOException, SIMPLTranslationException { - int event = 0; - event = nextEvent(); + int event = 0; + event = nextEvent(); - - FieldDescriptor currentFieldDescriptor = null; // new FieldDescriptor(); + FieldDescriptor currentFieldDescriptor = null; // new FieldDescriptor(); - String xmlText = ""; + String xmlText = ""; - while ( event!= XMLParser.END_DOCUMENT - && (event != XMLParser.END_ELEMENT || !rootTag.equals(getTagName()))) + while (event != XMLParser.END_DOCUMENT + && (event != XMLParser.END_ELEMENT || !rootTag.equals(getTagName()))) + { + if (event != XMLParser.START_ELEMENT) { - if (event != XMLParser.START_ELEMENT) + if (event == XMLParser.CHARACTERS) { - if (event == XMLParser.CHARACTERS) - { - xmlText += xmlParser.getText(); - } - else if (event == XMLParser.END_ELEMENT && currentFieldDescriptor != null && currentFieldDescriptor.getType() == FieldType.WRAPPER) - { - currentFieldDescriptor = currentFieldDescriptor.getWrappedFD(); - } - - event = nextEvent(); - continue; + xmlText += xmlParser.getText(); + } + else if (event == XMLParser.END_ELEMENT && currentFieldDescriptor != null + && currentFieldDescriptor.getType() == FieldType.WRAPPER) + { + currentFieldDescriptor = currentFieldDescriptor.getWrappedFD(); } - String tag = getTagName(); + event = nextEvent(); + continue; + } - currentFieldDescriptor = currentFieldDescriptor != null &¤tFieldDescriptor.getType() == FieldType.WRAPPER - ? currentFieldDescriptor.getWrappedFD() - : rootClassDescriptor.getFieldDescriptorByTag(tag, translationScope, null); + String tag = getTagName(); - if (currentFieldDescriptor == null) - { - currentFieldDescriptor = FieldDescriptor.makeIgnoredFieldDescriptor(tag); - } + currentFieldDescriptor = + currentFieldDescriptor != null && currentFieldDescriptor.getType() == FieldType.WRAPPER + ? currentFieldDescriptor.getWrappedFD() + : rootClassDescriptor.getFieldDescriptorByTag(tag, translationScope, null); - - FieldType fieldType = currentFieldDescriptor.getType(); + if (currentFieldDescriptor == null) + { + currentFieldDescriptor = FieldDescriptor.makeIgnoredFieldDescriptor(tag); + } - switch (fieldType) - { - case SCALAR: - - // If we don't find a field declaration in the serialized representation for a scalar field... - // We'll never end up changing its value. So instead, let's automatically set every scalar value to its corresponding default value first. - event = deserializeScalar(root, currentFieldDescriptor); - break; - - case COLLECTION_SCALAR: - event = deserializeScalarCollection(root, currentFieldDescriptor); - break; - - case COMPOSITE_ELEMENT: - event = deserializeComposite(root, currentFieldDescriptor); - break; - - case COLLECTION_ELEMENT: - event = deserializeCompositeCollection(root, currentFieldDescriptor); - break; - - case MAP_ELEMENT: - event = deserializeCompositeMap(root, currentFieldDescriptor); - break; - - case WRAPPER: - event = nextEvent(); - break; - - case IGNORED_ELEMENT: - event = ignoreTag(tag); - break; - - default: - event = nextEvent(); - - } + FieldType fieldType = currentFieldDescriptor.getType(); + + switch (fieldType) + { + case SCALAR: + + // If we don't find a field declaration in the serialized representation for a scalar + // field... + // We'll never end up changing its value. So instead, let's automatically set every scalar + // value to its corresponding default value first. + event = deserializeScalar(root, currentFieldDescriptor); + break; + + case COLLECTION_SCALAR: + event = deserializeScalarCollection(root, currentFieldDescriptor); + break; + + case COMPOSITE_ELEMENT: + event = deserializeComposite(root, currentFieldDescriptor); + break; + + case COLLECTION_ELEMENT: + event = deserializeCompositeCollection(root, currentFieldDescriptor); + break; + + case MAP_ELEMENT: + event = deserializeCompositeMap(root, currentFieldDescriptor); + break; + + case WRAPPER: + event = nextEvent(); + break; + + case IGNORED_ELEMENT: + event = ignoreTag(tag); + break; + + default: + event = nextEvent(); - if (event == XMLParser.END_DOCUMENT) - { - // no more data? but we are expecting so its not correct - throw new SIMPLTranslationException( - "premature end of file: check XML file for consistency"); - } } - if (rootClassDescriptor.hasScalarFD()) + if (event == XMLParser.END_DOCUMENT) { - rootClassDescriptor.getScalarTextFD().setFieldToScalar(root, xmlText, translationContext); + // no more data? but we are expecting so its not correct + throw new SIMPLTranslationException("premature end of file: check XML file for consistency"); } - - deserializationPostHook(root, translationContext); - if (deserializationHookStrategy != null) - deserializationHookStrategy.deserializationPostHook(root, - currentFieldDescriptor == null || currentFieldDescriptor.getType() == FieldType.IGNORED_ELEMENT - ? null : currentFieldDescriptor); -// deserializationHookStrategy.deserializationPostHook(root, null); + } + + if (rootClassDescriptor.hasScalarFD()) + { + rootClassDescriptor.getScalarTextFD().setFieldToScalar(root, xmlText, translationContext); + } + + deserializationPostHook(root, translationContext); + if (deserializationHookStrategy != null) + deserializationHookStrategy.deserializationPostHook(root, currentFieldDescriptor == null + || currentFieldDescriptor.getType() == FieldType.IGNORED_ELEMENT ? null + : currentFieldDescriptor); + // deserializationHookStrategy.deserializationPostHook(root, null); } /** @@ -395,7 +404,7 @@ private int deserializeScalarCollection(Object root, FieldDescriptor fd) fd.addLeafNodeToCollection(root, value, translationContext); } - event = xmlParser.nextTag(); + event = xmlParser.nextTag(); tagName = getTagName(); } } @@ -447,7 +456,8 @@ private int deserializeCompositeMap(Object root, FieldDescriptor fd) String compositeTagName = getTagName(); subRoot = getSubRoot(fd, compositeTagName, root); - final Object key = (subRoot instanceof IMappable) ? ((IMappable) subRoot).key() : fd.getMapKeyFieldValue(subRoot); + final Object key = (subRoot instanceof IMappable) ? ((IMappable) subRoot).key() : fd + .getMapKeyFieldValue(subRoot); if (key != null) { Map map = (Map) fd.automaticLazyGetCollectionOrMap(root); @@ -490,12 +500,11 @@ private int deserializeCompositeCollection(Object root, FieldDescriptor fd) } subRoot = getSubRoot(fd, tagName, root); - - + Collection collection = (Collection) fd.automaticLazyGetCollectionOrMap(root); collection.add(subRoot); - event = xmlParser.nextTag(); + event = xmlParser.nextTag(); tagName = getTagName(); } } @@ -523,7 +532,7 @@ private int deserializeScalar(Object root, FieldDescriptor currentFieldDescripto while (nextEvent() != XMLParser.END_ELEMENT); String value = text.toString(); - + currentFieldDescriptor.setFieldToScalar(root, value, translationContext); return nextEvent(); @@ -577,11 +586,11 @@ private Object getSubRoot(FieldDescriptor currentFieldDescriptor, String tagName else { subRoot = subRootClassDescriptor.getInstance(); - - // Logic to set all field descritpro scalars to defaults. - for(FieldDescriptor fd : subRootClassDescriptor.allFieldDescriptors()) + + // Logic to set all field descritpro scalars to defaults. + for (FieldDescriptor fd : subRootClassDescriptor.allFieldDescriptors()) { - if(fd.isScalar() && (fd.isEnum() == false)) + if (fd.isScalar() && (fd.isEnum() == false)) { fd.setFieldToScalarDefault(subRoot, translationContext); } @@ -600,17 +609,18 @@ private Object getSubRoot(FieldDescriptor currentFieldDescriptor, String tagName } deserializeAttributes(subRoot, subRootClassDescriptor); - + deserializationInHook(subRoot, translationContext); if (deserializationHookStrategy != null) deserializationHookStrategy.deserializationInHook(subRoot, currentFieldDescriptor); - + createObjectModel(subRoot, subRootClassDescriptor, tagName); } - + if (deserializationHookStrategy != null && subRoot != null) { - Object newSubRoot= deserializationHookStrategy.changeObjectIfNecessary(subRoot, currentFieldDescriptor); + Object newSubRoot = deserializationHookStrategy.changeObjectIfNecessary(subRoot, + currentFieldDescriptor); if (newSubRoot != null) subRoot = newSubRoot; } @@ -713,7 +723,7 @@ private int nextEvent() throws SIMPLTranslationException } /** - * @throws SIMPLTranslationException + * @throws SIMPLTranslationException * */ protected void debug() @@ -723,18 +733,18 @@ protected void debug() int event = xmlParser.getEventType(); switch (event) { - case XMLParser.START_ELEMENT: - System.out.println(getTagName()); - break; - case XMLParser.END_ELEMENT: - System.out.println(getTagName()); - break; - case XMLParser.CHARACTERS: - System.out.println(xmlParser.getText()); - break; - case XMLParser.CDATA: - System.out.println("cdata " + xmlParser.getText()); - break; + case XMLParser.START_ELEMENT: + System.out.println(getTagName()); + break; + case XMLParser.END_ELEMENT: + System.out.println(getTagName()); + break; + case XMLParser.CHARACTERS: + System.out.println(xmlParser.getText()); + break; + case XMLParser.CDATA: + System.out.println("cdata " + xmlParser.getText()); + break; } // end switch } catch (SIMPLTranslationException e) @@ -796,6 +806,6 @@ protected void printParse() throws SIMPLTranslationException } // end switch } while (xmlParser.next() != XMLParser.END_DOCUMENT); - + } } diff --git a/simplCore/src/ecologylab/serialization/types/CrossLanguageTypeConstants.java b/simplCore/src/ecologylab/serialization/types/CrossLanguageTypeConstants.java index e4077b27..a12ae813 100644 --- a/simplCore/src/ecologylab/serialization/types/CrossLanguageTypeConstants.java +++ b/simplCore/src/ecologylab/serialization/types/CrossLanguageTypeConstants.java @@ -145,6 +145,8 @@ public interface CrossLanguageTypeConstants public static final String JAVA_DATE = "Date"; + public static final String JAVA_CALENDAR = "Calendar"; + public static final String JAVA_STRING_BUILDER = "StringBuilder"; public static final String JAVA_URL = "Url"; diff --git a/simplCore/src/ecologylab/serialization/types/FundamentalTypes.java b/simplCore/src/ecologylab/serialization/types/FundamentalTypes.java index 8d4dcbec..d56e0cef 100644 --- a/simplCore/src/ecologylab/serialization/types/FundamentalTypes.java +++ b/simplCore/src/ecologylab/serialization/types/FundamentalTypes.java @@ -5,7 +5,9 @@ import java.net.URL; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Calendar; import java.util.Date; +import java.util.GregorianCalendar; import java.util.HashMap; import java.util.UUID; import java.util.regex.Pattern; @@ -13,7 +15,39 @@ import ecologylab.collections.Scope; import ecologylab.generic.HashMapArrayList; import ecologylab.net.ParsedURL; -import ecologylab.serialization.types.scalar.*; +import ecologylab.serialization.types.scalar.BinaryDataType; +import ecologylab.serialization.types.scalar.BooleanType; +import ecologylab.serialization.types.scalar.ByteType; +import ecologylab.serialization.types.scalar.CalendarType; +import ecologylab.serialization.types.scalar.CharType; +import ecologylab.serialization.types.scalar.ClassType; +import ecologylab.serialization.types.scalar.CollectionTypeType; +import ecologylab.serialization.types.scalar.CompositeAsScalarType; +import ecologylab.serialization.types.scalar.DateType; +import ecologylab.serialization.types.scalar.DoubleType; +import ecologylab.serialization.types.scalar.EnumeratedType; +import ecologylab.serialization.types.scalar.FieldType; +import ecologylab.serialization.types.scalar.FileType; +import ecologylab.serialization.types.scalar.FloatType; +import ecologylab.serialization.types.scalar.GregorianCalendarType; +import ecologylab.serialization.types.scalar.IntType; +import ecologylab.serialization.types.scalar.LongType; +import ecologylab.serialization.types.scalar.ParsedURLType; +import ecologylab.serialization.types.scalar.PatternType; +import ecologylab.serialization.types.scalar.ReferenceBooleanType; +import ecologylab.serialization.types.scalar.ReferenceByteType; +import ecologylab.serialization.types.scalar.ReferenceCharType; +import ecologylab.serialization.types.scalar.ReferenceDoubleType; +import ecologylab.serialization.types.scalar.ReferenceFloatType; +import ecologylab.serialization.types.scalar.ReferenceIntegerType; +import ecologylab.serialization.types.scalar.ReferenceLongType; +import ecologylab.serialization.types.scalar.ReferenceShortType; +import ecologylab.serialization.types.scalar.ScalarTypeType; +import ecologylab.serialization.types.scalar.ShortType; +import ecologylab.serialization.types.scalar.StringBuilderType; +import ecologylab.serialization.types.scalar.StringType; +import ecologylab.serialization.types.scalar.URLType; +import ecologylab.serialization.types.scalar.UUIDType; public class FundamentalTypes implements CrossLanguageTypeConstants @@ -84,6 +118,10 @@ public class FundamentalTypes public static final ScalarType DATE_TYPE = new DateType(); + public static final ScalarType CALENDAR_TYPE = new CalendarType(); + + public static final ScalarType GREGORIAN_CALENDAR_TYPE = new GregorianCalendarType(); + public static final ScalarType SCALAR_TYPE_TYPE = new ScalarTypeType(); public static final ScalarType COLLECTION_TYPE_TYPE = new CollectionTypeType(); diff --git a/simplCore/src/ecologylab/serialization/types/scalar/CalendarType.java b/simplCore/src/ecologylab/serialization/types/scalar/CalendarType.java new file mode 100644 index 00000000..638486da --- /dev/null +++ b/simplCore/src/ecologylab/serialization/types/scalar/CalendarType.java @@ -0,0 +1,265 @@ +/* + * Created on Jan 2, 2005 at the Interface Ecology Lab. + */ +package ecologylab.serialization.types.scalar; + +import java.io.IOException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +import org.json.simple.JSONObject; + +import ecologylab.serialization.ClassDescriptor; +import ecologylab.serialization.FieldDescriptor; +import ecologylab.serialization.ScalarUnmarshallingContext; +import ecologylab.serialization.TranslationContext; +import ecologylab.serialization.XMLTools; +import ecologylab.serialization.annotations.simpl_inherit; +import ecologylab.serialization.formatenums.Format; +import ecologylab.serialization.types.CrossLanguageTypeConstants; + +/** + * Type system entry for {@link java.util.Calendar Calendar}. + * + * @author Zachary O. Toups (ztoups@nmsu.edu) + */ +@simpl_inherit +public class CalendarType extends ReferenceType implements + CrossLanguageTypeConstants +{ + static final String datePatterns[] = + { + "EEE MMM dd kk:mm:ss zzz yyyy", + "yyyy:MM:dd HH:mm:ss", + "yyyy:MM:dd HH:mm", + "yyyy-MM-dd HH:mm:ss", + "yyyy-MM-dd HH:mm", + "MMM dd, yyyy", + "yyyyMMdd", + "MM/dd/yyyy", + "MM/dd/yyyy K:mm aa", + }; + + static final DateFormat dateFormats[] = new DateFormat[datePatterns.length + 1]; + + static final DateFormat plainDf = DateFormat.getDateTimeInstance(); + + static + { + for (int i = 0; i < datePatterns.length; i++) + dateFormats[i] = new SimpleDateFormat(datePatterns[i]); + dateFormats[datePatterns.length] = plainDf; + } + + public CalendarType() + { + super(Calendar.class, JAVA_CALENDAR, null, null, null); + } + + /** + * Uses the format specified by the first entry in simpl_format; if that fails, cycles through + * additional patterns specified by datePatterns[] until one succeeds. + * + * @param value + * @see ecologylab.serialization.types.ScalarType#getInstance(java.lang.String, String[], + * ScalarUnmarshallingContext) + */ + @Override + public Calendar getInstance(String value, String[] formatStrings, + ScalarUnmarshallingContext scalarUnmarshallingContext) + { + if (formatStrings[0] != null && !"".equals(formatStrings[0])) + try + { + DateFormat df = new SimpleDateFormat(formatStrings[0]); + Date d = df.parse(value); + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(d.getTime()); + + return c; + } + catch (ParseException e) + { // simply try all the patterns + } + + for (DateFormat dateFormatParser : dateFormats) + { + try + { + Date d = dateFormatParser.parse(value); + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(d.getTime()); + + return c; + } + catch (java.text.ParseException ex) + { // simply try the next pattern + } + } + + error("Failed to parse date: " + value); + return null; + } + + @Override + public void appendValue(StringBuilder buffy, FieldDescriptor fieldDescriptor, Object context) + throws IllegalArgumentException, IllegalAccessException + { + try + { + Calendar instance = (Calendar) fieldDescriptor.getField().get(context); + + appendValue(instance, fieldDescriptor.getFormat(), buffy, !fieldDescriptor.isCDATA(), null); + } + catch (IllegalArgumentException e) + { + throw e; + } + } + + /** + * Append the String directly, unless it needs escaping, in which case, call escapeXML. + * + * @param instance + * @param buffy + * @param needsEscaping + */ + public void appendValue( + Calendar instance, + String[] formatDescriptors, + StringBuilder buffy, + boolean needsEscaping, + TranslationContext serializationContext) + { + String instanceString = marshall(instance, formatDescriptors, serializationContext);// instance.toString(); + if (needsEscaping) + XMLTools.escapeXML(buffy, instanceString); + else + buffy.append(instanceString); + } + + @Override + public void appendValue(Calendar instance, StringBuilder buffy, boolean needsEscaping, + TranslationContext serializationContext) + { + ClassDescriptor compositeElement = ClassDescriptor.getClassDescriptor(instance); + FieldDescriptor scalarValueFD = compositeElement.getScalarValueFieldDescripotor(); + String instanceString = marshall(instance, scalarValueFD.getFormat(), serializationContext);// instance.toString(); + if (needsEscaping) + XMLTools.escapeXML(buffy, instanceString); + else + buffy.append(instanceString); + } + + // @Override + // public void appendValue(Calendar instance, Appendable buffy, boolean needsEscaping, + // TranslationContext serializationContext, Format format) throws IOException + // { + // String instanceString = ""; + // if (instance != null && serializationContext != null) + // { + // ClassDescriptor compositeElement = ClassDescriptor.getClassDescriptor(instance); + // FieldDescriptor scalarValueFD = compositeElement.getScalarValueFieldDescripotor(); + // + // if (scalarValueFD != null) + // instanceString = marshall(instance, scalarValueFD.getFormat(), serializationContext); // + // andruid + // // 1/4/10 + // else + // instanceString = marshall(instance, new String[0], serializationContext); + // } + // // instance.toString(); + // if (needsEscaping) + // { + // switch (format) + // { + // case JSON: + // buffy.append(JSONObject.escape(instanceString)); + // break; + // case XML: + // XMLTools.escapeXML(buffy, instanceString); + // break; + // default: + // XMLTools.escapeXML(buffy, instanceString); + // break; + // } + // + // } + // else + // buffy.append(instanceString); + // } + + /** + * Get the value from the Field, in the context. Append its value to the buffy. + *

+ * Should only be called *after* checking !isDefault() yourself. + * + * @param buffy + * @param context + * @param serializationContext + * TODO + * @param field + * @param needsEscaping + * TODO + * @throws IllegalAccessException + * @throws IllegalArgumentException + */ + @Override + public void appendValue(Appendable buffy, FieldDescriptor fieldDescriptor, Object context, + TranslationContext serializationContext, Format format) + throws IllegalArgumentException, IllegalAccessException, IOException + { + Calendar instance = (Calendar) fieldDescriptor.getValue(context); + boolean needsEscaping = !fieldDescriptor.isCDATA(); + // appendValue((T) instance, buffy, !fieldDescriptor.isCDATA(), serializationContext, format); + + String instanceString = ""; + if (instance != null && serializationContext != null) + instanceString = marshall(instance, fieldDescriptor.getFormat(), serializationContext); // andruid + // instance.toString(); + if (needsEscaping) + { + switch (format) + { + case JSON: + buffy.append(JSONObject.escape(instanceString)); + break; + case XML: + XMLTools.escapeXML(buffy, instanceString); + break; + default: + XMLTools.escapeXML(buffy, instanceString); + break; + } + + } + else + buffy.append(instanceString); + } + + /** + * Get a String representation of the instance, using this. The default just calls the toString() + * method on the instance. + * + * @param instance + * @param serializationContext + * TODO + * @return + */ + public String marshall(Calendar instance, String[] formatDescriptors, + TranslationContext serializationContext) + { + String pattern = null; + if (formatDescriptors.length > 0 && formatDescriptors[0] != null) + pattern = formatDescriptors[0]; + else + pattern = datePatterns[0]; + + DateFormat df = new SimpleDateFormat(pattern); + Date d = instance.getTime(); + return df.format(d); + } +} diff --git a/simplCore/src/ecologylab/serialization/types/scalar/GregorianCalendarType.java b/simplCore/src/ecologylab/serialization/types/scalar/GregorianCalendarType.java new file mode 100644 index 00000000..ebda375e --- /dev/null +++ b/simplCore/src/ecologylab/serialization/types/scalar/GregorianCalendarType.java @@ -0,0 +1,217 @@ +/* + * Created on Jan 2, 2005 at the Interface Ecology Lab. + */ +package ecologylab.serialization.types.scalar; + +import java.io.IOException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.json.simple.JSONObject; + +import ecologylab.serialization.ClassDescriptor; +import ecologylab.serialization.FieldDescriptor; +import ecologylab.serialization.ScalarUnmarshallingContext; +import ecologylab.serialization.TranslationContext; +import ecologylab.serialization.XMLTools; +import ecologylab.serialization.annotations.simpl_inherit; +import ecologylab.serialization.formatenums.Format; +import ecologylab.serialization.types.CrossLanguageTypeConstants; + +/** + * Type system entry for {@link java.util.Calendar Calendar}. + * + * @author Zachary O. Toups (ztoups@nmsu.edu) + */ +@simpl_inherit +public class GregorianCalendarType extends ReferenceType implements + CrossLanguageTypeConstants +{ + static final String datePatterns[] = + { + "EEE MMM dd kk:mm:ss zzz yyyy", + "yyyy:MM:dd HH:mm:ss", + "yyyy:MM:dd HH:mm", + "yyyy-MM-dd HH:mm:ss", + "yyyy-MM-dd HH:mm", + "MMM dd, yyyy", + "yyyyMMdd", + "MM/dd/yyyy", + "MM/dd/yyyy K:mm aa", + }; + + static final DateFormat dateFormats[] = new DateFormat[datePatterns.length + 1]; + + static final DateFormat plainDf = DateFormat.getDateTimeInstance(); + + static + { + for (int i = 0; i < datePatterns.length; i++) + dateFormats[i] = new SimpleDateFormat(datePatterns[i]); + dateFormats[datePatterns.length] = plainDf; + } + + public GregorianCalendarType() + { + super(GregorianCalendar.class, JAVA_CALENDAR, null, null, null); + } + + /** + * Uses the format specified by the first entry in simpl_format; if that fails, cycles through + * additional patterns specified by datePatterns[] until one succeeds. + * + * @param value + * @see ecologylab.serialization.types.ScalarType#getInstance(java.lang.String, String[], + * ScalarUnmarshallingContext) + */ + @Override + public GregorianCalendar getInstance(String value, String[] formatStrings, + ScalarUnmarshallingContext scalarUnmarshallingContext) + { + if (formatStrings[0] != null && !"".equals(formatStrings[0])) + try + { + DateFormat df = new SimpleDateFormat(formatStrings[0]); + Date d = df.parse(value); + GregorianCalendar c = (GregorianCalendar) Calendar.getInstance(); + c.setTimeInMillis(d.getTime()); + + return c; + } + catch (ParseException e) + { // simply try all the patterns + } + + for (DateFormat dateFormatParser : dateFormats) + { + try + { + Date d = dateFormatParser.parse(value); + GregorianCalendar c = (GregorianCalendar) Calendar.getInstance(); + c.setTimeInMillis(d.getTime()); + + return c; + } + catch (java.text.ParseException ex) + { // simply try the next pattern + } + } + + error("Failed to parse date: " + value); + return null; + } + + @Override + public void appendValue(StringBuilder buffy, FieldDescriptor fieldDescriptor, Object context) + throws IllegalArgumentException, IllegalAccessException + { + try + { + GregorianCalendar instance = (GregorianCalendar) fieldDescriptor.getField().get(context); + + appendValue(instance, fieldDescriptor.getFormat(), buffy, !fieldDescriptor.isCDATA(), null); + } + catch (IllegalArgumentException e) + { + throw e; + } + } + + /** + * Append the String directly, unless it needs escaping, in which case, call escapeXML. + * + * @param instance + * @param buffy + * @param needsEscaping + */ + public void appendValue( + GregorianCalendar instance, + String[] formatDescriptors, + StringBuilder buffy, + boolean needsEscaping, + TranslationContext serializationContext) + { + String instanceString = marshall(instance, formatDescriptors, serializationContext);// instance.toString(); + if (needsEscaping) + XMLTools.escapeXML(buffy, instanceString); + else + buffy.append(instanceString); + } + + @Override + public void appendValue(GregorianCalendar instance, StringBuilder buffy, boolean needsEscaping, + TranslationContext serializationContext) + { + ClassDescriptor compositeElement = ClassDescriptor.getClassDescriptor(instance); + FieldDescriptor scalarValueFD = compositeElement.getScalarValueFieldDescripotor(); + String instanceString = marshall(instance, scalarValueFD.getFormat(), serializationContext);// instance.toString(); + if (needsEscaping) + XMLTools.escapeXML(buffy, instanceString); + else + buffy.append(instanceString); + } + + @Override + public void appendValue(GregorianCalendar instance, Appendable buffy, boolean needsEscaping, + TranslationContext serializationContext, Format format) throws IOException + { + String instanceString = ""; + if (instance != null && serializationContext != null) + { + ClassDescriptor compositeElement = ClassDescriptor.getClassDescriptor(instance); + FieldDescriptor scalarValueFD = compositeElement.getScalarValueFieldDescripotor(); + + if (scalarValueFD != null) + instanceString = marshall(instance, scalarValueFD.getFormat(), serializationContext); // andruid + // 1/4/10 + else + instanceString = marshall(instance, new String[0], serializationContext); + } + // instance.toString(); + if (needsEscaping) + { + switch (format) + { + case JSON: + buffy.append(JSONObject.escape(instanceString)); + break; + case XML: + XMLTools.escapeXML(buffy, instanceString); + break; + default: + XMLTools.escapeXML(buffy, instanceString); + break; + } + + } + else + buffy.append(instanceString); + } + + /** + * Get a String representation of the instance, using this. The default just calls the toString() + * method on the instance. + * + * @param instance + * @param serializationContext + * TODO + * @return + */ + public String marshall(GregorianCalendar instance, String[] formatDescriptors, + TranslationContext serializationContext) + { + String pattern = null; + if (formatDescriptors.length > 0 && formatDescriptors[0] != null) + pattern = formatDescriptors[0]; + else + pattern = datePatterns[0]; + + DateFormat df = new SimpleDateFormat(pattern); + Date d = instance.getTime(); + return df.format(d); + } +}