You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/04/30 08:38:20 UTC

[1/2] git commit: ISIS-233: refactoring JsonValueEncoder

Updated Branches:
  refs/heads/master f0526cdfe -> 9b651e2e5


ISIS-233: refactoring JsonValueEncoder


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/4ff4f713
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/4ff4f713
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/4ff4f713

Branch: refs/heads/master
Commit: 4ff4f71373a8b6bc453f91ea0f2c6c52d7329414
Parents: f0526cd
Author: Dan Haywood <da...@apache.org>
Authored: Mon Apr 29 20:48:07 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Mon Apr 29 20:48:07 2013 +0100

----------------------------------------------------------------------
 .../restfulobjects/applib/JsonRepresentation.java  |   24 +-
 .../domainobjects/DomainObjectReprRenderer.java    |    2 +-
 .../rendering/domainobjects/JsonValueEncoder.java  |  505 +++++++++------
 .../domainobjects/ScalarValueReprRenderer.java     |    3 +-
 .../JsonValueEncoderTest_asAdapter.java            |    7 +-
 .../JsonValueEncoderTest_asObject.java             |   41 +-
 .../server/resources/DomainResourceHelper.java     |    2 +-
 ...hJodaProperties_thenRepresentation_ok_TODO.java |    1 -
 .../fixture/scalars/JodaValuedEntityFixture.java   |    8 +-
 9 files changed, 356 insertions(+), 237 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/4ff4f713/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java
index 58cd446..d4f7bb7 100644
--- a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java
+++ b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java
@@ -272,15 +272,36 @@ public class JsonRepresentation {
         return !representsNull(node) && node.isValueNode() && node.isNumber();
     }
 
+    public Number asNumber() {
+        return getNumber(null, asJsonNode());
+    }
+
+    private Number getNumber(final String path, final JsonNode node) {
+        if (representsNull(node)) {
+            return null;
+        }
+        checkValue(path, node, "a number");
+        if (!node.isNumber()) {
+            throw new IllegalArgumentException(formatExMsg(path, "is not a number"));
+        }
+        return node.getNumberValue();
+    }
+
 
     // ///////////////////////////////////////////////////////////////////////
-    // isIntegralNumber
+    // isIntegralNumber, getIntegralNumber, asIntegralNumber
     // ///////////////////////////////////////////////////////////////////////
 
+    /**
+     * Is a long, an int or a {@link BigInteger}.
+     */
     public boolean isIntegralNumber(final String path) {
         return isIntegralNumber(getNode(path));
     }
 
+    /**
+     * Is a long, an int or a {@link BigInteger}.
+     */
     public boolean isIntegralNumber() {
         return isIntegralNumber(asJsonNode());
     }
