Commits

John Marsden committed c2bd7c4

Marshal Updates.

Codec store is a re-write. This version still cannot marshal inbound JSON to Lists or Maps but it handles all of the primitive and some complex object types.

I need to work on this more often - I keep forgetting what I am doing.

Comments (0)

Files changed (28)

     <version>0.2.12-SNAPSHOT</version>
     <name>JSONiJ</name>
     <url>http://jsonij.plural.cc</url>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
     <build>
         <plugins>
             <plugin>
             </plugin>
         </plugins>
     </reporting>
-    <properties>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    </properties>
     <distributionManagement>
             <!-- My project's Sonatype repository to be used by the release plugin -->
         <repository>

src/main/java/cc/plural/jsonij/ObjectImp.java

 /**
  * Copyright (C) 2010-2011 J.W.Marsden
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- **/
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ *
+ */
 package cc.plural.jsonij;
 
 import java.util.LinkedHashMap;
 public class ObjectImp<CS extends CharSequence, V extends Value> extends Value implements java.util.Map<CS, V> {
 
     /**
-	 * Serial UID
-	 */
-	private static final long serialVersionUID = 7601285884315492844L;
-	
-	/**
+     * Serial UID
+     */
+    private static final long serialVersionUID = 7601285884315492844L;
+    /**
      * Holds the Mapping Values for the Object
      */
     protected LinkedHashMap<CS, V> mapValue;
     /**
-     * Holds the Key order so values can be extracted in the order they were added.
+     * Holds the Key order so values can be extracted in the order they were
+     * added.
      */
     protected ArrayList<CS> valueOrder;
 
     public V get(Object key) {
         return mapValue.get((CS) key.toString());
     }
-    
+
     public V safeGet(Object key) {
         return mapValue.get((CS) key.toString());
     }
-    
+
     /* (non-Javadoc)
      * @see java.util.Map#isEmpty()
      */

src/main/java/cc/plural/jsonij/Value.java

             case OBJECT:
                 result = ((JSON.Object<?, ?>) this).size() != 0;
                 break;
+            default: 
+                result = false;
         }
         return result;
     }

src/main/java/cc/plural/jsonij/marshal/JSONCodec.java

-/**
- * Copyright (C) 2010-2011 J.W.Marsden
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- **/
-package cc.plural.jsonij.marshal;
-
-import java.lang.reflect.Method;
-
-import cc.plural.jsonij.Value;
-
-/**
- *
- * @author openecho
- */
-public abstract class JSONCodec<T extends Object> {
-
-    int codecHash;
-
-    Method encodeMethod;
-
-    Method decodeMethod;
-
-    int getCodecHash() {
-        return codecHash;
-    }
-
-    void setCodecHash(int codecHash) {
-        this.codecHash = codecHash;
-    }
-
-    Method getEncodeMethod() {
-        return encodeMethod;
-    }
-
-    void setEncodeMethod(Method encodeMethod) {
-        this.encodeMethod = encodeMethod;
-    }
-
-    Method getDecodeMethod() {
-        return decodeMethod;
-    }
-
-    void setDecodeMethod(Method decodeMethod) {
-        this.decodeMethod = decodeMethod;
-    }
-    
-    public abstract JSONCodec<? extends Object> createInstance();
-
-    public abstract Value encode(T o);
-
-    public abstract T decode(Value value);
-}

src/main/java/cc/plural/jsonij/marshal/JSONCodecStore.java

-/**
- * Copyright (C) 2010-2011 J.W.Marsden
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- **/
-package cc.plural.jsonij.marshal;
-
-import cc.plural.jsonij.Value;
-import java.lang.reflect.Array;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.TypeVariable;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- *
- * @author openecho
- */
-public class JSONCodecStore {
-
-    public static final String CREATE_INSTANCE_METHOD_SIGNATURE;
-    public static final String ENCODE_METHOD_SIGNATURE;
-    public static final String DECODE_METHOD_SIGNATURE;
-    List<Class<?>> codecList;
-    Map<Class<?>, JSONCodec<?>> codecInstanceMap;
-
-    static {
-        CREATE_INSTANCE_METHOD_SIGNATURE = "createInstance";
-        ENCODE_METHOD_SIGNATURE = "encode";
-        DECODE_METHOD_SIGNATURE = "decode";
-    }
-
-    public JSONCodecStore() {
-        codecList = new ArrayList<Class<?>>();
-        codecInstanceMap = new HashMap<Class<?>, JSONCodec<?>>();
-    }
-
-    public int size() {
-        return codecList.size();
-    }
-
-    public boolean isEmpty() {
-        return codecList.isEmpty();
-    }
-
-    public void printSuperClasses(Class<?> c) {
-        String pad = "";
-        do {
-            String typeString = "";
-            TypeVariable<?>[] types = c.getTypeParameters();
-            for (TypeVariable<?> type : types) {
-                typeString += type.getBounds()[0];
-            }
-            System.out.println(String.format("%s%s<%s>", pad, c, typeString));
-            pad += " ";
-        } while ((c = c.getSuperclass()) != null);
-    }
-
-    public Class<?>[] getTypeParameterSet(Class<?> codec) {
-        /**
-         * TODO: yer....
-         */
-        Class<?>[] typeParameterSet = null;
-        Class<?> typeParameter = null;
-        TypeVariable<?>[] types = codec.getTypeParameters();
-        for (TypeVariable<?> type : types) {
-            typeParameter = (Class<?>) type.getBounds()[0];
-        }
-        typeParameterSet = new Class<?>[]{typeParameter};
-        return typeParameterSet;
-    }
-
-    public void registerCodec(Class<?> codec) {
-        Object codecInstance = null;
-        Method genericCodecCreateMethod = null;
-        Class<?> codecType = null;
-        JSONCodec<?> genericCodecInstance = null;
-        try {
-            codecInstance = codec.newInstance();
-            genericCodecCreateMethod = codec.getMethod(CREATE_INSTANCE_METHOD_SIGNATURE);
-            genericCodecInstance = (JSONCodec<?>) genericCodecCreateMethod.invoke(codecInstance);
-        } catch (IllegalArgumentException ex) {
-            Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-        } catch (InvocationTargetException ex) {
-            Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-        } catch (NoSuchMethodException ex) {
-            Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-        } catch (SecurityException ex) {
-            Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-        } catch (InstantiationException ex) {
-            Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-        } catch (IllegalAccessException ex) {
-            Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-        }
-
-        genericCodecInstance.setCodecHash(codec.hashCode());
-
-        /*
-        if (genericCodecInstance != null) {
-        } else {
-            // TODO: Throw Exception
-        }
-        */
-        
-        Method encodeMethod = null;
-        Method decodeMethod = null;
-        Class<?>[] typeParameterSet = getTypeParameterSet(codec);
-        if (typeParameterSet == null || Array.getLength(typeParameterSet) == 0) {
-            typeParameterSet = new Class<?>[]{java.lang.Object.class};
-        }
-
-        for (Class<?> typeParameter : typeParameterSet) {
-            try {
-                encodeMethod = genericCodecInstance.getClass().getMethod(ENCODE_METHOD_SIGNATURE, typeParameter);
-            } catch (NoSuchMethodException ex) {
-                Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-            } catch (SecurityException ex) {
-                Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-            }
-            if (encodeMethod != null) {
-                codecType = typeParameter;
-                break;
-            }
-        }
-
-        try {
-            decodeMethod = genericCodecInstance.getClass().getMethod(DECODE_METHOD_SIGNATURE, Value.class);
-        } catch (NoSuchMethodException ex) {
-            Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-        } catch (SecurityException ex) {
-            Logger.getLogger(JSONCodecStore.class.getName()).log(Level.SEVERE, null, ex);
-        }
-
-        if (encodeMethod != null && decodeMethod != null) {
-            genericCodecInstance.setEncodeMethod(encodeMethod);
-            genericCodecInstance.setDecodeMethod(decodeMethod);
-            codecList.add(codec);
-            codecInstanceMap.put(codecType, genericCodecInstance);
-        }
-    }
-
-    public void registerCodec(Class<?> type, Class<?> codec) {
-    }
-
-    public void deregisterCodec(Class<?> codec) {
-        if (codecList.contains(codec)) {
-            int codecHash = codec.hashCode();
-            Iterator<Class<?>> codecInstanceIterator = codecInstanceMap.keySet().iterator();
-            while (codecInstanceIterator.hasNext()) {
-                Class<?> codecType = codecInstanceIterator.next();
-                JSONCodec<?> codecInstance = codecInstanceMap.get(codecType);
-                if (codecInstance.getCodecHash() == codecHash) {
-                    codecInstanceMap.remove(codecType);
-                    codecList.remove(codec);
-                    break;
-                }
-            }
-        }
-
-    }
-
-    /**
-     * Check if the codec store has a codec registered for the class specified.
-     * If a codec is found then this will return true. The check will test the
-     * specified class then all parents of the specified class.
-     * @param type Class instance to check for.
-     * @return true when codec is found or false when there is not a codec.
-     */
-    public boolean hasCodec(Class<?> type) {
-        if (codecInstanceMap.containsKey(type)) {
-            return true;
-        } else {
-            // Check parent types
-            Class<?> parent = type.getSuperclass();
-            do {
-                if (codecInstanceMap.containsKey(parent)) {
-                    return true;
-                }
-            } while ((parent = parent.getSuperclass()) != null);
-            return false;
-        }
-    }
-
-    /**
-     * Finds the codec for the specified type. The check will check if a codec exists for the
-     * specified class then all parents of the specified class. When it finds a codec
-     * it will return it.
-     * @param type The Class type to check for.
-     * @return JSONCodec the codec for the specified class or null if none is found.
-     */
-    public JSONCodec<?> getCodec(Class<?> type) {
-        if (codecInstanceMap.containsKey(type)) {
-            return codecInstanceMap.get(type);
-        } else {
-            Class<?> parent = type.getSuperclass();
-            do {
-                if (codecInstanceMap.containsKey(parent)) {
-                    return codecInstanceMap.get(parent);
-                }
-            } while ((parent = type.getSuperclass()) != null);
-            return null;
-        }
-    }
-}

