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 2017/11/28 13:47:44 UTC

[isis] 02/02: ISIS-1768: supports either xml or json formats, improved representations, and simplified implementation

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 43f84745b3c3890259c413e64c2eca511b8dac9d
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Nov 28 13:15:36 2017 +0000

    ISIS-1768: supports either xml or json formats, improved representations, and simplified implementation
---
 .../server/ExceptionMapperAbstract.java            |  65 -----------
 .../server/ExceptionPojoWithDetail.java            |  64 -----------
 .../server/ObjectNotFoundExceptionMapper.java      |  71 ------------
 .../server/RestfulObjectsApplication.java          |   9 +-
 .../RestfulObjectsApplicationExceptionMapper.java  | 101 -----------------
 .../server/mappers/ExceptionMapperAbstract.java    | 120 +++++++++++++++++++++
 .../mappers/ExceptionMapperForObjectNotFound.java  |  35 ++++++
 ...xceptionMapperForRestfulObjectsApplication.java |  36 +++++++
 .../ExceptionMapperForRuntimeException.java}       |  33 ++----
 .../entity/ExceptionDetail.java}                   |  72 ++++++-------
 .../server/{ => mappers/entity}/ExceptionPojo.java |  51 ++++-----
 .../server/mappers/entity/package-info.java        |  28 +++++
 .../resources/DomainObjectResourceServerside.java  |  12 +--
 ...stfulObjectsApplicationExceptionMapperTest.java |  29 ++---
 .../java/domainapp/dom/impl/HelloWorldObjects.java |  27 +++++
 15 files changed, 341 insertions(+), 412 deletions(-)

diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionMapperAbstract.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionMapperAbstract.java
deleted file mode 100644
index ad38101..0000000
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionMapperAbstract.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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 org.apache.isis.viewer.restfulobjects.server;
-
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.apache.isis.viewer.restfulobjects.applib.RestfulMediaType;
-
-public abstract class ExceptionMapperAbstract<T extends Throwable> implements ExceptionMapper<T> {
-
-    @Context
-    protected HttpHeaders httpHeaders;
-
-    protected void setContentTypeOn(final ResponseBuilder builder) {
-        final boolean xml = isXmlButNotHtml();
-        if(!xml) {
-            builder.type(RestfulMediaType.APPLICATION_JSON_ERROR);
-        } else {
-            builder.type(RestfulMediaType.APPLICATION_XML_ERROR);
-        }
-    }
-
-    protected boolean isHtml() {
-        for (final MediaType acceptableMediaType : httpHeaders.getAcceptableMediaTypes()) {
-            if(acceptableMediaType.getType().equals("text") && acceptableMediaType.getSubtype().equals("html")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    protected boolean isXmlButNotHtml() {
-        if (isHtml()) {
-            return false;
-        }
-        for (final MediaType acceptableMediaType : httpHeaders.getAcceptableMediaTypes()) {
-            if(acceptableMediaType.getSubtype().equals("xml")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-
-}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojoWithDetail.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojoWithDetail.java
deleted file mode 100644
index 18af126..0000000
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojoWithDetail.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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 org.apache.isis.viewer.restfulobjects.server;
-
-import java.util.List;
-
-import com.google.common.collect.Lists;
-
-class ExceptionPojoWithDetail extends ExceptionPojo {
-
-    private static String format(final StackTraceElement stackTraceElement) {
-        return stackTraceElement.toString();
-    }
-
-    private final String className;
-
-    private final List<String> stackTrace = Lists.newArrayList();
-    private ExceptionPojoWithDetail causedBy;
-
-    public ExceptionPojoWithDetail(final Throwable ex) {
-        super(ex);
-        this.className = ex.getClass().getName();
-        final StackTraceElement[] stackTraceElements = ex.getStackTrace();
-        for (final StackTraceElement stackTraceElement : stackTraceElements) {
-            this.stackTrace.add(format(stackTraceElement));
-        }
-        final Throwable cause = ex.getCause();
-        if (cause != null && cause != ex) {
-            this.causedBy = new ExceptionPojoWithDetail(cause);
-        }
-    }
-
-    @SuppressWarnings("unused")
-    public String getClassName() {
-        return className;
-    }
-
-    @SuppressWarnings("unused")
-    public List<String> getStackTrace() {
-        return stackTrace;
-    }
-
-    @SuppressWarnings("unused")
-    public ExceptionPojoWithDetail getCausedBy() {
-        return causedBy;
-    }
-
-}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ObjectNotFoundExceptionMapper.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ObjectNotFoundExceptionMapper.java
deleted file mode 100644
index 4b1e154..0000000
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ObjectNotFoundExceptionMapper.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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 org.apache.isis.viewer.restfulobjects.server;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
-import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse;
-import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse.HttpStatusCode;
-import org.apache.isis.viewer.restfulobjects.applib.util.JsonMapper;
-
-@Provider
-public class ObjectNotFoundExceptionMapper extends ExceptionMapperAbstract<ObjectNotFoundException> {
-
-    @Override
-    public Response toResponse(final ObjectNotFoundException ex) {
-
-
-        final HttpStatusCode statusCode = HttpStatusCode.NOT_FOUND;
-        final ResponseBuilder builder =
-                Response.status(statusCode.getJaxrsStatusType());
-
-        final String message = ex.getMessage();
-        if (message != null) {
-            builder.header(RestfulResponse.Header.WARNING.getName(), RestfulResponse.Header.WARNING.render(message));
-        }
-
-        setContentTypeOn(builder);
-
-        String body = toBody(ex);
-
-        if(body != null) {
-            builder.entity(body);
-        }
-
-        return builder.build();
-    }
-
-    protected String toBody(final ObjectNotFoundException ex) {
-        final boolean xml = isXmlButNotHtml();
-        if (!xml) {
-            String body;
-            try {
-                body = JsonMapper.instance().write(new ExceptionPojo(ex));
-            } catch (final Exception e) {
-                // fallback
-                body = "{ \"message\": \"" + ex.getMessage() + "\" }";
-            }
-            return body;
-        }
-        return null;
-    }
-}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java
index fac1c27..7c33c52 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplication.java
@@ -20,6 +20,9 @@ package org.apache.isis.viewer.restfulobjects.server;
 
 import org.apache.isis.viewer.restfulobjects.rendering.service.acceptheader.AcceptHeaderServiceForRest;
 import org.apache.isis.viewer.restfulobjects.server.conneg.RestfulObjectsJaxbWriterForXml;
+import org.apache.isis.viewer.restfulobjects.server.mappers.ExceptionMapperForObjectNotFound;
+import org.apache.isis.viewer.restfulobjects.server.mappers.ExceptionMapperForRestfulObjectsApplication;
+import org.apache.isis.viewer.restfulobjects.server.mappers.ExceptionMapperForRuntimeException;
 import org.apache.isis.viewer.restfulobjects.server.resources.DomainObjectResourceServerside;
 import org.apache.isis.viewer.restfulobjects.server.resources.DomainServiceResourceServerside;
 import org.apache.isis.viewer.restfulobjects.server.resources.DomainTypeResourceServerside;
@@ -47,9 +50,9 @@ public class RestfulObjectsApplication extends AbstractJaxRsApplication {
         final RestfulObjectsJaxbWriterForXml roWriter = new RestfulObjectsJaxbWriterForXml();
         addSingleton(roWriter);
 
-        addSingleton(new RestfulObjectsApplicationExceptionMapper());
-        addSingleton(new RuntimeExceptionMapper());
-        addSingleton(new ObjectNotFoundExceptionMapper());
+        addSingleton(new ExceptionMapperForRestfulObjectsApplication());
+        addSingleton(new ExceptionMapperForRuntimeException());
+        addSingleton(new ExceptionMapperForObjectNotFound());
 
         addSingleton(new AcceptHeaderServiceForRest.RequestFilter());
         addSingleton(new AcceptHeaderServiceForRest.ResponseFilter());
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
deleted file mode 100644
index 210f8aa..0000000
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapper.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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 org.apache.isis.viewer.restfulobjects.server;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.isis.core.commons.exceptions.ExceptionUtils;
-import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
-import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse;
-import org.apache.isis.viewer.restfulobjects.applib.util.JsonMapper;
-import org.apache.isis.viewer.restfulobjects.rendering.RestfulObjectsApplicationException;
-
-//@Path("/") // FIXME: workaround for TomEE ... but breaks the RestEasy TCK tests so commented out:-(
-@Provider
-public class RestfulObjectsApplicationExceptionMapper extends ExceptionMapperAbstract<RestfulObjectsApplicationException> {
-
-    @Override
-    public Response toResponse(final RestfulObjectsApplicationException ex) {
-        final ResponseBuilder builder = Response.status(ex.getHttpStatusCode().getJaxrsStatusType());
-
-        final String message = ex.getMessage();
-        if (message != null) {
-            builder.header(RestfulResponse.Header.WARNING.getName(), RestfulResponse.Header.WARNING.render(message));
-        }
-
-        setContentTypeOn(builder);
-
-        final boolean xml = isXmlButNotHtml();
-        String body = null;
-        if(!xml) {
-            final JsonRepresentation bodyRepr = ex.getBody();
-            if (bodyRepr != null) {
-                body = bodyRepr.toString();
-            }
-        }
-        if (body == null) {
-            body = toBody(ex);
-        }
-
-        if(body != null) {
-            builder.entity(body);
-        }
-
-        return builder.build();
-    }
-
-    protected String toBody(final RestfulObjectsApplicationException ex) {
-        if(ex.getHttpStatusCode() == RestfulResponse.HttpStatusCode.NOT_FOUND) {
-            final ExceptionPojo exceptionPojo = new ExceptionPojo(ex);
-            try {
-                return JsonMapper.instance().write(exceptionPojo);
-            } catch (final Exception e) {
-                // fallback
-                return null;
-            }
-        }
-
-        final boolean xml = isXmlButNotHtml();
-        final ExceptionPojoWithDetail exceptionPojo = new ExceptionPojoWithDetail(ex);
-        if (!xml) {
-            try {
-                return JsonMapper.instance().write(exceptionPojo);
-            } catch (final Exception e) {
-                // fallback
-                return "{ \"exception\": \"" + ExceptionUtils.getFullStackTrace(ex) + "\" }";
-            }
-        } else {
-            final StringBuilder buf = new StringBuilder();
-            buf.append("<exception>\n");
-            buf.append("  <httpStatusCode>").append(exceptionPojo.getHttpStatusCode())
-                    .append("</httpStatusCode>/n");
-            buf.append("  <message>").append(exceptionPojo.getMessage()).append("</message>/n");
-            buf.append("  <stackTrace>/n");
-            for (String line : exceptionPojo.getStackTrace()) {
-                buf.append("    <stackTraceElement>").append(line).append("    </stackTraceElement>/n");
-            }
-            buf.append("  </stackTrace>/n");
-            buf.append("</exception>");
-
-            return buf.toString();
-        }
-    }
-}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperAbstract.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperAbstract.java
new file mode 100644
index 0000000..0977835
--- /dev/null
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperAbstract.java
@@ -0,0 +1,120 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.isis.viewer.restfulobjects.server.mappers;
+
+import java.util.List;
+
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Throwables;
+import com.google.common.collect.FluentIterable;
+
+import org.jboss.resteasy.spi.Failure;
+
+import org.apache.isis.applib.RecoverableException;
+import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
+import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse;
+import org.apache.isis.viewer.restfulobjects.rendering.HasHttpStatusCode;
+import org.apache.isis.viewer.restfulobjects.server.mappers.entity.ExceptionDetail;
+import org.apache.isis.viewer.restfulobjects.server.mappers.entity.ExceptionPojo;
+import org.apache.isis.viewer.restfulobjects.server.resources.serialization.SerializationStrategy;
+
+public abstract class ExceptionMapperAbstract<T extends Throwable> implements ExceptionMapper<T> {
+
+    @Context
+    protected HttpHeaders httpHeaders;
+
+    Response buildResponse(final T ex) {
+        final RestfulResponse.HttpStatusCode httpStatusCode = determineStatusCode(ex);
+        final String message = messageFor(ex);
+
+        final ExceptionPojo exceptionPojo =
+                new ExceptionPojo(
+                        httpStatusCode.getStatusCode(), message,
+                        detailIfRequired(httpStatusCode, ex)
+                );
+
+        return buildResponse(httpStatusCode, exceptionPojo);
+    }
+
+    private RestfulResponse.HttpStatusCode determineStatusCode(final T ex) {
+        final List<Throwable> chain = Throwables.getCausalChain(ex);
+
+        RestfulResponse.HttpStatusCode statusCode;
+        if(ex instanceof Failure) {
+            Failure failure = (Failure) ex;
+            statusCode = RestfulResponse.HttpStatusCode.statusFor(failure.getErrorCode());
+        } else if(!FluentIterable.from(chain).filter(RecoverableException.class).isEmpty()) {
+            statusCode = RestfulResponse.HttpStatusCode.OK;
+        } else if(ex instanceof HasHttpStatusCode) {
+            HasHttpStatusCode hasHttpStatusCode = (HasHttpStatusCode) ex;
+            statusCode = hasHttpStatusCode.getHttpStatusCode();
+        } else {
+            statusCode = RestfulResponse.HttpStatusCode.INTERNAL_SERVER_ERROR;
+        }
+        return statusCode;
+    }
+
+    private static String messageFor(final Throwable ex) {
+        final List<Throwable> chain = Throwables.getCausalChain(ex);
+        final Optional<RecoverableException> recoverableIfAny =
+                FluentIterable.from(chain).filter(RecoverableException.class).first();
+        return (recoverableIfAny.isPresent() ? recoverableIfAny.get() : ex).getMessage();
+    }
+
+    private ExceptionDetail detailIfRequired(
+            final RestfulResponse.HttpStatusCode httpStatusCode,
+            final Throwable ex) {
+        return httpStatusCode == RestfulResponse.HttpStatusCode.NOT_FOUND ||
+                httpStatusCode == RestfulResponse.HttpStatusCode.OK
+                ? null
+                : new ExceptionDetail(ex);
+    }
+
+    private Response buildResponse(
+            final RestfulResponse.HttpStatusCode httpStatusCode,
+            final ExceptionPojo exceptionPojo) {
+        final ResponseBuilder builder = Response.status(httpStatusCode.getJaxrsStatusType());
+
+        final List<MediaType> acceptableMediaTypes = httpHeaders.getAcceptableMediaTypes();
+        final SerializationStrategy serializationStrategy =
+                acceptableMediaTypes.contains(MediaType.APPLICATION_XML_TYPE) ||
+                        acceptableMediaTypes.contains(RepresentationType.OBJECT_LAYOUT.getXmlMediaType())
+                        ? SerializationStrategy.XML
+                        : SerializationStrategy.JSON;
+
+        final String message = exceptionPojo.getMessage();
+        if (message != null) {
+            builder.header(RestfulResponse.Header.WARNING.getName(), RestfulResponse.Header.WARNING.render(message));
+        }
+
+        builder.type(serializationStrategy.type(RepresentationType.ERROR));
+        builder.entity(serializationStrategy.entity(exceptionPojo));
+
+        return builder.build();
+    }
+
+
+}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForObjectNotFound.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForObjectNotFound.java
new file mode 100644
index 0000000..998d05e
--- /dev/null
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForObjectNotFound.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.isis.viewer.restfulobjects.server.mappers;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
+
+@Provider
+public class ExceptionMapperForObjectNotFound extends ExceptionMapperAbstract<ObjectNotFoundException> {
+
+    @Override
+    public Response toResponse(final ObjectNotFoundException ex) {
+
+        return buildResponse(ex);
+    }
+
+}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRestfulObjectsApplication.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRestfulObjectsApplication.java
new file mode 100644
index 0000000..da04ffe
--- /dev/null
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRestfulObjectsApplication.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.isis.viewer.restfulobjects.server.mappers;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.isis.viewer.restfulobjects.rendering.RestfulObjectsApplicationException;
+
+//@Path("/") // FIXME: workaround for TomEE ... but breaks the RestEasy TCK tests so commented out:-(
+@Provider
+public class ExceptionMapperForRestfulObjectsApplication extends ExceptionMapperAbstract<RestfulObjectsApplicationException> {
+
+    @Override
+    public Response toResponse(final RestfulObjectsApplicationException ex) {
+        return buildResponse(ex);
+    }
+
+
+}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRuntimeException.java
similarity index 57%
rename from core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java
rename to core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRuntimeException.java
index bdf3866..2596c65 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionMapper.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/ExceptionMapperForRuntimeException.java
@@ -16,63 +16,42 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.viewer.restfulobjects.server;
+package org.apache.isis.viewer.restfulobjects.server.mappers;
 
 import java.util.List;
 
 import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
 import com.google.common.base.Throwables;
 
-import org.jboss.resteasy.spi.Failure;
-
-import org.apache.isis.core.commons.exceptions.ExceptionUtils;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
 import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
-import org.apache.isis.viewer.restfulobjects.applib.RestfulMediaType;
-import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse.HttpStatusCode;
-import org.apache.isis.viewer.restfulobjects.applib.util.JsonMapper;
 
 @Provider
-public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException> {
+public class ExceptionMapperForRuntimeException extends ExceptionMapperAbstract<RuntimeException> {
 
     @Override
     public Response toResponse(final RuntimeException ex) {
 
+        // since already rendered...
         final IsisTransaction currentTransaction = getIsisSessionFactory().getCurrentSession()
                 .getPersistenceSession().getTransactionManager().getCurrentTransaction();
 
         final Throwable rootCause = Throwables.getRootCause(ex);
         final List<Throwable> causalChain = Throwables.getCausalChain(ex);
         for (Throwable throwable : causalChain) {
-
             if(throwable == rootCause) {
                 currentTransaction.clearAbortCause();
             }
         }
-        HttpStatusCode statusCode = HttpStatusCode.INTERNAL_SERVER_ERROR;
-        if(ex instanceof Failure) {
-            Failure failure = (Failure) ex;
-            statusCode = HttpStatusCode.statusFor(failure.getErrorCode());
-        }
-        final ResponseBuilder builder = Response.status(statusCode.getJaxrsStatusType()).type(RestfulMediaType.APPLICATION_JSON_ERROR).entity(jsonFor(ex));
-        return builder.build();
-    }
 
-    static String jsonFor(final Exception ex) {
-        try {
-            return JsonMapper.instance().write(RuntimeExceptionPojo.create(ex));
-        } catch (final Exception e) {
-            // fallback
-            return "{ \"exception\": \"" + ExceptionUtils.getFullStackTrace(ex) + "\" }";
-        }
+        return buildResponse(ex);
     }
 
-    IsisSessionFactory getIsisSessionFactory() {
+
+    private IsisSessionFactory getIsisSessionFactory() {
         return IsisContext.getSessionFactory();
     }
 
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionPojo.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionDetail.java
similarity index 62%
rename from core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionPojo.java
rename to core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionDetail.java
index f86e4d6..d47e2a3 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/RuntimeExceptionPojo.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionDetail.java
@@ -16,30 +16,52 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.viewer.restfulobjects.server;
+package org.apache.isis.viewer.restfulobjects.server.mappers.entity;
 
 import java.util.List;
+
 import javax.jdo.JDOException;
-import com.google.common.collect.Lists;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
 
-class RuntimeExceptionPojo {
+import com.google.common.collect.Lists;
 
-    public static RuntimeExceptionPojo create(final Exception ex) {
-        return new RuntimeExceptionPojo(ex);
-    }
+@XmlRootElement(
+        name = "exceptionDetail"
+)
+@XmlType(
+        name = "exceptionDetail"
+        , propOrder = {
+            "className",
+            "message",
+            "stackTrace",
+            "causedBy"
+        }
+)
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ExceptionDetail {
 
     private static String format(final StackTraceElement stackTraceElement) {
         return stackTraceElement.toString();
     }
 
-    private final String className;
-    private final String message;
-    private final List<String> stackTrace = Lists.newArrayList();
-    private RuntimeExceptionPojo causedBy;
+    private String className;
+    private String message;
+
+    @XmlElementWrapper()
+    @XmlElement(name="element")
+    private List<String> stackTrace = Lists.newArrayList();
+    private ExceptionDetail causedBy;
 
-    public RuntimeExceptionPojo(final Throwable ex) {
+    public ExceptionDetail() {
+    }
+    public ExceptionDetail(final Throwable ex) {
         this.className = ex.getClass().getName();
-        this.message = messageFor(ex);
+        this.message = ex.getMessage();
         final StackTraceElement[] stackTraceElements = ex.getStackTrace();
         for (final StackTraceElement stackTraceElement : stackTraceElements) {
             this.stackTrace.add(format(stackTraceElement));
@@ -47,7 +69,7 @@ class RuntimeExceptionPojo {
 
         final Throwable cause = causeOf(ex);
         if (cause != null && cause != ex) {
-            this.causedBy = new RuntimeExceptionPojo(cause);
+            this.causedBy = new ExceptionDetail(cause);
         }
     }
 
@@ -62,28 +84,4 @@ class RuntimeExceptionPojo {
         }
     }
 
-    private static String messageFor(final Throwable ex) {
-        final String message = ex.getMessage();
-        return message != null ? message : ex.getClass().getName();
-    }
-
-    @SuppressWarnings("unused")
-    public String getClassName() {
-        return className;
-    }
-
-    @SuppressWarnings("unused")
-    public String getMessage() {
-        return message;
-    }
-
-    @SuppressWarnings("unused")
-    public List<String> getStackTrace() {
-        return stackTrace;
-    }
-
-    @SuppressWarnings("unused")
-    public RuntimeExceptionPojo getCausedBy() {
-        return causedBy;
-    }
 }
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojo.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionPojo.java
similarity index 52%
rename from core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojo.java
rename to core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionPojo.java
index 2e745f0..c0602b2 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ExceptionPojo.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/ExceptionPojo.java
@@ -16,37 +16,40 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.viewer.restfulobjects.server;
-
-import org.apache.isis.viewer.restfulobjects.rendering.HasHttpStatusCode;
-
-class ExceptionPojo {
-
-    static int getHttpStatusCodeIfAny(final Throwable ex) {
-        if (!(ex instanceof HasHttpStatusCode)) {
-            return 0;
-        }
-        final HasHttpStatusCode hasHttpStatusCode = (HasHttpStatusCode) ex;
-        return hasHttpStatusCode.getHttpStatusCode().getStatusCode();
+package org.apache.isis.viewer.restfulobjects.server.mappers.entity;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(
+        name = "exception"
+)
+@XmlType(
+        name = "exception"
+        , propOrder = {
+            "httpStatusCode",
+            "message",
+            "detail",
     }
+)
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ExceptionPojo {
 
+    int httpStatusCode;
+    private String message;
+    private ExceptionDetail detail;
 
-    private final int httpStatusCode;
-    private final String message;
+    public ExceptionPojo() { }
 
-    public ExceptionPojo(final Throwable ex) {
-        this.httpStatusCode = getHttpStatusCodeIfAny(ex);
-        this.message = ex.getMessage();
+    public ExceptionPojo(final int statusCode, final String message, final ExceptionDetail detail) {
+        this.httpStatusCode = statusCode;
+        this.message = message;
+        this.detail = detail;
     }
 
-    @SuppressWarnings("unused")
-    public int getHttpStatusCode() {
-        return httpStatusCode;
-    }
-
-    @SuppressWarnings("unused")
     public String getMessage() {
         return message;
     }
-
 }
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/package-info.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/package-info.java
new file mode 100644
index 0000000..f94ac90
--- /dev/null
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/mappers/entity/package-info.java
@@ -0,0 +1,28 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ */
+
+@javax.xml.bind.annotation.XmlSchema(
+        namespace = "http://isis.apache.org/viewer/restfulobjects/server/mappers/entity",
+        elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
+        xmlns = {
+                @javax.xml.bind.annotation.XmlNs(
+                        namespaceURI = "http://isis.apache.org/viewer/restfulobjects/server/mappers/entity", prefix = "ro")
+}
+)
+package org.apache.isis.viewer.restfulobjects.server.mappers.entity;
\ No newline at end of file
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
index 9de98f4..938dfa5 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
@@ -206,20 +206,18 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
 
         init(RepresentationType.OBJECT_LAYOUT, Where.ANYWHERE, RepresentationService.Intent.NOT_APPLICABLE);
 
-        final SerializationStrategy serializationStrategy;
         final List<MediaType> acceptableMediaTypes = getResourceContext().getAcceptableMediaTypes();
-        if(acceptableMediaTypes.contains(MediaType.APPLICATION_XML_TYPE) || acceptableMediaTypes.contains(RepresentationType.OBJECT_LAYOUT.getXmlMediaType())) {
-            serializationStrategy = SerializationStrategy.XML;
-        } else {
-            serializationStrategy = SerializationStrategy.JSON;
-        }
+        final SerializationStrategy serializationStrategy =
+                acceptableMediaTypes.contains(MediaType.APPLICATION_XML_TYPE) ||
+                acceptableMediaTypes.contains(RepresentationType.OBJECT_LAYOUT.getXmlMediaType())
+                    ? SerializationStrategy.XML
+                    : SerializationStrategy.JSON;
 
         final ObjectSpecification objectSpec = getSpecificationLoader().lookupBySpecId(ObjectSpecId.of(domainType));
         final GridFacet gridFacet = objectSpec.getFacet(GridFacet.class);
         final Response.ResponseBuilder builder;
         if(gridFacet == null) {
             builder = Responses.ofNotFound();
-            return builder.build();
         } else {
             Grid grid = gridFacet.getGrid();
             addLinks(domainType, instanceId, grid);
diff --git a/core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapperTest.java b/core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/mappers/RestfulObjectsApplicationExceptionMapperTest.java
similarity index 82%
rename from core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapperTest.java
rename to core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/mappers/RestfulObjectsApplicationExceptionMapperTest.java
index 5cc00bf..7c5ad83 100644
--- a/core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/RestfulObjectsApplicationExceptionMapperTest.java
+++ b/core/viewer-restfulobjects-server/src/test/java/org/apache/isis/viewer/restfulobjects/server/mappers/RestfulObjectsApplicationExceptionMapperTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.viewer.restfulobjects.server;
+package org.apache.isis.viewer.restfulobjects.server.mappers;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
@@ -39,7 +39,7 @@ import static org.junit.Assert.assertThat;
 
 public class RestfulObjectsApplicationExceptionMapperTest {
 
-    private RestfulObjectsApplicationExceptionMapper exceptionMapper;
+    private ExceptionMapperForRestfulObjectsApplication exceptionMapper;
 
     @Rule
     public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(JUnitRuleMockery2.Mode.INTERFACES_AND_CLASSES);
@@ -49,7 +49,7 @@ public class RestfulObjectsApplicationExceptionMapperTest {
 
     @Before
     public void setUp() throws Exception {
-        exceptionMapper = new RestfulObjectsApplicationExceptionMapper();
+        exceptionMapper = new ExceptionMapperForRestfulObjectsApplication();
         exceptionMapper.httpHeaders = mockHttpHeaders;
     }
 
@@ -71,7 +71,7 @@ public class RestfulObjectsApplicationExceptionMapperTest {
 
         // and then
         final String entity = (String) response.getEntity();
-        assertThat(entity, is(nullValue()));
+        assertThat(entity, is(not(nullValue())));
     }
 
     @Test
@@ -89,7 +89,7 @@ public class RestfulObjectsApplicationExceptionMapperTest {
 
         // and then
         final String entity = (String) response.getEntity();
-        assertThat(entity, is(nullValue()));
+        assertThat(entity, is(not(nullValue())));
     }
 
     @Test
@@ -108,7 +108,7 @@ public class RestfulObjectsApplicationExceptionMapperTest {
 
         // then
         assertThat((String) response.getMetadata().get("Warning").get(0), is("199 RestfulObjects foobar"));
-        assertThat(jsonRepr.getString("message"), is("barfoo"));
+        assertThat(jsonRepr.getString("message"), is("foobar"));
         final JsonRepresentation causedByRepr = jsonRepr.getRepresentation("causedBy");
         assertThat(causedByRepr, is(nullValue()));
     }
@@ -118,9 +118,9 @@ public class RestfulObjectsApplicationExceptionMapperTest {
 
         // given
         context.allowing(mockHttpHeaders);
-        final Exception cause = new Exception("bozfoz");
-        final Exception exception = new Exception("barfoo", cause);
-        final RestfulObjectsApplicationException ex = RestfulObjectsApplicationException.createWithCauseAndMessage(HttpStatusCode.BAD_REQUEST, exception, "foobar");
+        final Exception rootCause = new Exception("bozfoz");
+        final Exception cause = new Exception("barfoo", rootCause);
+        final RestfulObjectsApplicationException ex = RestfulObjectsApplicationException.createWithCauseAndMessage(HttpStatusCode.BAD_REQUEST, cause, "foobar");
 
         // when
         final Response response = exceptionMapper.toResponse(ex);
@@ -130,10 +130,13 @@ public class RestfulObjectsApplicationExceptionMapperTest {
 
         // then
         assertThat((String) response.getMetadata().get("Warning").get(0), is("199 RestfulObjects foobar"));
-        assertThat(jsonRepr.getString("message"), is("barfoo"));
-        final JsonRepresentation causedByRepr = jsonRepr.getRepresentation("causedBy");
-        assertThat(causedByRepr, is(not(nullValue())));
-        assertThat(causedByRepr.getString("message"), is(cause.getMessage()));
+        assertThat(jsonRepr.getString("message"), is("foobar"));
+        final JsonRepresentation detail = jsonRepr.getRepresentation("detail");
+        assertThat(detail, is(not(nullValue())));
+        assertThat(detail.getString("message"), is("foobar"));
+        final JsonRepresentation causedBy = detail.getRepresentation("causedBy");
+        assertThat(causedBy, is(not(nullValue())));
+        assertThat(causedBy.getString("message"), is(cause.getMessage()));
     }
 
 }
diff --git a/example/application/helloworld/src/main/java/domainapp/dom/impl/HelloWorldObjects.java b/example/application/helloworld/src/main/java/domainapp/dom/impl/HelloWorldObjects.java
index 242cf7e..84f89c7 100644
--- a/example/application/helloworld/src/main/java/domainapp/dom/impl/HelloWorldObjects.java
+++ b/example/application/helloworld/src/main/java/domainapp/dom/impl/HelloWorldObjects.java
@@ -22,6 +22,9 @@ import java.util.List;
 
 import org.datanucleus.query.typesafe.TypesafeQuery;
 
+import org.apache.isis.applib.ApplicationException;
+import org.apache.isis.applib.NonRecoverableException;
+import org.apache.isis.applib.RecoverableException;
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.MemberOrder;
@@ -60,6 +63,30 @@ public class HelloWorldObjects {
                 .executeList();
     }
 
+    @Action(semantics = SemanticsOf.SAFE)
+    @MemberOrder(sequence = "2.1")
+    public void throwRuntimeException() {
+        throw new RuntimeException("all gone wrong - a RuntimeException!");
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    @MemberOrder(sequence = "2.2")
+    public void throwRecoverableException() {
+        throw new RecoverableException("all gone wrong - a RecoverableException!");
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    @MemberOrder(sequence = "2.3")
+    public void throwNonRecoverableException() {
+        throw new NonRecoverableException("all gone wrong - a NonRecoverableException!");
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    @MemberOrder(sequence = "2.4")
+    public void throwApplicableException() {
+        throw new ApplicationException("all gone wrong - an ApplicationException!");
+    }
+
     @Action(semantics = SemanticsOf.SAFE, restrictTo = RestrictTo.PROTOTYPING)
     @MemberOrder(sequence = "3")
     public List<HelloWorldObject> listAll() {

-- 
To stop receiving notification emails like this one, please contact
"commits@isis.apache.org" <co...@isis.apache.org>.