@@ -1379,4 +1400,5 @@ public class JsonRepresentation {
     }
 
 
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/4ff4f713/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
index 9aeef67..dc51bb7 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
@@ -360,7 +360,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
     public static Object valueOrRef(final RendererContext resourceContext, final ObjectAdapter objectAdapter, final ObjectSpecification objectSpec) {
         final ValueFacet valueFacet = objectSpec.getFacet(ValueFacet.class);
         if (valueFacet != null) {
-            return new JsonValueEncoder().asObject(objectAdapter);
+            return JsonValueEncoder.asObject(objectAdapter);
         }
         final TitleFacet titleFacet = objectSpec.getFacet(TitleFacet.class);
         final String title = titleFacet.title(objectAdapter, resourceContext.getLocalization());

http://git-wip-us.apache.org/repos/asf/isis/blob/4ff4f713/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
index 0989147..3655e4e 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
@@ -20,12 +20,23 @@ package org.apache.isis.viewer.restfulobjects.rendering.domainobjects;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 
 import org.codehaus.jackson.node.NullNode;
 
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 
 /**
@@ -34,11 +45,251 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
  */
 public final class JsonValueEncoder {
 
+    private JsonValueEncoder(){}
+
+    
     public static class ExpectedStringRepresentingValueException extends IllegalArgumentException {
         private static final long serialVersionUID = 1L;
     }
 
-    public ObjectAdapter asAdapter(final ObjectSpecification objectSpec, final JsonRepresentation argRepr) {
+    public static abstract class JsonValueConverter {
+
+        private final String format;
+        private final String xIsisFormat;
+        private final Class<?>[] classes;
+
+        public JsonValueConverter(String format, String xIsisFormat, Class<?>... classes) {
+            this.format = format;
+            this.xIsisFormat = xIsisFormat;
+            this.classes = classes;
+        }
+
+        public List<ObjectSpecId> getSpecIds() {
+            return Lists.newArrayList(Iterables.transform(Arrays.asList(classes), new Function<Class<?>, ObjectSpecId>() {
+                public ObjectSpecId apply(Class<?> cls) {
+                    return new ObjectSpecId(cls.getName());
+                }
+            }));
+        }
+        
+        /**
+         * The value, otherwise <tt>null</tt>.
+         */
+        public abstract ObjectAdapter asAdapter(JsonRepresentation repr);
+        
+        public void appendValueAndFormat(ObjectAdapter objectAdapter, JsonRepresentation repr) {
+            append(repr, objectAdapter, format, xIsisFormat);
+        }
+
+        public Object asObject(ObjectAdapter objectAdapter) {
+            return objectAdapter.getObject();
+        }
+        
+        
+
+
+    }
+    
+    private static Map<ObjectSpecId, JsonValueConverter> converterBySpec = Maps.newLinkedHashMap();
+    
+    private static void putConverter(JsonValueConverter jvc) {
+        final List<ObjectSpecId> specIds = jvc.getSpecIds();
+        for (ObjectSpecId specId : specIds) {
+            converterBySpec.put(specId, jvc);
+        }
+    }
+
+    static {
+        putConverter(new JsonValueConverter(null, "boolean", boolean.class, Boolean.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isBoolean()) {
+                    return adapterFor(repr.asBoolean());
+                } 
+                return null;
+            }
+        });
+        
+        putConverter(new JsonValueConverter(null, "byte", byte.class, Byte.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isNumber()) {
+                    return adapterFor(repr.asNumber().byteValue());
+                }
+                if (repr.isInt()) {
+                    return adapterFor((byte)(int)repr.asInt());
+                }
+                if (repr.isLong()) {
+                    return adapterFor((byte)(long)repr.asLong());
+                }
+                if (repr.isBigInteger()) {
+                    return adapterFor(repr.asBigInteger().byteValue());
+                }
+                return null;
+            }
+        });
+        
+        putConverter(new JsonValueConverter(null, "short", short.class, Short.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isNumber()) {
+                    return adapterFor(repr.asNumber().shortValue());
+                }
+                if (repr.isInt()) {
+                    return adapterFor((short)(int)repr.asInt());
+                }
+                if (repr.isLong()) {
+                    return adapterFor((short)(long)repr.asLong());
+                }
+                if (repr.isBigInteger()) {
+                    return adapterFor(repr.asBigInteger().shortValue());
+                }
+                return null;
+            }
+        });
+        
+        putConverter(new JsonValueConverter("int", "int", int.class, Integer.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isInt()) {
+                    return adapterFor(repr.asInt());
+                }
+                if (repr.isLong()) {
+                    return adapterFor((int)(long)repr.asLong());
+                }
+                if (repr.isBigInteger()) {
+                    return adapterFor(repr.asBigInteger().intValue());
+                }
+                if (repr.isNumber()) {
+                    return adapterFor(repr.asNumber().intValue());
+                }
+                return null;
+            }
+        });
+        
+        putConverter(new JsonValueConverter("int", "long", long.class, Long.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isLong()) {
+                    return adapterFor(repr.asLong());
+                }
+                if (repr.isInt()) {
+                    return adapterFor(repr.asInt());
+                }
+                if (repr.isBigInteger()) {
+                    return adapterFor(repr.asBigInteger().longValue());
+                }
+                if (repr.isNumber()) {
+                    return adapterFor(repr.asNumber().longValue());
+                }
+                return null;
+            }
+        });
+        
+        putConverter(new JsonValueConverter("decimal", "float", float.class, Float.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isDouble()) {
+                    return adapterFor((float)(double)repr.asDouble());
+                }
+                if (repr.isNumber()) {
+                    return adapterFor(repr.asNumber().floatValue());
+                }
+                if (repr.isLong()) {
+                    return adapterFor((float)repr.asLong());
+                }
+                if (repr.isInt()) {
+                    return adapterFor((float)repr.asInt());
+                }
+                if (repr.isBigInteger()) {
+                    return adapterFor(repr.asBigInteger().floatValue());
+                }
+                return null;
+            }
+        });
+        
+        putConverter(new JsonValueConverter("decimal", "double", double.class, Double.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isDouble()) {
+                    return adapterFor(repr.asDouble());
+                }
+                if (repr.isLong()) {
+                    return adapterFor((double)repr.asLong());
+                }
+                if (repr.isInt()) {
+                    return adapterFor((double)repr.asInt());
+                }
+                if (repr.isBigInteger()) {
+                    return adapterFor(repr.asBigInteger().doubleValue());
+                }
+                if (repr.isBigDecimal()) {
+                    return adapterFor(repr.asBigDecimal().doubleValue());
+                }
+                if (repr.isNumber()) {
+                    return adapterFor(repr.asNumber().doubleValue());
+                }
+                return null;
+            }
+        });
+        
+        putConverter(new JsonValueConverter(null, "char", char.class, Character.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isString()) {
+                    final String str = repr.asString();
+                    if(str != null && str.length()>0) {
+                        return adapterFor(str.charAt(0));
+                    }
+                }
+                return null;
+            }
+        });
+        
+        putConverter(new JsonValueConverter("int", "biginteger", BigInteger.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isBigInteger()) {
+                    return adapterFor(repr.asBigInteger());
+                }
+                if (repr.isLong()) {
+                    return adapterFor(BigInteger.valueOf(repr.asLong()));
+                }
+                if (repr.isInt()) {
+                    return adapterFor(BigInteger.valueOf(repr.asInt()));
+                }
+                if (repr.isNumber()) {
+                    return adapterFor(BigInteger.valueOf(repr.asNumber().longValue()));
+                }
+                return null;
+            }
+        });
+        
+        putConverter(new JsonValueConverter("decimal", "bigdecimal", BigDecimal.class){
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                // TODO: if inferring a BigDecimal, need to get the scale from somewhere...
+                if (repr.isBigDecimal()) {
+                    return adapterFor(repr.asBigDecimal());
+                }
+                if (repr.isBigInteger()) {
+                    return adapterFor(new BigDecimal(repr.asBigInteger()));
+                }
+                if (repr.isDouble()) {
+                    return adapterFor(BigDecimal.valueOf(repr.asDouble()));
+                }
+                if (repr.isLong()) {
+                    return adapterFor(BigDecimal.valueOf(repr.asLong()));
+                }
+                if (repr.isInt()) {
+                    return adapterFor(BigDecimal.valueOf(repr.asInt()));
+                }
+                return null;
+            }
+        });
+    }
+
+    public static ObjectAdapter asAdapter(final ObjectSpecification objectSpec, final JsonRepresentation argRepr) {
         if (objectSpec == null) {
             String reason = "ObjectSpec is null, cannot validate";
             argRepr.mapPut("invalidReason", reason);
@@ -50,6 +301,7 @@ public final class JsonValueEncoder {
             argRepr.mapPut("invalidReason", reason);
             throw new IllegalArgumentException(reason);
         }
+        
         if(!argRepr.mapHas("value")) {
             String reason = "No 'value' key";
             argRepr.mapPut("invalidReason", reason);
@@ -65,198 +317,62 @@ public final class JsonValueEncoder {
             throw new IllegalArgumentException(reason);
         }
 
-        // special case handling for JSON built-ins
-        if (isBoolean(objectSpec)) {
-            if (!argValueRepr.isBoolean()) {
-                throwIncompatibleException(objectSpec, argRepr);
-            }
-            final String argStr = "" + argValueRepr.asBoolean();
-            return encodableFacet.fromEncodedString(argStr);
-        }
-
-        if (isInteger(objectSpec)) {
-            if (argValueRepr.isInt()) {
-                final String argStr = "" + argValueRepr.asInt();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            // best effort
-            if (argValueRepr.isString()) {
-                final String argStr = argValueRepr.asString();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            // give up
-            throwIncompatibleException(objectSpec, argRepr);
-        }
-
-        if (isLong(objectSpec)) {
-            if (!argValueRepr.isLong()) {
-                throwIncompatibleException(objectSpec, argRepr);
-            }
-            final String argStr = "" + argValueRepr.asLong();
-            return encodableFacet.fromEncodedString(argStr);
-        }
-
-        if (isBigInteger(objectSpec)) {
-            if (argValueRepr.isBigInteger()) {
-                final String argStr = "" + argValueRepr.asBigInteger();
-                return encodableFacet.fromEncodedString(argStr);
-            }
+        final JsonValueConverter jvc = converterBySpec.get(objectSpec.getSpecId());
+        if(jvc == null) {
             // best effort
-            if (argValueRepr.isLong()) {
-                final String argStr = "" + argValueRepr.asLong();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            if (argValueRepr.isInt()) {
-                final String argStr = "" + argValueRepr.asInt();
-                return encodableFacet.fromEncodedString(argStr);
-            }
             if (argValueRepr.isString()) {
                 final String argStr = argValueRepr.asString();
                 return encodableFacet.fromEncodedString(argStr);
             }
-            // give up
-            throwIncompatibleException(objectSpec, argRepr);
-        }
 
-        if (isBigDecimal(objectSpec)) {
-            if (argValueRepr.isBigDecimal()) {
-                final String argStr = "" + argValueRepr.asBigDecimal();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            // best effort
-            if (argValueRepr.isBigInteger()) {
-                final String argStr = "" + argValueRepr.asBigInteger();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            if (argValueRepr.isDouble()) {
-                final String argStr = "" + argValueRepr.asDouble();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            if (argValueRepr.isLong()) {
-                final String argStr = "" + argValueRepr.asLong();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            if (argValueRepr.isInt()) {
-                final String argStr = "" + argValueRepr.asInt();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            if (argValueRepr.isString()) {
-                final String argStr = argValueRepr.asString();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            // give up
-            throwIncompatibleException(objectSpec, argRepr);
+            final String reason = "Unable to parse value";
+            argRepr.mapPut("invalidReason", reason);
+            throw new IllegalArgumentException(reason);
         }
 
-        if (isDouble(objectSpec)) {
-            if (argValueRepr.isDouble()) {
-                final String argStr = "" + argValueRepr.asDouble();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            // best effort
-            if (argValueRepr.isLong()) {
-                final String argStr = "" + argValueRepr.asLong();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            if (argValueRepr.isInt()) {
-                final String argStr = "" + argValueRepr.asInt();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            if (argValueRepr.isString()) {
-                final String argStr = argValueRepr.asString();
-                return encodableFacet.fromEncodedString(argStr);
-            }
-            // give up
-            throwIncompatibleException(objectSpec, argRepr);
+        final ObjectAdapter asAdapter = jvc.asAdapter(argValueRepr);
+        if(asAdapter != null) {
+            return asAdapter;
         }
-
+        
+        // last attempt
         if (argValueRepr.isString()) {
             final String argStr = argValueRepr.asString();
             return encodableFacet.fromEncodedString(argStr);
         }
-        
-        final String reason = "Unable to parse value";
+
+        final String reason = "Could not parse value '" + argValueRepr.asString() + "' as a " + objectSpec.getFullIdentifier();
         argRepr.mapPut("invalidReason", reason);
         throw new IllegalArgumentException(reason);
     }
 
-    static void appendValueAndFormat(ObjectSpecification objectSpec, ObjectAdapter objectAdapter, JsonRepresentation repr) {
+    public static void appendValueAndFormat(ObjectSpecification objectSpec, ObjectAdapter objectAdapter, JsonRepresentation repr) {
 
-        // special case handling for JSON built-ins 
-        // (at least so far as json.org defines them).
-        Object value;
-        String format = null; // as defined by RO spec
-        String xIsisFormat = null; // isis-specific support
-        if (isBoolean(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            xIsisFormat = "boolean";
-        } else if (isByte(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            xIsisFormat = "byte";
-        } else if (isChar(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            xIsisFormat = "char";
-        } else if (isShort(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            xIsisFormat = "short";
-        } else if (isInteger(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            format = "int";
-            xIsisFormat = "int";
-        } else if (isLong(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            format = "int";
-            xIsisFormat = "long";
-        } else if (isBigInteger(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            format = "int";
-            xIsisFormat = "biginteger";
-        } else if (isFloat(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            format = "decimal";
-            xIsisFormat = "float";
-        } else if (isDouble(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            format = "decimal";
-            xIsisFormat = "double";
-        } else if (isBigDecimal(objectSpec)) {
-            value = asValueElseNull(objectAdapter);
-            format = "decimal";
-            xIsisFormat = "bigdecimal";
+        final JsonValueConverter jvc = converterBySpec.get(objectSpec.getSpecId());
+        if(jvc != null) {
+            jvc.appendValueAndFormat(objectAdapter, repr);
         } else {
             final EncodableFacet encodableFacet = objectSpec.getFacet(EncodableFacet.class);
             if (encodableFacet == null) {
                 throw new IllegalArgumentException("objectSpec expected to have EncodableFacet");
             }
-            value = objectAdapter != null? encodableFacet.toEncodedString(objectAdapter): NullNode.getInstance();
-        }
-        
-        repr.mapPut("value", value);
-        if(format != null) {
-            repr.mapPut("format", format);
-        }
-        if(xIsisFormat != null) {
-            repr.mapPut("x-isis-format", xIsisFormat);
+            Object value = objectAdapter != null? encodableFacet.toEncodedString(objectAdapter): NullNode.getInstance();
+            append(repr, value, "decimal", "bigdecimal");
         }
     }
-
-    private static Object asValueElseNull(ObjectAdapter objectAdapter) {
-        return objectAdapter != null? objectAdapter.getObject(): NullNode.getInstance();
-    }
-
-    static Object asObject(final ObjectAdapter objectAdapter) {
+    
+    public static Object asObject(final ObjectAdapter objectAdapter) {
         if (objectAdapter == null) {
             throw new IllegalArgumentException("objectAdapter cannot be null");
         }
         final ObjectSpecification objectSpec = objectAdapter.getSpecification();
 
-        // special case handling for JSON built-ins (at least so far as json.org
-        // defines them).
-        if (isBoolean(objectSpec) || isInteger(objectSpec) || isLong(objectSpec) || isBigInteger(objectSpec) || isDouble(objectSpec) || isBigDecimal(objectSpec)) {
-            // simply return
-            return objectAdapter.getObject();
-        }
-
+        final JsonValueConverter jvc = converterBySpec.get(objectSpec.getSpecId());
+        if(jvc != null) {
+            return jvc.asObject(objectAdapter);
+        } 
+        
+        // else
         final EncodableFacet encodableFacet = objectSpec.getFacet(EncodableFacet.class);
         if (encodableFacet == null) {
             throw new IllegalArgumentException("objectSpec expected to have EncodableFacet");
@@ -264,61 +380,34 @@ public final class JsonValueEncoder {
         return encodableFacet.toEncodedString(objectAdapter);
     }
 
-    private static boolean isBoolean(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, boolean.class, Boolean.class);
-    }
-
-    private static boolean isByte(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, byte.class, Byte.class);
-    }
-    
-    private static boolean isChar(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, char.class, Character.class);
-    }
     
-    private static boolean isShort(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, short.class, Short.class);
-    }
 
-    private static boolean isInteger(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, int.class, Integer.class);
-    }
-    
-    private static boolean isLong(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, long.class, Long.class);
+    private static void append(JsonRepresentation repr, Object value, String format, String xIsisFormat) {
+        repr.mapPut("value", value);
+        if(format != null) {
+            repr.mapPut("format", format);
+        }
+        if(xIsisFormat != null) {
+            repr.mapPut("x-isis-format", xIsisFormat);
+        }
     }
 
-    private static boolean isBigInteger(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, BigInteger.class);
+    private static void append(JsonRepresentation repr, ObjectAdapter value, String format, String xIsisFormat) {
+        append(repr, unwrap(value), format, xIsisFormat);
     }
     
-    private static boolean isFloat(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, float.class, Float.class);
+    private static Object unwrap(ObjectAdapter objectAdapter) {
+        return objectAdapter != null? objectAdapter.getObject(): NullNode.getInstance();
     }
 
-    private static boolean isDouble(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, double.class, Double.class);
-    }
-    
-    private static boolean isBigDecimal(final ObjectSpecification objectSpec) {
-        return hasCorrespondingClass(objectSpec, BigDecimal.class);
-    }
 
-    private static boolean hasCorrespondingClass(final ObjectSpecification objectSpec, final Class<?>... candidates) {
-        final Class<?> specClass = objectSpec.getCorrespondingClass();
-        for (final Class<?> candidate : candidates) {
-            if (specClass == candidate) {
-                return true;
-            }
-        }
-        return false;
-    }
 
-    private void throwIncompatibleException(final ObjectSpecification objectSpec, final JsonRepresentation argRepr) {
-        String reason = String.format("representation '%s' incompatible with objectSpec '%s'", argRepr.getMap("value").toString(), objectSpec.getCorrespondingClass().getName());
-        argRepr.mapPut("invalidReason", reason);
-        throw new IllegalArgumentException(reason);
+    private static ObjectAdapter adapterFor(Object value) {
+        return getAdapterManager().adapterFor(value);
+    }
+    
+    public static AdapterManager getAdapterManager() {
+        return IsisContext.getPersistenceSession().getAdapterManager();
     }
-
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/4ff4f713/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
index f5eb48a..159765c 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
@@ -31,7 +31,6 @@ import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererException;
 
 public class ScalarValueReprRenderer extends ReprRendererAbstract<ScalarValueReprRenderer, ObjectAdapter> {
 
-    private final JsonValueEncoder jsonValueEncoder = new JsonValueEncoder();
     private ObjectSpecification returnType;
 
     ScalarValueReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) {
@@ -55,7 +54,7 @@ public class ScalarValueReprRenderer extends ReprRendererAbstract<ScalarValueRep
         if (facet == null) {
             throw ReprRendererException.create("Not an (encodable) value", objectAdapter.titleString());
         }
-        final Object value = jsonValueEncoder.asObject(objectAdapter);
+        final Object value = JsonValueEncoder.asObject(objectAdapter);
 
         representation.mapPut("value", value);
         return this;

http://git-wip-us.apache.org/repos/asf/isis/blob/4ff4f713/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
index b313c74..e4cf0e4 100644
--- a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
+++ b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
@@ -63,18 +63,17 @@ public class JsonValueEncoderTest_asAdapter {
         objectAdapter = context.mock(ObjectAdapter.class);
 
         representation = new JsonRepresentation(TextNode.valueOf("aString"));
-        jsonValueEncoder = new JsonValueEncoder();
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void whenSpecIsNull() throws Exception {
-        jsonValueEncoder.asAdapter(null, representation);
+        JsonValueEncoder.asAdapter(null, representation);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void whenReprIsNull() throws Exception {
         allowingObjectSpecHas(EncodableFacet.class, encodableFacet);
-        jsonValueEncoder.asAdapter(objectSpec, null);
+        JsonValueEncoder.asAdapter(objectSpec, null);
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -308,7 +307,7 @@ public class JsonValueEncoderTest_asAdapter {
         });
 
         // when
-        final ObjectAdapter adapter = jsonValueEncoder.asAdapter(objectSpec, representation);
+        final ObjectAdapter adapter = JsonValueEncoder.asAdapter(objectSpec, representation);
 
         // then
         assertSame(objectAdapter, adapter);

http://git-wip-us.apache.org/repos/asf/isis/blob/4ff4f713/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
index 584b883..d324744 100644
--- a/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
+++ b/component/viewer/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
@@ -24,11 +24,6 @@ import static org.junit.Assert.assertSame;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.jmock.integration.junit4.JMock;
@@ -37,12 +32,18 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
+
 @RunWith(JMock.class)
 public class JsonValueEncoderTest_asObject {
 
     private final Mockery context = new JUnit4Mockery();
 
-    private JsonValueEncoder jsonValueEncoder;
     private JsonRepresentation representation;
     private ObjectAdapter objectAdapter;
     private ObjectSpecification objectSpec;
@@ -64,20 +65,18 @@ public class JsonValueEncoderTest_asObject {
         encodableFacet = context.mock(EncodableFacet.class);
 
         encoded = new Object();
-
-        jsonValueEncoder = new JsonValueEncoder();
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void whenAdapterIsNull() throws Exception {
-        jsonValueEncoder.asObject(null);
+        JsonValueEncoder.asObject(null);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void whenObjectAdapterIsNotSpecialCaseAndSpecIsNotEncodable() throws Exception {
         allowingObjectSpecCorrespondingClassIs(String.class);
         allowingObjectSpecHas(EncodableFacet.class, null);
-        jsonValueEncoder.asObject(objectAdapter);
+        JsonValueEncoder.asObject(objectAdapter);
     }
 
     @Test
@@ -100,7 +99,7 @@ public class JsonValueEncoderTest_asObject {
                 will(returnValue(true));
             }
         });
-        assertEquals(true, jsonValueEncoder.asObject(objectAdapter));
+        assertEquals(true, JsonValueEncoder.asObject(objectAdapter));
     }
 
     @Test
@@ -123,7 +122,7 @@ public class JsonValueEncoderTest_asObject {
                 will(returnValue(123));
             }
         });
-        assertEquals(123, jsonValueEncoder.asObject(objectAdapter));
+        assertEquals(123, JsonValueEncoder.asObject(objectAdapter));
     }
 
     @Test
@@ -146,7 +145,7 @@ public class JsonValueEncoderTest_asObject {
                 will(returnValue(123456789L));
             }
         });
-        assertEquals(123456789L, jsonValueEncoder.asObject(objectAdapter));
+        assertEquals(123456789L, JsonValueEncoder.asObject(objectAdapter));
     }
 
     @Test
@@ -169,7 +168,7 @@ public class JsonValueEncoderTest_asObject {
                 will(returnValue(12345.6789));
             }
         });
-        assertEquals(12345.6789, jsonValueEncoder.asObject(objectAdapter));
+        assertEquals(12345.6789, JsonValueEncoder.asObject(objectAdapter));
     }
 
     @Test
@@ -185,7 +184,7 @@ public class JsonValueEncoderTest_asObject {
                 will(returnValue(value));
             }
         });
-        assertEquals(value, jsonValueEncoder.asObject(objectAdapter));
+        assertEquals(value, JsonValueEncoder.asObject(objectAdapter));
     }
 
     @Test
@@ -197,11 +196,11 @@ public class JsonValueEncoderTest_asObject {
         context.checking(new Expectations() {
 
             {
-                one(objectAdapter).getObject();
+                oneOf(objectAdapter).getObject();
                 will(returnValue(value));
             }
         });
-        assertEquals(value, jsonValueEncoder.asObject(objectAdapter));
+        assertEquals(value, JsonValueEncoder.asObject(objectAdapter));
     }
 
     @Test
@@ -214,7 +213,7 @@ public class JsonValueEncoderTest_asObject {
                 will(returnValue("encodedString"));
             }
         });
-        assertSame("encodedString", jsonValueEncoder.asObject(objectAdapter));
+        assertSame("encodedString", JsonValueEncoder.asObject(objectAdapter));
     }
 
     private void allowingObjectSpecCorrespondingClassIs(final Class<?> result) {
@@ -224,6 +223,12 @@ public class JsonValueEncoderTest_asObject {
                 will(returnValue(result));
             }
         });
+        context.checking(new Expectations() {
+            {
+                allowing(objectSpec).getSpecId();
+                will(returnValue(new ObjectSpecId(result.getName())));
+            }
+        });
     }
 
     private <T extends Facet> void allowingObjectSpecHas(final Class<T> facetClass, final T encodableFacet) {

http://git-wip-us.apache.org/repos/asf/isis/blob/4ff4f713/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainResourceHelper.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainResourceHelper.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainResourceHelper.java
index 0e0450d..d965aea 100644
--- a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainResourceHelper.java
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainResourceHelper.java
@@ -310,7 +310,7 @@ public final class DomainResourceHelper {
 
         // value (encodable)
         if (objectSpec.isEncodeable()) {
-            return new JsonValueEncoder().asAdapter(objectSpec, argRepr);
+            return JsonValueEncoder.asAdapter(objectSpec, argRepr);
         }
 
         final JsonRepresentation argValueRepr = argRepr.getRepresentation("value");

http://git-wip-us.apache.org/repos/asf/isis/blob/4ff4f713/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java b/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java
index 6c21f23..3118e68 100644
--- a/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java
+++ b/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java
@@ -61,7 +61,6 @@ public class Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO {
         client = new RestfulClient(webServer.getBase());
     }
 
-    @Ignore("TODO")
     @Test
     public void thenMembers() throws Exception {
 

http://git-wip-us.apache.org/repos/asf/isis/blob/4ff4f713/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java
----------------------------------------------------------------------
diff --git a/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java b/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java
index e86e457..8f5a23d 100644
--- a/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java
+++ b/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java
@@ -19,6 +19,9 @@
 
 package org.apache.isis.core.tck.fixture.scalars;
 
+import org.joda.time.LocalDate;
+import org.joda.time.LocalDateTime;
+
 import org.apache.isis.applib.fixtures.AbstractFixture;
 import org.apache.isis.core.tck.dom.scalars.JodaValuedEntity;
 import org.apache.isis.core.tck.dom.scalars.JodaValuedEntityRepository;
@@ -35,7 +38,10 @@ public class JodaValuedEntityFixture extends AbstractFixture {
     }
 
     private JodaValuedEntity createEntity() {
-        return jodaValuesEntityRepository.newEntity();
+        final JodaValuedEntity jve = jodaValuesEntityRepository.newEntity();
+        jve.setLocalDateProperty(new LocalDate(2008,3,21));
+        jve.setLocalDateTimeProperty(new LocalDateTime(2009, 4, 29, 13, 45, 22, 213));
+        return jve;
     }
 
     private JodaValuedEntityRepository jodaValuesEntityRepository;


[2/2] git commit: ISIS-233: refactored JsonValueEncoder, support for joda date props/values

Posted by da...@apache.org.
ISIS-233: refactored JsonValueEncoder, support for joda date props/values


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/9b651e2e
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/9b651e2e
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/9b651e2e

Branch: refs/heads/master
Commit: 9b651e2e5f4962c503a410a6afcff4cfcbe62c64
Parents: 4ff4f71
Author: Dan Haywood <da...@apache.org>
Authored: Tue Apr 30 07:05:03 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Tue Apr 30 07:05:03 2013 +0100

----------------------------------------------------------------------
 .../restfulobjects/applib/JsonRepresentation.java  |   69 +++++++++++++--
 .../domainobjects/ScalarValueRepresentation.java   |    1 +
 .../rendering/domainobjects/JsonValueEncoder.java  |   66 +++++++++++++--
 .../RestfulObjectsApplicationExceptionMapper.java  |    2 +-
 .../tck/ide/eclipse/launch/viewer-json-tck.launch  |   19 ----
 .../ide/eclipse/launch/viewer-restful-tck.launch   |   19 ++++
 ...hJodaProperties_thenRepresentation_ok_TODO.java |   35 +++++---
 .../fixture/scalars/JodaValuedEntityFixture.java   |    2 +-
 8 files changed, 168 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/9b651e2e/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java
index d4f7bb7..9ddd6fe 100644
--- a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java
+++ b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/JsonRepresentation.java
@@ -24,6 +24,7 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -38,6 +39,8 @@ import org.codehaus.jackson.node.JsonNodeFactory;
 import org.codehaus.jackson.node.NullNode;
 import org.codehaus.jackson.node.ObjectNode;
 import org.codehaus.jackson.node.POJONode;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
@@ -312,35 +315,87 @@ public class JsonRepresentation {
 
 
     // ///////////////////////////////////////////////////////////////////////
-    // isBoolean, getBoolean, asBoolean
+    // getDate, asDate
     // ///////////////////////////////////////////////////////////////////////
 
+    public final static DateTimeFormatter yyyyMMdd = DateTimeFormat.forPattern("yyyy-MM-dd");
+
+    public java.util.Date getDate(final String path) {
+        return getDate(path, getNode(path));
+    }
+
+    public java.util.Date asDate() {
+        return getDate(null, asJsonNode());
+    }
+
+    private java.util.Date getDate(final String path, final JsonNode node) {
+        if (representsNull(node)) {
+            return null;
+        }
+        checkValue(path, node, "a date");
+        if (!node.isTextual()) {
+            throw new IllegalArgumentException(formatExMsg(path, "is not a date"));
+        }
+        final String textValue = node.getTextValue();
+        return new java.util.Date(yyyyMMdd.parseMillis(textValue));
+    }
+
+    // ///////////////////////////////////////////////////////////////////////
+    // getDate, asDate
+    // ///////////////////////////////////////////////////////////////////////
+
+    public final static DateTimeFormatter yyyyMMddTHHmmssZ = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ");
+
+    public java.util.Date getDateTime(final String path) {
+        return getDateTime(path, getNode(path));
+    }
+
+    public java.util.Date asDateTime() {
+        return getDateTime(null, asJsonNode());
+    }
+
+    private java.util.Date getDateTime(final String path, final JsonNode node) {
+        if (representsNull(node)) {
+            return null;
+        }
+        checkValue(path, node, "a date-time");
+        if (!node.isTextual()) {
+            throw new IllegalArgumentException(formatExMsg(path, "is not a date-time"));
+        }
+        final String textValue = node.getTextValue();
+        return new java.util.Date(yyyyMMddTHHmmssZ.parseMillis(textValue));
+    }
+
+    // ///////////////////////////////////////////////////////////////////////
+    // isBoolean, getBoolean, asBoolean
+    // ///////////////////////////////////////////////////////////////////////
+    
     public boolean isBoolean(final String path) {
         return isBoolean(getNode(path));
     }
-
+    
     public boolean isBoolean() {
         return isBoolean(asJsonNode());
     }
-
+    
     private boolean isBoolean(final JsonNode node) {
         return !representsNull(node) && node.isValueNode() && node.isBoolean();
     }
-
+    
     /**
      * Use {@link #isBoolean(String)} to check first, if required.
      */
     public Boolean getBoolean(final String path) {
         return getBoolean(path, getNode(path));
     }
-
+    
     /**
      * Use {@link #isBoolean()} to check first, if required.
      */
     public Boolean asBoolean() {
         return getBoolean(null, asJsonNode());
     }
-
+    
     private Boolean getBoolean(final String path, final JsonNode node) {
         if (representsNull(node)) {
             return null;
@@ -351,7 +406,7 @@ public class JsonRepresentation {
         }
         return node.getBooleanValue();
     }
-
+    
     // ///////////////////////////////////////////////////////////////////////
     // getByte, asByte
     // ///////////////////////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/isis/blob/9b651e2e/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/domainobjects/ScalarValueRepresentation.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/domainobjects/ScalarValueRepresentation.java b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/domainobjects/ScalarValueRepresentation.java
index 5b88ff1..fec5c0b 100644
--- a/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/domainobjects/ScalarValueRepresentation.java
+++ b/component/viewer/restfulobjects/applib/src/main/java/org/apache/isis/viewer/restfulobjects/applib/domainobjects/ScalarValueRepresentation.java
@@ -31,4 +31,5 @@ public class ScalarValueRepresentation extends DomainRepresentation {
         return getRepresentation("value");
     }
 
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/9b651e2e/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
index 3655e4e..c7c85e0 100644
--- a/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
+++ b/component/viewer/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
@@ -21,6 +21,7 @@ package org.apache.isis.viewer.restfulobjects.rendering.domainobjects;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
@@ -30,6 +31,10 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 import org.codehaus.jackson.node.NullNode;
+import org.joda.time.LocalDate;
+import org.joda.time.LocalDateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
 
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
@@ -54,8 +59,8 @@ public final class JsonValueEncoder {
 
     public static abstract class JsonValueConverter {
 
-        private final String format;
-        private final String xIsisFormat;
+        protected final String format;
+        protected final String xIsisFormat;
         private final Class<?>[] classes;
 
         public JsonValueConverter(String format, String xIsisFormat, Class<?>... classes) {
@@ -84,10 +89,6 @@ public final class JsonValueEncoder {
         public Object asObject(ObjectAdapter objectAdapter) {
             return objectAdapter.getObject();
         }
-        
-        
-
-
     }
     
     private static Map<ObjectSpecId, JsonValueConverter> converterBySpec = Maps.newLinkedHashMap();
@@ -287,8 +288,61 @@ public final class JsonValueEncoder {
                 return null;
             }
         });
+
+        putConverter(new JsonValueConverter("date", "jodalocaldate", LocalDate.class){
+
+            final DateTimeFormatter yyyyMMdd = JsonRepresentation.yyyyMMdd;
+
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isString()) {
+                    final String dateStr = repr.asString();
+                    try {
+                        final Date parsedDate = yyyyMMdd.parseDateTime(dateStr).toDate();
+                        return adapterFor(parsedDate);
+                    } catch (IllegalArgumentException ex) {
+                        // fall through
+                    }
+                }
+                return null;
+            }
+
+            @Override
+            public void appendValueAndFormat(ObjectAdapter objectAdapter, JsonRepresentation repr) {
+                final LocalDate date = (LocalDate) unwrap(objectAdapter);
+                final String dateStr = yyyyMMdd.print(date.toDateTimeAtStartOfDay());
+                append(repr, dateStr, format, xIsisFormat);
+            }
+        });
+
+        putConverter(new JsonValueConverter("date-time", "jodalocaldatetime", LocalDateTime.class){
+            final DateTimeFormatter yyyyMMddHHmmss = JsonRepresentation.yyyyMMddTHHmmssZ;
+            @Override
+            public ObjectAdapter asAdapter(JsonRepresentation repr) {
+                if (repr.isString()) {
+                    final String dateStr = repr.asString();
+                    try {
+                        final Date parsedDate = yyyyMMddHHmmss.parseDateTime(dateStr).toDate();
+                        return adapterFor(parsedDate);
+                    } catch (IllegalArgumentException ex) {
+                        // fall through
+                    }
+                }
+                return null;
+            }
+    
+            @Override
+            public void appendValueAndFormat(ObjectAdapter objectAdapter, JsonRepresentation repr) {
+                final LocalDateTime date = (LocalDateTime) unwrap(objectAdapter);
+                final String dateStr = yyyyMMddHHmmss.print(date.toDateTime());
+                append(repr, dateStr, format, xIsisFormat);
+            }
+        });
+        
     }
 
+
+
     public static ObjectAdapter asAdapter(final ObjectSpecification objectSpec, final JsonRepresentation argRepr) {
         if (objectSpec == null) {
             String reason = "ObjectSpec is null, cannot validate";

http://git-wip-us.apache.org/repos/asf/isis/blob/9b651e2e/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
index 5178601..409ecdc 100644
--- a/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
+++ b/component/viewer/restfulobjects/server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
@@ -35,7 +35,7 @@ import org.apache.isis.viewer.restfulobjects.applib.util.JsonMapper;
 
 import com.google.common.collect.Lists;
 
-@Path("/") // FIXME: workaround for TomEE
+//@Path("/") // FIXME: workaround for TomEE ... but breaks the RestEasy TCK tests so commented out:-(
 @Provider
 public class RestfulObjectsApplicationExceptionMapper implements ExceptionMapper<RestfulObjectsApplicationException> {
 

http://git-wip-us.apache.org/repos/asf/isis/blob/9b651e2e/component/viewer/restfulobjects/tck/ide/eclipse/launch/viewer-json-tck.launch
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/tck/ide/eclipse/launch/viewer-json-tck.launch b/component/viewer/restfulobjects/tck/ide/eclipse/launch/viewer-json-tck.launch
deleted file mode 100644
index 53bd401..0000000
--- a/component/viewer/restfulobjects/tck/ide/eclipse/launch/viewer-json-tck.launch
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.apache.isis.runtimes.dflt.webserver/src/main/java/org/apache/isis/WebServer.java"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="1"/>
-</listAttribute>
-<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
-<mapEntry key="[debug]" value="org.eclipse.jdt.launching.localJavaApplication"/>
-<mapEntry key="[run]" value="org.eclipse.jdt.launching.localJavaApplication"/>
-</mapAttribute>
-<stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.isis.WebServer"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="isis-viewer-restfulobjects-tck"/>
-<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
-</launchConfiguration>

http://git-wip-us.apache.org/repos/asf/isis/blob/9b651e2e/component/viewer/restfulobjects/tck/ide/eclipse/launch/viewer-restful-tck.launch
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/tck/ide/eclipse/launch/viewer-restful-tck.launch b/component/viewer/restfulobjects/tck/ide/eclipse/launch/viewer-restful-tck.launch
new file mode 100644
index 0000000..53bd401
--- /dev/null
+++ b/component/viewer/restfulobjects/tck/ide/eclipse/launch/viewer-restful-tck.launch
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.apache.isis.runtimes.dflt.webserver/src/main/java/org/apache/isis/WebServer.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[debug]" value="org.eclipse.jdt.launching.localJavaApplication"/>
+<mapEntry key="[run]" value="org.eclipse.jdt.launching.localJavaApplication"/>
+</mapAttribute>
+<stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
+<booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/>
+<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.isis.WebServer"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="isis-viewer-restfulobjects-tck"/>
+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
+</launchConfiguration>

http://git-wip-us.apache.org/repos/asf/isis/blob/9b651e2e/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java
----------------------------------------------------------------------
diff --git a/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java b/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java
index 3118e68..77663f7 100644
--- a/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java
+++ b/component/viewer/restfulobjects/tck/src/test/java/org/apache/isis/viewer/restfulobjects/tck/domainobject/oid/Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO.java
@@ -21,13 +21,17 @@ package org.apache.isis.viewer.restfulobjects.tck.domainobject.oid;
 import static org.apache.isis.core.commons.matchers.IsisMatchers.matches;
 import static org.apache.isis.viewer.restfulobjects.tck.RestfulMatchers.assertThat;
 import static org.apache.isis.viewer.restfulobjects.tck.RestfulMatchers.isLink;
+import static org.hamcrest.CoreMatchers.*;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertThat;
 
+import java.util.Date;
+
 import org.joda.time.LocalDate;
 import org.joda.time.LocalDateTime;
+import org.joda.time.format.DateTimeFormat;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Rule;
@@ -35,6 +39,7 @@ import org.junit.Test;
 
 import org.apache.isis.core.commons.matchers.IsisMatchers;
 import org.apache.isis.core.webserver.WebServer;
+import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.LinkRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
@@ -74,23 +79,23 @@ public class Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO {
         
         property = domainObjectRepr.getProperty("localDateProperty");
         assertThat(property.getMemberType(), is("property"));
-        //assertThat(property.getFormat(), is(nullValue())); // should be?
-        //assertThat(property.getXIsisFormat(), is("boolean"));  // should be?
+        assertThat(property.getFormat(), is("date"));
+        assertThat(property.getXIsisFormat(), is("jodalocaldate"));
         scalarRepr = property.getRepresentation("value").as(ScalarValueRepresentation.class);
-        //assertThat(scalarRepr.isLocalDate(), is(true));
-        //LocalDate localDateValue = scalarRepr.asLocalDate(); // should be?
-        //assertThat(localDateValue, is(true));
+        assertThat(scalarRepr.isString(), is(true));
+        java.util.Date dateValue = scalarRepr.asDate();
+        assertThat(dateValue, is(asDate("2008-03-21")));
         
         property = domainObjectRepr.getProperty("localDateTimeProperty");
         assertThat(property.getMemberType(), is("property"));
-        //assertThat(property.getFormat(), is(nullValue())); // should be?
-        //assertThat(property.getXIsisFormat(), is("byte")); // should be?
+        assertThat(property.getFormat(), is("date-time"));
+        assertThat(property.getXIsisFormat(), is("jodalocaldatetime"));
         scalarRepr = property.getRepresentation("value").as(ScalarValueRepresentation.class);
-        //assertThat(scalarRepr.isDateTime(), is(true));
-        //LocalDateTime localDateTimeValue = scalarRepr.asLocalDateTime(); // should be?
-        //assertThat(localDateTimeValue, is((byte)123));
+        assertThat(scalarRepr.isString(), is(true));
+        java.util.Date dateTimeValue = scalarRepr.asDateTime();
+        assertThat(dateTimeValue, is(not(nullValue())));
+        assertThat(scalarRepr.asString(), IsisMatchers.startsWith("2009-04-29T13:45:22+0100"));
 
-        
         // and then member types have links to details (selected ones inspected only)
         property = domainObjectRepr.getProperty("localDateProperty");
         assertThat(property.getLinkWithRel(Rel.DETAILS), 
@@ -107,4 +112,12 @@ public class Get_givenEntityWithJodaProperties_thenRepresentation_ok_TODO {
                     .type(RepresentationType.OBJECT_PROPERTY.getMediaType()));
     }
 
+    private static Date asDate(final String text) {
+        return new java.util.Date(JsonRepresentation.yyyyMMdd.parseDateTime(text).getMillis());
+    }
+
+    private static Date asDateTime(final String text) {
+        return new java.util.Date(JsonRepresentation.yyyyMMddTHHmmssZ.parseDateTime(text).getMillis());
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/9b651e2e/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java
----------------------------------------------------------------------
diff --git a/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java b/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java
index 8f5a23d..720b847 100644
--- a/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java
+++ b/core/tck/tck-fixture/src/main/java/org/apache/isis/core/tck/fixture/scalars/JodaValuedEntityFixture.java
@@ -40,7 +40,7 @@ public class JodaValuedEntityFixture extends AbstractFixture {
     private JodaValuedEntity createEntity() {
         final JodaValuedEntity jve = jodaValuesEntityRepository.newEntity();
         jve.setLocalDateProperty(new LocalDate(2008,3,21));
-        jve.setLocalDateTimeProperty(new LocalDateTime(2009, 4, 29, 13, 45, 22, 213));
+        jve.setLocalDateTimeProperty(new LocalDateTime(2009, 4, 29, 13, 45, 22));
         return jve;
     }