src/main/java/cc/plural/jsonij/marshal/JSONDocumentMarshaler.java

 import java.io.InputStream;
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
     public Object marshalJSONDocument(Value value, Class<?> objectClass) throws JSONMarshalerException {
         Object resultObject = null;
         if (JavaMarshalerObjects.hasCodec(objectClass)) {
-            JSONCodec codec = JavaMarshalerObjects.getCodec(objectClass);
-            resultObject = codec.decode(value);
+//            JSONCodec codec = JavaMarshalerObjects.getCodec(objectClass);
+//            resultObject = codec.decode(value);
         } else {
-            if (value.type() == Value.TYPE.OBJECT) {
-                JSON.Object<CharSequence, Value> jsonObjectRoot = (JSON.Object<CharSequence, Value>) value;
-                resultObject = marshalJSONDocumentObject(jsonObjectRoot, objectClass);
-            } else if (value.type() == Value.TYPE.ARRAY) {
-                JSON.Array<Value> jsonArrayRoot = (JSON.Array<Value>) value;
-                resultObject = marshalJSONDocumentArray(jsonArrayRoot, objectClass);
-            } else {
-                // TODO: Add Strict!
-
-                if (value.type() == Value.TYPE.NUMERIC) {
-                    return value.getNumber();
-                } else if (value.type() == Value.TYPE.STRING) {
-                    return value.toString();
-                } else if (value.type() == Value.TYPE.TRUE) {
-                    return true;
-                } else if (value.type() == Value.TYPE.FALSE) {
-                    return false;
-                } else if (value.type() == Value.TYPE.NULL) {
-                    return null;
-                } else {
-                    //throw new Exception();
-                }
+            ReflectType type = ReflectType.inspectObjectType(objectClass);
+            switch (type) {
+                case OBJECT:
+                    if (value.type() == Value.TYPE.OBJECT) {
+                        JSON.Object<CharSequence, Value> jsonObjectRoot = (JSON.Object<CharSequence, Value>) value;
+                        resultObject = marshalJSONDocumentObject(jsonObjectRoot, objectClass);
+                    } else {
+                        // TODO
+                    }
+                    break;
+                case ARRAY:
+                case ARRAY_BOOLEAN:
+                case ARRAY_BYTE:
+                case ARRAY_SHORT:
+                case ARRAY_INTEGER:
+                case ARRAY_FLOAT:
+                case ARRAY_DOUBLE:
+                case ARRAY_LONG:
+                case ARRAY_STRING:
+                case ARRAY_ENUM:
+                    if (value.type() == Value.TYPE.ARRAY) {
+                        JSON.Array<Value> jsonArrayRoot = (JSON.Array<Value>) value;
+                        resultObject = marshalJSONDocumentArray(jsonArrayRoot, objectClass);
+                    } else {
+                        // TODO: Strict
+                    }
+                    break;
+
+                case STRING:
+                    if (value.type() == Value.TYPE.STRING) {
+                        return value.toString();
+                    }
+                    break;
+                case BOOLEAN:
+                    if (value.type() == Value.TYPE.TRUE) {
+                        return true;
+                    } else if (value.type() == Value.TYPE.FALSE) {
+                        return false;
+                    } else {
+                    }
+                    break;
+                case BYTE:
+                    if (value.type() == Value.TYPE.NUMERIC) {
+                        return value.getNumber().byteValue();
+                    } else {
+                        // TODO: Strict
+                    }
+                    break;
+                case SHORT:
+                    if (value.type() == Value.TYPE.NUMERIC) {
+                        return value.getNumber().shortValue();
+                    } else {
+                        // TODO: Strict
+                    }
+                    break;
+                case INTEGER:
+                    if (objectClass == BigInteger.class) {
+                        return new BigInteger(value.getString());
+                    } else if (value.type() == Value.TYPE.NUMERIC) {
+                        return value.getNumber().intValue();
+                    } else {
+                        // TODO: Strict
+                    }
+                    break;
+                case DOUBLE:
+                    if (objectClass == BigDecimal.class) {
+                        return new BigDecimal(value.getString());
+                    } else if (value.type() == Value.TYPE.NUMERIC) {
+                        return value.getNumber().doubleValue();
+                    } else {
+                        // TODO: Strict
+                    }
+                    break;
+                case FLOAT:
+                    if (value.type() == Value.TYPE.NUMERIC) {
+                        return value.getNumber().floatValue();
+                    } else {
+                        // TODO: Strict
+                    }
+                    break;
+                case LONG:
+                    if (value.type() == Value.TYPE.NUMERIC) {
+                        return value.getNumber().longValue();
+                    } else {
+                        // TODO: Strict
+                    }
+                    break;
+                case UNKOWN:
+                default:
+                    System.out.println("Unknown Type:" + type + " " + value);
+                    throw new RuntimeException("Unhandled Type " + type + " " + value);
             }
         }
         return resultObject;
     }
 
+    public Object marshalJSONDocument(InputStream stream, Class<?> objectClass) throws JSONMarshalerException {
+        JSON json;
+        try {
+            json = JSON.parse(stream);
+        } catch (ParserException ex) {
+            throw new JSONMarshalerException("", ex);
+        } catch (IOException ex) {
+            throw new JSONMarshalerException("", ex);
+        }
+        return marshalJSONDocument(json, objectClass);
+    }
+
+    public Object marshalJSONDocument(String jsonString, Class<?> objectClass) throws JSONMarshalerException {
+        JSON json;
+        try {
+            json = JSON.parse(jsonString);
+        } catch (ParserException ex) {
+            throw new JSONMarshalerException("", ex);
+        } catch (IOException ex) {
+            throw new JSONMarshalerException("", ex);
+        }
+        return marshalJSONDocument(json, objectClass);
+    }
+
     public Object marshalJSONDocumentObject(JSON.Object<CharSequence, Value> jsonObject, Class<?> objectClass) throws JSONMarshalerException {
         Object object = null;
 
         return object;
     }
 
-    public Object marshalJSONDocument(InputStream stream, Class<?> objectClass) throws JSONMarshalerException {
-        JSON json;
-        try {
-            json = JSON.parse(stream);
-        } catch (ParserException ex) {
-            throw new JSONMarshalerException("", ex);
-        } catch (IOException ex) {
-            throw new JSONMarshalerException("", ex);
+    public Object marshalJSONDocumentArray(JSON.Array<Value> jsonArray, Class<?> objectClass) throws JSONMarshalerException {
+        int size = jsonArray.size();
+        ReflectType type = ReflectType.inspectObjectType(objectClass);
+        if (type == ReflectType.OBJECT) {
+            return marshalJSONDocumentList(jsonArray, objectClass);
+        } else {
+            Class<?> componentClass = objectClass.getComponentType();
+            ReflectType componentType = ReflectType.inspectObjectType(componentClass);
+            Object array = Array.newInstance(componentClass, size);
+            for (int i = 0; i < size; i++) {
+                Value value = jsonArray.get(i);
+                if (value.getValueType() == Value.TYPE.OBJECT) {
+                    Array.set(array, i, marshalJSONDocumentObject((JSON.Object<CharSequence, Value>) value, componentClass));
+                } else if (value.getValueType() == Value.TYPE.ARRAY) {
+                    Array.set(array, i, marshalJSONDocumentArray((JSON.Array<Value>) value, componentClass));
+                } else if (componentType == ReflectType.INTEGER) {
+                    Array.set(array, i, jsonArray.get(i).getNumber().intValue());
+                } else if (componentType == ReflectType.FLOAT) {
+                    Array.set(array, i, jsonArray.get(i).getNumber().floatValue());
+                } else if (componentType == ReflectType.DOUBLE) {
+                    Array.set(array, i, jsonArray.get(i).getNumber().doubleValue());
+                } else if (componentType == ReflectType.BYTE) {
+                    Array.set(array, i, jsonArray.get(i).getNumber().byteValue());
+                } else if (componentType == ReflectType.BOOLEAN) {
+                    Array.set(array, i, jsonArray.get(i).getBoolean());
+                } else if (componentType == ReflectType.STRING) {
+                    Array.set(array, i, jsonArray.get(i).getString());
+                } else {
+                    //
+                }
+            }
+            return array;
         }
-        return marshalJSONDocument(json, objectClass);
     }
 
-    public Object marshalJSONDocument(String jsonString, Class<?> objectClass) throws JSONMarshalerException {
-        JSON json;
-        try {
-            json = JSON.parse(jsonString);
-        } catch (ParserException ex) {
-            throw new JSONMarshalerException("", ex);
-        } catch (IOException ex) {
-            throw new JSONMarshalerException("", ex);
-        }
-        return marshalJSONDocument(json, objectClass);
+    public List<?> marshalJSONDocumentList(JSON.Array<Value> jsonArray, Class<?> objectClass) throws JSONMarshalerException {
+        return null;
     }
 
-    public Object marshalJSONDocumentArray(JSON.Array<Value> jsonArray, Class<?> objectClass) throws JSONMarshalerException {
-        int size = jsonArray.size();
-        Class<?> componentClass = objectClass.getComponentType();
-        ReflectType type = ReflectType.inspectObjectType(componentClass);
-
-        Object array = Array.newInstance(componentClass, size);
-        for (int i = 0; i < size; i++) {
-            Value value = jsonArray.get(i);
-            if (value.getValueType() == Value.TYPE.OBJECT) {
-                Array.set(array, i, marshalJSONDocumentObject((JSON.Object<CharSequence, Value>) value, componentClass));
-            } else if (value.getValueType() == Value.TYPE.ARRAY) {
-                Array.set(array, i, marshalJSONDocumentArray((JSON.Array<Value>) value, componentClass));
-            } else if (type == ReflectType.INTEGER) {
-                Array.set(array, i, jsonArray.get(i).getNumber().intValue());
-            } else if (type == ReflectType.FLOAT) {
-                Array.set(array, i, jsonArray.get(i).getNumber().floatValue());
-            } else if (type == ReflectType.DOUBLE) {
-                Array.set(array, i, jsonArray.get(i).getNumber().doubleValue());
-            } else if (type == ReflectType.BYTE) {
-                Array.set(array, i, jsonArray.get(i).getNumber().byteValue());
-            } else if (type == ReflectType.BOOLEAN) {
-                Array.set(array, i, jsonArray.get(i).getBoolean());
-            } else if (type == ReflectType.STRING) {
-                Array.set(array, i, jsonArray.get(i).getString());
-            } else {
-                //
-            }
+    public Map<?, ?> marshalJSONDocumentMap(JSON.Object<CharSequence, Value> jsonMap, Class<?> objectClass) {
+        System.out.println(objectClass);
+        System.out.println(jsonMap);
+
+        Iterator<CharSequence> keySet = jsonMap.keySet().iterator();
+        while(keySet.hasNext()) {
+            CharSequence key = keySet.next();
+            Value v = jsonMap.get(key);
+            
+            
         }
-        return array;
+        
+
+        return null;
     }
 
     private void marshalJSONValue(Value value, Object object, ClassProperty inspectorProperty) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, JSONMarshalerException {
                 Object propertyObject = marshalJSONDocument(value, mutator.getType());
                 mutator.fire(object, propertyObject);
                 return;
+            case MAP:
+                Map<?, ?> propertyMap = marshalJSONDocumentMap((JSON.Object<CharSequence, Value>) value, mutator.getType());
+                mutator.fire(object, propertyMap);
+                return;
             case UNKOWN:
                 Object propertyUnknown = marshalJSONDocument(value, mutator.getType());
                 mutator.fire(object, propertyUnknown);
             default:
                 System.out.println("Unknown Type:" + type + " " + value);
+                throw new RuntimeException("Unhandled Type " + type + " " + value);
 
         }
 

src/main/java/cc/plural/jsonij/marshal/JSONMarshaler.java

  */
 package cc.plural.jsonij.marshal;
 
-import java.io.IOException;
-import java.io.InputStream;
-
 import cc.plural.jsonij.JSON;
 import cc.plural.jsonij.Value;
 import cc.plural.jsonij.parser.ParserException;
+import java.io.IOException;
+import java.io.InputStream;
 
 /**
  *
         INNER_OBJECT_PROPERTY = "$innerObject";
     }
 
-    public static JSON marshalObject(Object o) {
+    public static JSON marshalObject(Object o) throws JSONMarshalerException {
         Value mashaledObject = JAVA_MARSHALLER.marshalObject(o);
         return new JSON(mashaledObject);
     }
         return new JSON(marshaledArray);
     }
 
-    public static JSON marshalObject(Object[] a) {
+    public static JSON marshalObject(Object[] a) throws JSONMarshalerException {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return new JSON(marshaledArray);
     }
 
-    public static Value marshalValue(Object o) throws JSONMarshalerException {
+    public static Value marshalObjectToValue(Object o) throws JSONMarshalerException {
         Value marshaledObject = JAVA_MARSHALLER.marshalObject(o);
         return marshaledObject;
     }
 
-    public static Value marshalValue(boolean[] a) {
+    public static Value marshalObjectToValue(boolean[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(Boolean[] a) {
+    public static Value marshalObjectToValue(Boolean[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(int[] a) {
+    public static Value marshalObjectToValue(int[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(Integer[] a) {
+    public static Value marshalObjectToValue(Integer[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(char[] a) {
+    public static Value marshalObjectToValue(char[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(Character[] a) {
+    public static Value marshalObjectToValue(Character[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(double[] a) {
+    public static Value marshalObjectToValue(double[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(Double[] a) {
+    public static Value marshalObjectToValue(Double[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(float[] a) {
+    public static Value marshalObjectToValue(float[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(Float[] a) {
+    public static Value marshalObjectToValue(Float[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(short[] a) {
+    public static Value marshalObjectToValue(short[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(Short[] a) {
+    public static Value marshalObjectToValue(Short[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(long[] a) {
+    public static Value marshalObjectToValue(long[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(Long[] a) {
+    public static Value marshalObjectToValue(Long[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(String[] a) {
+    public static Value marshalObjectToValue(String[] a) {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }
 
-    public static Value marshalValue(Object[] a) {
+    public static Value marshalObjectToValue(Object[] a) throws JSONMarshalerException {
         Value marshaledArray = JAVA_MARSHALLER.marshalObject(a);
         return marshaledArray;
     }

src/main/java/cc/plural/jsonij/marshal/JavaMarshaler.java

 import cc.plural.jsonij.JSON;
 import cc.plural.jsonij.Value;
 import cc.plural.jsonij.reflect.ReflectType;
+import java.lang.reflect.InvocationTargetException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  *
         javaObjectMarshaler = new JavaMarshalerObjects(this);
     }
 
-    public Value marshalObject(Object o) {
+    public Value marshalObject(Object o) throws JSONMarshalerException {
         CycleDetector cycleDetector = new CycleDetector();
         return marshalAnyObject(o, cycleDetector);
     }
         return marshaledArray;
     }
 
-    public Value marshalObject(Object[] a) {
+    public Value marshalObject(Object[] a) throws JSONMarshalerException {
         int size = 0;
         if ((size = Array.getLength(a)) == 0) {
             return new JSON.Array<JSON.Numeric>();
         return marshaledArray;
     }
 
-    protected Value marshalAnyObject(Object o, CycleDetector cycleDetector) {
+    protected Value marshalAnyObject(Object o, CycleDetector cycleDetector) throws JSONMarshalerException {
         if (o == null) {
             return JSON.NULL;
         }
             case MAP:
                 marshaledObject = marshalJavaMap(o, cycleDetector);
                 break;
+            case CLASS:
+                marshaledObject = marshalJavaObject(o, cycleDetector);
+                break;
             case UNKOWN:
                 marshaledObject = new JSON.String(o.toString());
+                System.out.println("UNKNOWN TYPE!!");
+                Thread.dumpStack();
+                throw new RuntimeException("Unknown Type: " + objectType);
         }
         return marshaledObject;
     }
         return value;
     }
 
-    protected Value marshalJavaArray(Object o, CycleDetector cycleDetector) {
+    protected Value marshalJavaArray(Object o, CycleDetector cycleDetector) throws JSONMarshalerException {
         Value value = null;
         if (o != null) {
             JSON.Array<Value> marshaledArray = new JSON.Array<Value>();
         return value;
     }
 
-    protected Value marshalJavaList(Object o, CycleDetector cycleDetector) {
+    protected Value marshalJavaList(Object o, CycleDetector cycleDetector) throws JSONMarshalerException {
         Value value;
         if (o != null) {
             List<?> marshaledList = (List<?>) o;
         return value;
     }
 
-    protected Value marshalJavaMap(Object o, CycleDetector cycleDetector) {
+    protected Value marshalJavaMap(Object o, CycleDetector cycleDetector) throws JSONMarshalerException {
         Value value;
         if (o != null) {
             Map<?, ?> marshaledMap = (Map<?, ?>) o;
         return value;
     }
 
-    protected Value marshalJavaObject(Object o, CycleDetector cycleDetector) {
-        Value marshaledValue = javaObjectMarshaler.marshalJavaObject(o, cycleDetector);
+    protected Value marshalJavaObject(Object o, CycleDetector cycleDetector) throws JSONMarshalerException {
+        Value marshaledValue;
+        try {
+            marshaledValue = javaObjectMarshaler.marshalJavaObject(o, cycleDetector);
+        } catch (IllegalAccessException ex) {
+            Logger.getLogger(JavaMarshaler.class.getName()).log(Level.SEVERE, null, ex);
+            throw new JSONMarshalerException("object", ex);
+        } catch (IllegalArgumentException ex) {
+            Logger.getLogger(JavaMarshaler.class.getName()).log(Level.SEVERE, null, ex);
+            throw new JSONMarshalerException("object", ex);
+        } catch (InvocationTargetException ex) {
+            Logger.getLogger(JavaMarshaler.class.getName()).log(Level.SEVERE, null, ex);
+            throw new JSONMarshalerException("object", ex);
+        }
         if (marshaledValue == null) {
             marshaledValue = new JSON.String(o.toString());
         }

src/main/java/cc/plural/jsonij/marshal/JavaMarshalerObjects.java

 import cc.plural.jsonij.marshal.JavaMarshaler.CycleDetector;
 import cc.plural.jsonij.marshal.annotation.JSONCollector;
 import cc.plural.jsonij.marshal.annotation.JSONEncoder;
+import cc.plural.jsonij.marshal.codec.JSONValueCodec;
+import cc.plural.jsonij.marshal.codec.JSONValueCodecStore;
+import cc.plural.jsonij.marshal.codec.JSONValueCodecStore.JSONValueCodecHelper;
 import cc.plural.jsonij.reflect.ClassProperty;
 import cc.plural.jsonij.reflect.ClassProperty.ClassPropertyAccessor;
 import cc.plural.jsonij.reflect.Inspection;
 public class JavaMarshalerObjects {
 
     protected JavaMarshaler marshaler;
-
-    static JSONCodecStore codecStore;
-
+    static JSONValueCodecStore codecStore;
     static int cycleLevels;
 
     static {
     public JavaMarshalerObjects(JavaMarshaler marshaler) {
         this.marshaler = marshaler;
     }
-    
-    public Value marshalJavaObject(Object o, CycleDetector cycleDetector) {
+
+    public Value marshalJavaObject(Object o, CycleDetector cycleDetector) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, JSONMarshalerException {
         Class<?> objectClass = o.getClass();
         // Check for JSONEncoder Annotation
         Method[] methods = objectClass.getDeclaredMethods();
-        for(Method method : methods) {
-            if(method.getAnnotation(JSONEncoder.class) != null) {
+        for (Method method : methods) {
+            if (method.getAnnotation(JSONEncoder.class) != null) {
                 // TODO: Encode using method.
             }
         }
 
         Field[] fields = objectClass.getFields();
-        for(Field field : fields) {
-            if(field.getAnnotation(JSONCollector.class) != null) {
+        for (Field field : fields) {
+            if (field.getAnnotation(JSONCollector.class) != null) {
             }
         }
 
         // Check for JSONCodec
-        if(codecStore != null && codecStore.hasCodec(objectClass)) {
-            @SuppressWarnings("rawtypes")
-            JSONCodec codec = codecStore.getCodec(objectClass);
-            @SuppressWarnings("unchecked")
-            Value value = codec.encode(o);
+        if (codecStore != null && codecStore.hasCodec(objectClass)) {
+            JSONValueCodecHelper codecHelper = codecStore.getCodecHelper(objectClass);
+            Value value = codecHelper.encode(o);
             return value;
         }
 
                 try {
                     Field field = property.getAccessor().getField();
                     value = marshalObjectFieldValue(field, o, cycleDetector);
-                    if(value == null) {
+                    if (value == null) {
                         continue;
                     }
-                } catch(Exception ex) {
+                } catch (Exception ex) {
                     value = new JSON.String(ex.toString());
                 }
             } else if (accessor.methodType()) {
                 try {
                     Method method = property.getAccessor().getMethod();
                     value = marshalObjectMethodValue(method, o, cycleDetector);
-                    if(value == null) {
+                    if (value == null) {
                         continue;
                     }
-                } catch(Exception ex) {
+                } catch (Exception ex) {
                     value = new JSON.String(ex.toString());
                 }
             } else {
                 return marshaler.marshalJavaMap(o, cycleDetector);
             }
         }
-        if(valueCollector.isEmpty()) {
+        if (valueCollector.isEmpty()) {
             return null;
         } else {
             JSON.Object<JSON.String, Value> marshaledObject = new JSON.Object<JSON.String, Value>();
             Iterator<String> keySetIterator = valueCollector.keySet().iterator();
-            while(keySetIterator.hasNext()) {
+            while (keySetIterator.hasNext()) {
                 String key = keySetIterator.next();
                 marshaledObject.put(new JSON.String(key), valueCollector.get(key));
             }
         }
     }
 
-    protected Value marshalObjectMethodValue(Method method, Object o, CycleDetector cycleDetector) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+    protected Value marshalObjectMethodValue(Method method, Object o, CycleDetector cycleDetector) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, JSONMarshalerException {
         Value value;
         Object marshaledObject = method.invoke(o);
-        if(marshaledObject == null) {
+        if (marshaledObject == null) {
             value = null;
         } else {
             int hashCode = marshaledObject.hashCode();
-            if(marshaledObject.getClass() == Boolean.class
+            if (marshaledObject.getClass() == Boolean.class
                     || marshaledObject.getClass() == Byte.class
                     || marshaledObject.getClass() == Short.class
                     || marshaledObject.getClass() == Integer.class
                     || marshaledObject.getClass() == Long.class
                     || marshaledObject.getClass() == String.class) {
                 value = marshaler.marshalAnyObject(marshaledObject, cycleDetector.cloneCycleDetector());
-            } else if(!cycleDetector.hashDetected(hashCode) || cycleDetector.getHashCount(hashCode) < JavaMarshalerObjects.getCycleLevels()) {
+            } else if (!cycleDetector.hashDetected(hashCode) || cycleDetector.getHashCount(hashCode) < JavaMarshalerObjects.getCycleLevels()) {
                 cycleDetector.addHash(hashCode);
                 value = marshaler.marshalAnyObject(marshaledObject, cycleDetector.cloneCycleDetector());
             } else {
         return value;
     }
 
-    protected Value marshalObjectFieldValue(Field field, Object o, CycleDetector cycleDetector) throws IllegalArgumentException, IllegalAccessException {
+    protected Value marshalObjectFieldValue(Field field, Object o, CycleDetector cycleDetector) throws IllegalArgumentException, IllegalAccessException, JSONMarshalerException {
         Value value = null;
         Object marshaledObject = field.get(o);
-        if(marshaledObject == null) {
+        if (marshaledObject == null) {
             value = null;
         } else {
             int hashCode = marshaledObject.hashCode();
-            if(marshaledObject.getClass() == Boolean.class
+            if (marshaledObject.getClass() == Boolean.class
                     || marshaledObject.getClass() == Byte.class
                     || marshaledObject.getClass() == Short.class
                     || marshaledObject.getClass() == Integer.class
                     || marshaledObject.getClass() == Long.class
                     || marshaledObject.getClass() == String.class) {
                 value = marshaler.marshalAnyObject(marshaledObject, cycleDetector.cloneCycleDetector());
-            } else if(!cycleDetector.hashDetected(hashCode) || cycleDetector.getHashCount(hashCode) < JavaMarshalerObjects.getCycleLevels()) {
+            } else if (!cycleDetector.hashDetected(hashCode) || cycleDetector.getHashCount(hashCode) < JavaMarshalerObjects.getCycleLevels()) {
                 cycleDetector.addHash(hashCode);
                 value = marshaler.marshalAnyObject(marshaledObject, cycleDetector.cloneCycleDetector());
             } else {
         return value;
     }
 
+    public static void resetCodecStore() {
+        if (codecStore != null) {
+            codecStore = null;
+        }
+    }
+
     public static boolean hasCodec(Class<?> codecType) {
-        if(codecStore == null) {
+        if (codecStore == null) {
             return false;
         } else {
             return codecStore.hasCodec(codecType);
         }
     }
 
-    public static void registerCodec(Class<?> codecClass) {
-        if(codecStore == null) {
-            codecStore = new JSONCodecStore();
+    public static void registerCodec(Class<?> type, Class<? extends JSONValueCodec> codec) {
+        if (codecStore == null) {
+            codecStore = new JSONValueCodecStore();
+        }
+        codecStore.registerCodec(type, codec);
+    }
+
+    public static JSONValueCodecHelper getCodecHelper(Class<?> type) {
+        if (codecStore == null) {
+            return null;
+        } else {
+            return codecStore.getCodecHelper(type);
         }
-        codecStore.registerCodec(codecClass);
     }
 
-    public static JSONCodec<?> getCodec(Class<?> codecType) {
-        if(codecStore == null) {
+    public static Class<? extends JSONValueCodec> getCodec(Class<?> type) {
+        if (codecStore == null) {
             return null;
         } else {
-            return codecStore.getCodec(codecType);
+            return codecStore.getCodec(type);
         }
     }
 

src/main/java/cc/plural/jsonij/marshal/codec/ClassJSONCodec.java

-/**
- * Copyright (C) 2010-2011 J.W.Marsden
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package cc.plural.jsonij.marshal.codec;
-
-import cc.plural.jsonij.JSON;
-import cc.plural.jsonij.Value;
-import cc.plural.jsonij.marshal.JSONCodec;
-
-public class ClassJSONCodec<C extends Class> extends JSONCodec<C> {
-
-    @Override
-    public ClassJSONCodec<C> createInstance() {
-        return new ClassJSONCodec<C>();
-    }
-
-    @Override
-    public Value encode(C c) {
-        return new JSON.String(c.getName());
-    }
-
-    @Override
-    public C decode(Value value) {
-        Class<?> c = null;
-        try {
-            c = Class.forName(value.getString());
-        } catch(ClassNotFoundException ex) {
-            throw new UnsupportedOperationException("Incorrect Value Type." + ex);
-        }
-        return (C) c;
-    }
-}

src/main/java/cc/plural/jsonij/marshal/codec/ClassJSONValueCodec.java

+/*
+ * Copyright 2012 jmarsden.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cc.plural.jsonij.marshal.codec;
+
+import cc.plural.jsonij.JSON;
+import cc.plural.jsonij.Value;
+import cc.plural.jsonij.marshal.JSONMarshalerException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author jmarsden
+ */
+public class ClassJSONValueCodec implements JSONValueCodec {
+
+    public static <D extends Class> Value encode(D d) {
+        JSON.String encoded = new JSON.String(d.getCanonicalName());
+        return encoded;
+    }
+
+    public static <D extends Class<?>> Class<?> decode(Value value, D clazz) throws JSONMarshalerException {
+        if (value.getValueType() == Value.TYPE.STRING) {
+            try {
+                Class<?> decode = Class.forName(value.toString());
+                return decode;
+            } catch (ClassNotFoundException ex) {
+                Logger.getLogger(ClassJSONValueCodec.class.getName()).log(Level.SEVERE, null, ex);
+            }
+            throw new JSONMarshalerException("decodeError");
+        } else {
+            throw new JSONMarshalerException("decodeError");
+        }
+    }
+}

src/main/java/cc/plural/jsonij/marshal/codec/DateJSONCodec.java

-/**
- * Copyright (C) 2010-2011 J.W.Marsden
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- **/
-package cc.plural.jsonij.marshal.codec;
-
-import cc.plural.jsonij.JSON;
-import cc.plural.jsonij.Value;
-import cc.plural.jsonij.marshal.JSONCodec;
-
-/**
- * JSON codec implementation for java.util.Date. Encodes a java.util.Date instance
- * into a JSON Object with two attributes,
- *
- * <ol>
- *  <li>$type - The JSON String "java.util.Date"</li>
- *  <li>time - The value of getTime() from the java.util.Date</li>
- * </ol>
- *
- * @author openecho
- */
-public class DateJSONCodec<D extends java.util.Date> extends JSONCodec<D> {
-
-    /**
-     * Helper method to create the specific internalType of the DateJSONCodec. This is
-     * required to circumvent a short coming of Java Generics. Simply return a
-     * new instance of the codec class with the generic internalType specified.
-     * @return DateJSONCodec<java.util.Date> instance.
-     */
-    @Override
-    public DateJSONCodec<? extends java.util.Date> createInstance() {
-        return new DateJSONCodec<java.util.Date>();
-    }
-
-    /**
-     * The encode method for the DateJSONCodec.
-     * @param d Accepts any class D that extends java.util.Date
-     * @return Value Object for the java.util.Date that is passed.
-     */
-    @Override
-    public Value encode(D d) {
-        JSON.Object<JSON.String, Value> object = new JSON.Object<JSON.String, Value>();
-        object.put(new JSON.String("time"), new JSON.Numeric(d.getTime()));
-        return object;
-    }
-
-    /**
-     * The decode method for the DateJSONCodec.
-     * @param value The JSON Value to be decoded.
-     * @return D that extends java.util.Date representing the passed JSON Value
-     */
-    @Override
-    public D decode(Value value) {
-        if(value.getValueType() == Value.TYPE.OBJECT && value.has("time")) {
-            return (D) new java.util.Date(value.get("time").getInt());
-        } else {
-            throw new UnsupportedOperationException("Incorrect Value Type.");
-        }
-    }
-}

src/main/java/cc/plural/jsonij/marshal/codec/DateJSONValueCodec.java

+/*
+ * Copyright 2012 jmarsden.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cc.plural.jsonij.marshal.codec;
+
+import cc.plural.jsonij.JSON;
+import cc.plural.jsonij.Value;
+import cc.plural.jsonij.marshal.JSONMarshalerException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author jmarsden
+ */
+public class DateJSONValueCodec implements JSONValueCodec {
+    
+    public static <D extends java.util.Date> Value encode(D d) {
+        JSON.Object<JSON.String, Value> object = new JSON.Object<JSON.String, Value>();
+        object.put(new JSON.String("time"), new JSON.Numeric(d.getTime()));
+        return object;
+    }
+    
+    public static <D extends java.util.Date> D decode(Value value, Class<D> clazz) throws JSONMarshalerException {
+        if (value.getValueType() == Value.TYPE.OBJECT && value.has("time")) {
+            try {
+                D decodedObject = clazz.newInstance();
+                decodedObject.setTime(value.get("time").getNumber().longValue());
+                return decodedObject;
+            } catch (InstantiationException ex) {
+                Logger.getLogger(DateJSONValueCodec.class.getName()).log(Level.SEVERE, null, ex);
+                throw new JSONMarshalerException("decode");
+            } catch (IllegalAccessException ex) {
+                Logger.getLogger(DateJSONValueCodec.class.getName()).log(Level.SEVERE, null, ex);
+                throw new JSONMarshalerException("decode");
+            }
+        } else {
+            throw new JSONMarshalerException("notdate");
+        }   
+    }
+}

src/main/java/cc/plural/jsonij/marshal/codec/JSONValueCodec.java

+/*
+ * Copyright 2012 jmarsden.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cc.plural.jsonij.marshal.codec;
+
+/**
+ *
+ * @author jmarsden
+ */
+public interface JSONValueCodec {
+    
+}

src/main/java/cc/plural/jsonij/marshal/codec/JSONValueCodecStore.java

+/*
+ * Copyright 2012 jmarsden.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cc.plural.jsonij.marshal.codec;
+
+import cc.plural.jsonij.Value;
+import cc.plural.jsonij.reflect.ReflectType;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author jmarsden
+ */
+public class JSONValueCodecStore {
+
+    public static final String ENCODE_METHOD_SIGNATURE;
+    public static final String DECODE_METHOD_SIGNATURE;
+    public static Map<String, JSONValueCodecHelper> codecs;
+
+    static {
+        ENCODE_METHOD_SIGNATURE = "encode";
+        DECODE_METHOD_SIGNATURE = "decode";
+    }
+
+    public static void clearCodecs() {
+        if (codecs != null) {
+            codecs = null;
+        }
+    }
+
+    public boolean hasCodec(Class<?> type) {
+        String name = type.getName();
+        if (codecs == null) {
+            return false;
+        }
+        if (codecs.containsKey(name)) {
+            return true;
+        }
+        // Check Parents
+        List<Class<?>> interfaceTrace = ReflectType.getInterfaceTrace(type);
+        for (Class<?> i : interfaceTrace) {
+            String interfaceName = i.getName();
+            if (codecs.containsKey(interfaceName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void registerCodec(Class<?> type, Class<? extends JSONValueCodec> codec) {
+        String name = type.getName();
+        if (codecs != null && codecs.containsKey(name)) {
+            return;
+        } else if (codecs == null) {
+            codecs = new HashMap<String, JSONValueCodecHelper>();
+        }
+        
+        JSONValueCodecHelper helper = new JSONValueCodecHelper();
+        helper.type = type;
+
+
+//        List<Class<?>> genericTypes = new ArrayList<Class<?>>();
+//        TypeVariable<Class<?>>[] parameterTypes = (TypeVariable<Class<?>>[]) type.getTypeParameters();
+//        for (TypeVariable<Class<?>> parameterType : parameterTypes) {
+//            Type[] bounds = parameterType.getBounds();
+//            System.out.println(bounds[0]);
+//        }
+
+
+
+        helper.codec = codec;
+        Method[] methods = codec.getMethods();
+        for (Method method : methods) {
+            if (method.getName().equals(ENCODE_METHOD_SIGNATURE)) {
+                helper.encodeMethod = method;
+            } else if (method.getName().equals(DECODE_METHOD_SIGNATURE)) {
+                helper.decodeMethod = method;
+            }
+        }
+        codecs.put(name, helper);
+    }
+
+    public JSONValueCodecHelper getCodecHelper(Class<?> type) {
+        String name = type.getName();
+        
+        if (codecs.containsKey(name)) {
+            return codecs.get(name);
+        } else {
+            // Check Parents
+            List<Class<?>> interfaceTrace = ReflectType.getInterfaceTrace(type);
+            for (Class<?> i : interfaceTrace) {
+                String interfaceName = i.getName();
+                if (codecs.containsKey(interfaceName)) {
+                    return codecs.get(interfaceName);
+                }
+            }
+        }
+        return null;
+    }
+
+    public Class<? extends JSONValueCodec> getCodec(Class<?> type) {
+        String name = type.getName();
+        if (codecs.containsKey(name)) {
+            return codecs.get(name).getCodec();
+        } else {
+            // Check Parents
+            List<Class<?>> interfaceTrace = ReflectType.getInterfaceTrace(type);
+            for (Class<?> i : interfaceTrace) {
+                 String interfaceName = i.getName();
+                if (codecs.containsKey(interfaceName)) {
+                    return codecs.get(interfaceName).getCodec();
+                }
+            }
+        }
+        return null;
+    }
+
+    public static class JSONValueCodecHelper {
+
+        private Class<?> type;
+        //private Class<?>[] genericTypes;
+        private Class<? extends JSONValueCodec> codec;
+        private Method encodeMethod;
+        private Method decodeMethod;
+
+        public Class<? extends JSONValueCodec> getCodec() {
+            return codec;
+        }
+
+        public void setCodec(Class<? extends JSONValueCodec> codec) {
+            this.codec = codec;
+        }
+
+        public Method getEncodeMethod() {
+            return encodeMethod;
+        }
+
+        public void setEncodeMethod(Method encodeMethod) {
+            this.encodeMethod = encodeMethod;
+        }
+
+        public Method getDecodeMethod() {
+            return decodeMethod;
+        }
+
+        public void setDecodeMethod(Method decodeMethod) {
+            this.decodeMethod = decodeMethod;
+        }
+
+        public Value encode(Object object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+            return (Value) encodeMethod.invoke(codec, new Object[]{object});
+        }
+
+        public Object decode(Value value) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+            return (Value) decodeMethod.invoke(codec, new Object[]{value});
+        }
+
+        @Override
+        public String toString() {
+            return "JSONValueCodecHelper[codec=" + codec + " encodeMethod=" + encodeMethod + " decodeMethod=" + decodeMethod + "]";
+        }
+    }
+}

src/main/java/cc/plural/jsonij/reflect/InspectionFactory.java

  */
 package cc.plural.jsonij.reflect;
 
+import cc.plural.jsonij.marshal.annotation.JSONName;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
  * @author jmarsden@plural.cc
  */
 public class InspectionFactory {
-    
+
     public InspectionFilter filter;
     public static final String IS_PREFIX;
     public static final String SET_PREFIX;
     public static final String GET_PREFIX;
-    
+
     static {
         IS_PREFIX = "is";
         SET_PREFIX = "set";
         GET_PREFIX = "get";
     }
-    
+
     public InspectionFactory() {
         filter = InspectionFilter.getDefaultFilters();
     }
-    
+
     public Inspection inspect(Object object) {
         return inspect(object.getClass());
     }
-    
+
     public Inspection inspect(Class<?> klass) {
         if (klass == null) {
             throw new NullPointerException();
         }
         List<ClassProperty> tempProperties = new ArrayList<ClassProperty>();
-        
+
         Class<?> currentClass = klass;
         do {
             if (filter.isFiltered(currentClass)) {
                 }
             }
         } while ((currentClass = currentClass.getSuperclass()) != null);
-        
+
         List<ClassProperty> classProperties = new ArrayList<ClassProperty>();
         List<ClassProperty> collectorProperties = new ArrayList<ClassProperty>();
         for (ClassProperty property : tempProperties) {
                 classProperties.add(property);
             }
         }
-        
+
         Inspection inspection = new Inspection();
         inspection.setKlass(klass);
         inspection.setProperties(classProperties);
         inspection.setCollectors(collectorProperties);
         return inspection;
     }
-    
+
     private List<ClassProperty> inspectClassProperties(Class<?> klass) {
         Map<String, ClassProperty> propertyMap = new HashMap<String, ClassProperty>();
         Field[] fields = klass.getDeclaredFields();
         for (Field field : fields) {
             ClassProperty property = new ClassProperty();
             property.setKlass(klass);
-            property.setPropertyName(field.getName());
+            String propertyName = field.getName();
+            if (field.isAnnotationPresent(JSONName.class)) {
+                JSONName jsonName = (JSONName) field.getAnnotation(JSONName.class);
+                propertyName = jsonName.value();
+            }
+            property.setPropertyName(propertyName);
             property.registerAccessor(field);
             property.registorMutator(field);
-            propertyMap.put(field.getName(), property);
+            propertyMap.put(propertyName, property);
         }
         Method[] methods = klass.getDeclaredMethods();
         for (Method method : methods) {
             char ch;
             String propertyName = null;
             String methodName = method.getName();
+
             Class<?> returnType = method.getReturnType();
             if (methodName.length() > IS_PREFIX.length() && methodName.startsWith(IS_PREFIX) && returnType == boolean.class && Character.isUpperCase(ch = methodName.charAt(IS_PREFIX.length()))) {
-                propertyName = Character.toLowerCase(ch) + methodName.substring(IS_PREFIX.length() + 1, methodName.length());
+                if (method.isAnnotationPresent(JSONName.class)) {
+                    JSONName jsonName = (JSONName) method.getAnnotation(JSONName.class);
+                    propertyName = jsonName.value();
+                } else {
+                    propertyName = Character.toLowerCase(ch) + methodName.substring(IS_PREFIX.length() + 1, methodName.length());
+                }
                 ClassProperty property = null;
                 if (propertyMap.containsKey(propertyName)) {
                     property = propertyMap.get(propertyName);
         propertyList.addAll(propertyMap.values());
         return propertyList;
     }
-    
+
     public static boolean isMapType(Class<?> c) {
         Class<?> currentClass = c;
         do {
         } while ((currentClass = currentClass.getSuperclass()) != null);
         return false;
     }
-    
+
     public static boolean isListType(Class<?> c) {
         Class<?> currentClass = c;
         do {

src/main/java/cc/plural/jsonij/reflect/ReflectType.java

 import java.util.Map;
 
 import cc.plural.jsonij.marshal.JSONMarshaler;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
 
 /**
  * JavaType Utility. Queries objects for their types and manages inspector
  * instances so time is not wasted re-inspecting the same objects.
  *
- * Inspecting is the task of reflecting attributes and methods and their
- * types for access.
+ * Inspecting is the task of reflecting attributes and methods and their types
+ * for access.
  *
  * @author jmarsden@plural.cc
  */
 public enum ReflectType {
 
     /**
-     * The JavaTypes possible for an inspection.
-     * UNKNOWN will be returned where an object cannot be decided.
-     * ARRAY will be returned for an array of Objects.
+     * The JavaTypes possible for an inspection. UNKNOWN will be returned where
+     * an object cannot be decided. ARRAY will be returned for an array of
+     * Objects.
      */
     BOOLEAN,
     BYTE,
     ARRAY_LIST,
     ARRAY_MAP,
     ARRAY_ARRAY,
+    CLASS,
     UNKOWN;
-
     boolean primitive;
-
     JavaArrayType arrayType;
-
     static final protected InspectionFactory inspectionFactory;
-    
     static final protected Map<Class<?>, Inspection> inspectedClasses;
 
     static {
 
     public static ReflectType inspectObjectType(Class<?> c) {
         ReflectType type = null;
-        if(c == boolean.class) {
+        if (c == boolean.class) {
             type = BOOLEAN;
             type.setPrimitive(true);
             return type;
-        } else if(c == Boolean.class) {
+        } else if (c == Boolean.class) {
             type = BOOLEAN;
             type.setPrimitive(false);
             return type;
-        } else if(c == int.class) {
+        } else if (c == int.class) {
             type = INTEGER;
             type.setPrimitive(true);
             return type;
-        } else if(c == Integer.class) {
+        } else if (c == Integer.class) {
             type = INTEGER;
             type.setPrimitive(false);
             return type;
-        } else if(c == double.class) {
+        } else if (c == BigInteger.class) {
+            type = INTEGER;
+            type.setPrimitive(false);
+            return type;
+        } else if (c == double.class) {
             type = DOUBLE;
             type.setPrimitive(true);
             return type;
-        } else if(c == Double.class) {
+        } else if (c == Double.class) {
+            type = DOUBLE;
+            type.setPrimitive(false);
+            return type;
+        } else if (c == BigDecimal.class) {
             type = DOUBLE;
             type.setPrimitive(false);
             return type;
-        } else if(c == float.class) {
+        } else if (c == float.class) {
             type = FLOAT;
             type.setPrimitive(true);
             return type;
-        } else if(c == Float.class) {
+        } else if (c == Float.class) {
             type = FLOAT;
             type.setPrimitive(false);
             return type;
-        } else if(c == long.class) {
+        } else if (c == long.class) {
             type = LONG;
             type.setPrimitive(true);
             return type;
-        } else if(c == Long.class) {
+        } else if (c == Long.class) {
             type = LONG;
             type.setPrimitive(false);
             return type;
-        } else if(c == short.class) {
+        } else if (c == short.class) {
             type = SHORT;
             type.setPrimitive(true);
             return type;
-        } else if(c == Short.class) {
+        } else if (c == Short.class) {
             type = SHORT;
             type.setPrimitive(false);
             return type;
-        } else if(c == byte.class) {
+        } else if (c == byte.class) {
             type = BYTE;
             type.setPrimitive(true);
             return type;
-        } else if(c == Byte.class) {
+        } else if (c == Byte.class) {
             type = BYTE;
             type.setPrimitive(false);
             return type;
-        } else if(c.isEnum()) {
+        } else if (c.isEnum()) {
             type = ENUM;
             type.setPrimitive(false);
             return type;
-        } else if(c == String.class || c == CharSequence.class ||((c == char.class || c == Character.class))) {
+        } else if (c == String.class || c == CharSequence.class || ((c == char.class || c == Character.class))) {
             type = STRING;
             type.setPrimitive(false);
             return type;
-        } else if(c.isArray()) {
+        } else if (c.isArray()) {
             type = getArrayType(c);
             return type;
         }
         
-        if(c == List.class) {
+        if(c == Class.class) {