You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2020/04/06 14:22:11 UTC
[juneau] branch master updated: ignoreRecursions should not depend
on detectRecursions.
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 1a827ef ignoreRecursions should not depend on detectRecursions.
1a827ef is described below
commit 1a827efdcf57a5661db2d350c3536435cbda60e3
Author: JamesBognar <ja...@apache.org>
AuthorDate: Mon Apr 6 10:21:51 2020 -0400
ignoreRecursions should not depend on detectRecursions.
---
.../org/apache/juneau/BeanTraverseBuilder.java | 115 ++++++++++++-
.../org/apache/juneau/BeanTraverseContext.java | 56 +++---
.../apache/juneau/http/SerializedHttpEntity.java | 3 +-
juneau-doc/docs/ReleaseNotes/8.1.4.html | 3 +
.../juneau/rest/client2/RestClientBuilderTest.java | 191 +++++++++++++++------
.../apache/juneau/rest/client2/RestRequest.java | 2 +-
6 files changed, 282 insertions(+), 88 deletions(-)
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseBuilder.java
index 6330c07..03d81f0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseBuilder.java
@@ -54,11 +54,35 @@ public class BeanTraverseBuilder extends BeanContextBuilder {
* <p>
* Specifies that recursions should be checked for during traversal.
*
+ * <p>
+ * Recursions can occur when traversing models that aren't true trees but rather contain loops.
+ * <br>In general, unchecked recursions cause stack-overflow-errors.
+ * <br>These show up as {@link BeanRecursionException BeanRecursionException} with the message <js>"Depth too deep. Stack overflow occurred."</js>.
+ *
* <ul class='notes'>
* <li>
* Checking for recursion can cause a small performance penalty.
* </ul>
*
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * <jc>// Create a serializer that never adds _type to nodes.</jc>
+ * WriterSerializer s = JsonSerializer
+ * .<jsm>create</jsm>()
+ * .detectRecursions(<jk>true</jk>)
+ * .build();
+ *
+ * <jc>// Create a POJO model with a recursive loop.</jc>
+ * <jk>public class</jk> A {
+ * <jk>public</jk> Object <jf>f</jf>;
+ * }
+ * A a = <jk>new</jk> A();
+ * a.<jf>f</jf> = a;
+ *
+ * <jc>// Throws a SerializeException</jc>
+ * String json = s.serialize(a);
+ * </p>
+ *
* <ul class='seealso'>
* <li class='jf'>{@link BeanTraverseContext#BEANTRAVERSE_detectRecursions}
* </ul>
@@ -77,7 +101,36 @@ public class BeanTraverseBuilder extends BeanContextBuilder {
* Configuration property: Automatically detect POJO recursions.
*
* <p>
- * Shortcut for calling <code>detectRecursions(<jk>true</jk>)</code>.
+ * Specifies that recursions should be checked for during traversal.
+ *
+ * <p>
+ * Recursions can occur when traversing models that aren't true trees but rather contain loops.
+ * <br>In general, unchecked recursions cause stack-overflow-errors.
+ * <br>These show up as {@link BeanRecursionException BeanRecursionException} with the message <js>"Depth too deep. Stack overflow occurred."</js>.
+ *
+ * <ul class='notes'>
+ * <li>
+ * Checking for recursion can cause a small performance penalty.
+ * </ul>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * <jc>// Create a serializer that never adds _type to nodes.</jc>
+ * WriterSerializer s = JsonSerializer
+ * .<jsm>create</jsm>()
+ * .detectRecursions()
+ * .build();
+ *
+ * <jc>// Create a POJO model with a recursive loop.</jc>
+ * <jk>public class</jk> A {
+ * <jk>public</jk> Object <jf>f</jf>;
+ * }
+ * A a = <jk>new</jk> A();
+ * a.<jf>f</jf> = a;
+ *
+ * <jc>// Throws a SerializeException</jc>
+ * String json = s.serialize(a);
+ * </p>
*
* <ul class='seealso'>
* <li class='jf'>{@link BeanTraverseContext#BEANTRAVERSE_detectRecursions}
@@ -95,12 +148,33 @@ public class BeanTraverseBuilder extends BeanContextBuilder {
*
* <p>
* If <jk>true</jk>, when we encounter the same object when traversing a tree, we set the value to <jk>null</jk>.
- * Otherwise, an exception is thrown.
*
- * <ul class='notes'>
- * <li>
- * Checking for recursion can cause a small performance penalty.
- * </ul>
+ * <p>
+ * For example, if a model contains the links A->B->C->A, then the JSON generated will look like
+ * the following when <jsf>BEANTRAVERSE_ignoreRecursions</jsf> is <jk>true</jk>...
+ *
+ * <p class='bcode w800'>
+ * {A:{B:{C:<jk>null</jk>}}}
+ * </p>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * <jc>// Create a serializer that never adds _type to nodes.</jc>
+ * WriterSerializer s = JsonSerializer
+ * .<jsm>create</jsm>()
+ * .ignoreRecursions(<jk>true</jk>)
+ * .build();
+ *
+ * <jc>// Create a POJO model with a recursive loop.</jc>
+ * <jk>public class</jk> A {
+ * <jk>public</jk> Object <jf>f</jf>;
+ * }
+ * A a = <jk>new</jk> A();
+ * a.<jf>f</jf> = a;
+ *
+ * <jc>// Produces "{f:null}"</jc>
+ * String json = s.serialize(a);
+ * </p>
*
* <ul class='seealso'>
* <li class='jf'>{@link BeanTraverseContext#BEANTRAVERSE_ignoreRecursions}
@@ -120,7 +194,34 @@ public class BeanTraverseBuilder extends BeanContextBuilder {
* Configuration property: Ignore recursion errors.
*
* <p>
- * Shortcut for calling <code>ignoreRecursions(<jk>true</jk>)</code>.
+ * When enabled, when we encounter the same object when traversing a tree, we set the value to <jk>null</jk>.
+ *
+ * <p>
+ * For example, if a model contains the links A->B->C->A, then the JSON generated will look like
+ * the following when <jsf>BEANTRAVERSE_ignoreRecursions</jsf> is <jk>true</jk>...
+ *
+ * <p class='bcode w800'>
+ * {A:{B:{C:<jk>null</jk>}}}
+ * </p>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * <jc>// Create a serializer that never adds _type to nodes.</jc>
+ * WriterSerializer s = JsonSerializer
+ * .<jsm>create</jsm>()
+ * .ignoreRecursions()
+ * .build();
+ *
+ * <jc>// Create a POJO model with a recursive loop.</jc>
+ * <jk>public class</jk> A {
+ * <jk>public</jk> Object <jf>f</jf>;
+ * }
+ * A a = <jk>new</jk> A();
+ * a.<jf>f</jf> = a;
+ *
+ * <jc>// Produces "{f:null}"</jc>
+ * String json = s.serialize(a);
+ * </p>
*
* <ul class='seealso'>
* <li class='jf'>{@link BeanTraverseContext#BEANTRAVERSE_ignoreRecursions}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseContext.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseContext.java
index ee5cb95..dcad339 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseContext.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseContext.java
@@ -15,7 +15,6 @@ package org.apache.juneau;
import org.apache.juneau.annotation.*;
import org.apache.juneau.collections.*;
-import org.apache.juneau.parser.*;
/**
* Parent class for all classes that traverse POJOs.
@@ -63,18 +62,7 @@ public abstract class BeanTraverseContext extends BeanContext {
* <p>
* Recursions can occur when traversing models that aren't true trees but rather contain loops.
* <br>In general, unchecked recursions cause stack-overflow-errors.
- * <br>These show up as {@link ParseException ParseExceptions} with the message <js>"Depth too deep. Stack overflow occurred."</js>.
- *
- * <p>
- * The behavior when recursions are detected depends on the value for {@link #BEANTRAVERSE_ignoreRecursions}.
- *
- * <p>
- * For example, if a model contains the links A->B->C->A, then the JSON generated will look like
- * the following when <jsf>BEANTRAVERSE_ignoreRecursions</jsf> is <jk>true</jk>...
- *
- * <p class='bcode w800'>
- * {A:{B:{C:<jk>null</jk>}}}
- * </p>
+ * <br>These show up as {@link BeanRecursionException BeanRecursionException} with the message <js>"Depth too deep. Stack overflow occurred."</js>.
*
* <ul class='notes'>
* <li>
@@ -86,15 +74,7 @@ public abstract class BeanTraverseContext extends BeanContext {
* <jc>// Create a serializer that never adds _type to nodes.</jc>
* WriterSerializer s = JsonSerializer
* .<jsm>create</jsm>()
- * .detectRecursions()
- * .ignoreRecursions()
- * .build();
- *
- * <jc>// Same, but use property.</jc>
- * WriterSerializer s = JsonSerializer
- * .<jsm>create</jsm>()
* .set(<jsf>BEANTRAVERSE_detectRecursions</jsf>, <jk>true</jk>)
- * .set(<jsf>BEANTRAVERSE_ignoreRecursions</jsf>, <jk>true</jk>)
* .build();
*
* <jc>// Create a POJO model with a recursive loop.</jc>
@@ -104,7 +84,7 @@ public abstract class BeanTraverseContext extends BeanContext {
* A a = <jk>new</jk> A();
* a.<jf>f</jf> = a;
*
- * <jc>// Produces "{f:null}"</jc>
+ * <jc>// Throws a SerializeException</jc>
* String json = s.serialize(a);
* </p>
*/
@@ -135,12 +115,34 @@ public abstract class BeanTraverseContext extends BeanContext {
*
* <h5 class='section'>Description:</h5>
* <p>
- * Used in conjunction with {@link #BEANTRAVERSE_detectRecursions}.
- * <br>Setting is ignored if <jsf>BEANTRAVERSE_detectRecursions</jsf> is <jk>false</jk>.
+ * If <jk>true</jk>, when we encounter the same object when traversing a tree, we set the value to <jk>null</jk>.
*
* <p>
- * If <jk>true</jk>, when we encounter the same object when traversing a tree, we set the value to <jk>null</jk>.
- * <br>Otherwise, a {@link BeanRecursionException} is thrown with the message <js>"Recursion occurred, stack=..."</js>.
+ * For example, if a model contains the links A->B->C->A, then the JSON generated will look like
+ * the following when <jsf>BEANTRAVERSE_ignoreRecursions</jsf> is <jk>true</jk>...
+ *
+ * <p class='bcode w800'>
+ * {A:{B:{C:<jk>null</jk>}}}
+ * </p>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * <jc>// Create a serializer that never adds _type to nodes.</jc>
+ * WriterSerializer s = JsonSerializer
+ * .<jsm>create</jsm>()
+ * .set(<jsf>BEANTRAVERSE_ignoreRecursions</jsf>, <jk>true</jk>)
+ * .build();
+ *
+ * <jc>// Create a POJO model with a recursive loop.</jc>
+ * <jk>public class</jk> A {
+ * <jk>public</jk> Object <jf>f</jf>;
+ * }
+ * A a = <jk>new</jk> A();
+ * a.<jf>f</jf> = a;
+ *
+ * <jc>// Produces "{f:null}"</jc>
+ * String json = s.serialize(a);
+ * </p>
*/
public static final String BEANTRAVERSE_ignoreRecursions = PREFIX + ".ignoreRecursions.b";
@@ -257,8 +259,8 @@ public abstract class BeanTraverseContext extends BeanContext {
maxDepth = getIntegerProperty(BEANTRAVERSE_maxDepth, 100);
initialDepth = getIntegerProperty(BEANTRAVERSE_initialDepth, 0);
- detectRecursions = getBooleanProperty(BEANTRAVERSE_detectRecursions, false);
ignoreRecursions = getBooleanProperty(BEANTRAVERSE_ignoreRecursions, false);
+ detectRecursions = getBooleanProperty(BEANTRAVERSE_detectRecursions, ignoreRecursions);
}
@Override /* Context */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHttpEntity.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHttpEntity.java
index 0026a12..b0bdefb 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHttpEntity.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHttpEntity.java
@@ -17,6 +17,7 @@ import static org.apache.juneau.internal.IOUtils.*;
import java.io.*;
import org.apache.http.entity.*;
+import org.apache.juneau.*;
import org.apache.juneau.httppart.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.serializer.*;
@@ -69,7 +70,7 @@ public class SerializedHttpEntity extends BasicHttpEntity {
}
}
} catch (SerializeException e) {
- throw new IOException(e);
+ throw new BasicRuntimeException(e, "Serialization error on request body.");
}
}
}
diff --git a/juneau-doc/docs/ReleaseNotes/8.1.4.html b/juneau-doc/docs/ReleaseNotes/8.1.4.html
index 49a3475..80557d1 100644
--- a/juneau-doc/docs/ReleaseNotes/8.1.4.html
+++ b/juneau-doc/docs/ReleaseNotes/8.1.4.html
@@ -183,6 +183,9 @@
<li class='jm'>{@link oaj.http.annotation.FormData#multi()}
</ul>
<li>
+ {@link oaj.BeanContext#BEAN_ignoreRecursions} setting no longer requires {@link oaj.BeanContext#BEAN_detectRecursions}
+ to be enabled.
+ <li>
HTML-Schema support is being deprecated due to low-use and difficulty in maintaining. It will be removed in 9.0.
</ul>
diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientBuilderTest.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientBuilderTest.java
index e5ccd22..72798fc 100644
--- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientBuilderTest.java
+++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientBuilderTest.java
@@ -2233,58 +2233,145 @@ public class RestClientBuilderTest {
assertEquals("{f:1}", b.toString());
}
-// @Test
-// public void k21_restClient_serializerClass() throws Exception { fail(); }
-//// public RestClientBuilder serializer(Class<? extends Serializer> value) {
-//
-// @Test
-// public void k22_restClient_serializerObject() throws Exception { fail(); }
-//// public RestClientBuilder serializer(Serializer value) {
-//
-// @Test
-// public void k23_restClient_serializersClasses() throws Exception { fail(); }
-//// public RestClientBuilder serializers(Class<? extends Serializer>...value) {
-//
-// @Test
-// public void k24_restClient_serializersObjects() throws Exception { fail(); }
-//// public RestClientBuilder serializers(Serializer...value) {
-//
-// //-----------------------------------------------------------------------------------------------------------------
-// // Serializer properties
-// //-----------------------------------------------------------------------------------------------------------------
-//
-// @Test
-// public void l01_serializer_addBeanTypesBoolean() throws Exception { fail(); }
-//// public RestClientBuilder addBeanTypes(boolean value) {
-//
-// @Test
-// public void l02_serializer_addBeanTypes() throws Exception { fail(); }
-//// public RestClientBuilder addBeanTypes() {
-//
-// @Test
-// public void l03_serializer_addRootTypeBoolean() throws Exception { fail(); }
-//// public RestClientBuilder addRootType(boolean value) {
-//
-// @Test
-// public void l04_serializer_addRootType() throws Exception { fail(); }
-//// public RestClientBuilder addRootType() {
-//
-// @Test
-// public void l05_serializer_detectRecursionsBoolean() throws Exception { fail(); }
-//// public RestClientBuilder detectRecursions(boolean value) {
-//
-// @Test
-// public void l06_serializer_detectRecursions() throws Exception { fail(); }
-//// public RestClientBuilder detectRecursions() {
-//
-// @Test
-// public void l07_serializer_ignoreRecursionsBoolean() throws Exception { fail(); }
-//// public RestClientBuilder ignoreRecursions(boolean value) {
-//
-// @Test
-// public void l08_serializer_ignoreRecursions() throws Exception { fail(); }
-//// public RestClientBuilder ignoreRecursions() {
-//
+ //-----------------------------------------------------------------------------------------------------------------
+ // Serializer properties
+ //-----------------------------------------------------------------------------------------------------------------
+
+ @Rest
+ public static class L extends BasicRest {
+ @RestMethod(path="/")
+ public Reader post(org.apache.juneau.rest.RestRequest req) throws IOException {
+ return req.getBody().getReader();
+ }
+ }
+
+ public static class L1 {
+ public Object f1;
+
+ public static L1 create() {
+ L1 l = new L1();
+ l.f1 = L2.create();
+ return l;
+ }
+ }
+
+ @org.apache.juneau.annotation.Bean(typeName="L")
+ public static class L2 {
+ public int f2;
+
+ public static L2 create() {
+ L2 l = new L2();
+ l.f2 = 1;
+ return l;
+ }
+ }
+
+ @Test
+ public void l01a_serializer_addBeanTypes() throws Exception {
+ RestClient rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .addBeanTypes(true)
+ .build();
+ rc.post("", L1.create()).run().getBody().assertValue("{f1:{_type:'L',f2:1}}");
+
+ rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .addBeanTypes(false)
+ .build();
+ rc.post("", L1.create()).run().getBody().assertValue("{f1:{f2:1}}");
+
+ rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .addBeanTypes()
+ .build();
+ rc.post("", L1.create()).run().getBody().assertValue("{f1:{_type:'L',f2:1}}");
+ }
+
+ @Test
+ public void l03_serializer_addRootType() throws Exception {
+ RestClient rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .addRootType(true)
+ .build();
+ rc.post("", L2.create()).run().getBody().assertValue("{f2:1}");
+
+ rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .addBeanTypes()
+ .addRootType(false)
+ .build();
+ rc.post("", L2.create()).run().getBody().assertValue("{f2:1}");
+
+ rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .addBeanTypes()
+ .addRootType(true)
+ .build();
+ rc.post("", L2.create()).run().getBody().assertValue("{_type:'L',f2:1}");
+
+ rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .addBeanTypes()
+ .addRootType()
+ .build();
+ rc.post("", L2.create()).run().getBody().assertValue("{_type:'L',f2:1}");
+ }
+
+ @Test
+ public void l05_serializer_detectRecursions() throws Exception {
+ L1 l1 = new L1();
+ l1.f1 = l1;
+
+ RestClient rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .detectRecursions()
+ .build();
+ try {
+ rc.post("", l1).run();
+ } catch (RestCallException e) {
+ assertTrue(e.getCause().getCause().getMessage().startsWith("Recursion occurred"));
+ }
+
+ rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .detectRecursions(true)
+ .build();
+ try {
+ rc.post("", l1).run();
+ } catch (RestCallException e) {
+ assertTrue(e.getCause().getCause().getMessage().startsWith("Recursion occurred"));
+ }
+ }
+
+ @Test
+ public void l07_serializer_ignoreRecursions() throws Exception {
+ L1 l1 = new L1();
+ l1.f1 = l1;
+
+ RestClient rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .ignoreRecursions()
+ .build();
+ rc.post("", l1).run().getBody().assertValue("{}");
+
+ rc = MockRestClient
+ .create(L.class)
+ .simpleJson()
+ .ignoreRecursions(true)
+ .build();
+ rc.post("", l1).run().getBody().assertValue("{}");
+ }
+
// @Test
// public void l09_serializer_initialDepth() throws Exception { fail(); }
//// public RestClientBuilder initialDepth(int value) {
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
index 4daf6c5..b13ae8a 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
@@ -2378,7 +2378,7 @@ public final class RestRequest extends BeanSession implements HttpUriRequest, Co
} catch (Exception e) {
if (response != null)
response.close();
- throw e instanceof RestCallException ? (RestCallException)e : new RestCallException(e).setRestResponse(response);
+ throw RestCallException.create(e).setRestResponse(response);
}
return this.response;