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 <[email protected]> Authored: Tue Apr 30 07:05:03 2013 +0100 Committer: Dan Haywood <[email protected]> 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; }
