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    }