001 // Copyright 2008 Waterken Inc. under the terms of the MIT X license
002 // found at http://www.opensource.org/licenses/mit-license.html
003 package org.waterken.syntax;
004
005 import java.io.Serializable;
006 import java.lang.reflect.Constructor;
007 import java.lang.reflect.Type;
008
009 import org.joe_e.Powerless;
010 import org.joe_e.Struct;
011 import org.joe_e.reflect.Reflection;
012 import org.ref_send.Record;
013 import org.ref_send.deserializer;
014 import org.ref_send.name;
015
016 /**
017 * A serialization syntax.
018 */
019 public class
020 Syntax extends Struct implements Powerless, Record, Serializable {
021 static private final long serialVersionUID = 1L;
022
023 /**
024 * file extension
025 */
026 public final String ext;
027
028 /**
029 * serializer
030 */
031 public final Serializer serializer;
032
033 /**
034 * deserializer
035 */
036 public final Deserializer deserializer;
037
038 /**
039 * Constructs an instance.
040 * @param ext {@link #ext}
041 * @param serializer {@link #serializer}
042 * @param deserializer {@link #deserializer}
043 */
044 public @deserializer
045 Syntax(@name("ext") final String ext,
046 @name("serializer") final Serializer serializer,
047 @name("deserializer") final Deserializer deserializer) {
048 this.ext = ext;
049 this.serializer = serializer;
050 this.deserializer = deserializer;
051 }
052
053 /**
054 * Finds a corresponding {@link deserializer}.
055 * @param type type to construct
056 * @return constructor, or <code>null</code> if none
057 */
058 static public Constructor<?>
059 deserializer(final Class<?> type) {
060 for (Class<?> i = type; null != i; i = i.getSuperclass()) {
061 // Check for an explicit deserializer constructor.
062 for (final Constructor<?> c : Reflection.constructors(i)) {
063 if (c.isAnnotationPresent(deserializer.class)) { return c; }
064 }
065 // Check for a default constructor of a pass-by-copy type.
066 if (Throwable.class.isAssignableFrom(i) ||
067 Record.class.isAssignableFrom(i)) {
068 try {
069 return Reflection.constructor(i);
070 } catch (final NoSuchMethodException e) {
071 if (Record.class.isAssignableFrom(i)) {
072 throw new MissingDeserializer(Reflection.getName(i));
073 }
074 }
075 }
076 // Look for one in the superclass.
077 }
078 return null;
079 }
080
081 /**
082 * Gets the default value of a specified type.
083 * @param required required type
084 * @return default value
085 */
086 static public Object
087 defaultValue(final Type required) {
088 return boolean.class == required ? Boolean.FALSE :
089 char.class == required ? Character.valueOf('\0') :
090 byte.class == required ? Byte.valueOf((byte)0) :
091 short.class == required ? Short.valueOf((short)0) :
092 int.class == required ? Integer.valueOf(0) :
093 long.class == required ? Long.valueOf(0) :
094 float.class == required ? Float.valueOf(0.0f) :
095 double.class == required ? Double.valueOf(0.0) :
096 (Object)null;
097 }
098 }