001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau;
014
015
016import static org.apache.juneau.collections.JsonMap.*;
017import java.lang.annotation.*;
018import java.lang.reflect.*;
019import java.util.*;
020
021import org.apache.juneau.collections.*;
022import org.apache.juneau.internal.*;
023import org.apache.juneau.utils.*;
024
025/**
026 * Parent class for all classes that traverse POJOs.
027 *
028 * <h5 class='topic'>Description</h5>
029 * <p>
030 * Base class that serves as the parent class for all serializers and other classes that traverse POJOs.
031 *
032 * <h5 class='section'>Notes:</h5><ul>
033 *    <li class='note'>This class is thread safe and reusable.
034 * </ul>
035 *
036 * <h5 class='section'>See Also:</h5><ul>
037
038 * </ul>
039 */
040public abstract class BeanTraverseContext extends BeanContextable {
041
042   //-------------------------------------------------------------------------------------------------------------------
043   // Builder
044   //-------------------------------------------------------------------------------------------------------------------
045
046   /**
047    * Builder class.
048    */
049   @FluentSetters
050   public abstract static class Builder extends BeanContextable.Builder {
051
052      boolean detectRecursions, ignoreRecursions;
053      int initialDepth, maxDepth;
054
055      /**
056       * Constructor, default settings.
057       */
058      protected Builder() {
059         super();
060         detectRecursions = env("BeanTraverseContext.detectRecursions", false);
061         ignoreRecursions = env("BeanTraverseContext.ignoreRecursions", false);
062         initialDepth = env("BeanTraverseContext.initialDepth", 0);
063         maxDepth = env("BeanTraverseContext.maxDepth", 100);
064      }
065
066      /**
067       * Copy constructor.
068       *
069       * @param copyFrom The bean to copy from.
070       */
071      protected Builder(BeanTraverseContext copyFrom) {
072         super(copyFrom);
073         detectRecursions = copyFrom.detectRecursions;
074         ignoreRecursions = copyFrom.ignoreRecursions;
075         initialDepth = copyFrom.initialDepth;
076         maxDepth = copyFrom.maxDepth;
077      }
078
079      /**
080       * Copy constructor.
081       *
082       * @param copyFrom The builder to copy from.
083       */
084      protected Builder(Builder copyFrom) {
085         super(copyFrom);
086         detectRecursions = copyFrom.detectRecursions;
087         ignoreRecursions = copyFrom.ignoreRecursions;
088         initialDepth = copyFrom.initialDepth;
089         maxDepth = copyFrom.maxDepth;
090      }
091
092      @Override /* Context.Builder */
093      public abstract Builder copy();
094
095      @Override /* Context.Builder */
096      public HashKey hashKey() {
097         return HashKey.of(
098            super.hashKey(),
099            detectRecursions,
100            ignoreRecursions,
101            initialDepth,
102            maxDepth
103         );
104      }
105
106      //-----------------------------------------------------------------------------------------------------------------
107      // Properties
108      //-----------------------------------------------------------------------------------------------------------------
109
110      /**
111       * Automatically detect POJO recursions.
112       *
113       * <p>
114       * When enabled, specifies that recursions should be checked for during traversal.
115       *
116       * <p>
117       * Recursions can occur when traversing models that aren't true trees but rather contain loops.
118       * <br>In general, unchecked recursions cause stack-overflow-errors.
119       * <br>These show up as {@link BeanRecursionException BeanRecursionException} with the message <js>"Depth too deep.  Stack overflow occurred."</js>.
120       *
121       * <h5 class='section'>Notes:</h5><ul>
122       *    <li class='note'>
123       *       Checking for recursion can cause a small performance penalty.
124       * </ul>
125       *
126       * <h5 class='section'>Example:</h5>
127       * <p class='bjava'>
128       *    <jc>// Create a serializer that automatically checks for recursions.</jc>
129       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
130       *       .<jsm>create</jsm>()
131       *       .detectRecursions()
132       *       .build();
133       *
134       *    <jc>// Create a POJO model with a recursive loop.</jc>
135       *    <jk>public class</jk> MyBean {
136       *       <jk>public</jk> Object <jf>f</jf>;
137       *    }
138       *    MyBean <jv>bean</jv> = <jk>new</jk> MyBean();
139       *    <jv>bean</jv>.<jf>f</jf> = <jv>bean</jv>;
140       *
141       *    <jc>// Throws a SerializeException and not a StackOverflowError</jc>
142       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>bean</jv>);
143       * </p>
144       *
145       * @return This object.
146       */
147      @FluentSetter
148      public Builder detectRecursions() {
149         return detectRecursions(true);
150      }
151
152      /**
153       * Same as {@link #detectRecursions()} but allows you to explicitly specify the value.
154       *
155       * @param value The value for this setting.
156       * @return This object.
157       */
158      @FluentSetter
159      public Builder detectRecursions(boolean value) {
160         detectRecursions = value;
161         return this;
162      }
163
164      /**
165       * Ignore recursion errors.
166       *
167       * <p>
168       * When enabled, when we encounter the same object when traversing a tree, we set the value to <jk>null</jk>.
169       *
170       * <p>
171       * For example, if a model contains the links A-&gt;B-&gt;C-&gt;A, then the JSON generated will look like
172       *    the following when this setting is <jk>true</jk>...
173       *
174       * <p class='bjson'>
175       *    {A:{B:{C:<jk>null</jk>}}}
176       * </p>
177       *
178       * <h5 class='section'>Notes:</h5><ul>
179       *    <li class='note'>
180       *       Checking for recursion can cause a small performance penalty.
181       * </ul>
182       *
183       * <h5 class='section'>Example:</h5>
184       * <p class='bjava'>
185       *    <jc>// Create a serializer ignores recursions.</jc>
186       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
187       *       .<jsm>create</jsm>()
188       *       .ignoreRecursions()
189       *       .build();
190       *
191       *    <jc>// Create a POJO model with a recursive loop.</jc>
192       *    <jk>public class</jk> MyBean {
193       *       <jk>public</jk> Object <jf>f</jf>;
194       *    }
195       *    MyBean <jv>bean</jv> = <jk>new</jk> MyBean();
196       *    <jv>bean</jv>.<jf>f</jf> = <jv>bean</jv>;
197       *
198       *    <jc>// Produces "{f:null}"</jc>
199       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>bean</jv>);
200       * </p>
201       *
202       * @return This object.
203       */
204      @FluentSetter
205      public Builder ignoreRecursions() {
206         return ignoreRecursions(true);
207      }
208
209      /**
210       * Same as {@link #ignoreRecursions()} but allows you to explicitly specify the value.
211       *
212       * @param value The value for this setting.
213       * @return This object.
214       */
215      @FluentSetter
216      public Builder ignoreRecursions(boolean value) {
217         ignoreRecursions = value;
218         return this;
219      }
220
221      /**
222       * Initial depth.
223       *
224       * <p>
225       * The initial indentation level at the root.
226       *
227       * <p>
228       * Useful when constructing document fragments that need to be indented at a certain level when whitespace is enabled.
229       *
230       * <h5 class='section'>Example:</h5>
231       * <p class='bjava'>
232       *    <jc>// Create a serializer with whitespace enabled and an initial depth of 2.</jc>
233       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
234       *       .<jsm>create</jsm>()
235       *       .ws()
236       *       .initialDepth(2)
237       *       .build();
238       *
239       *    <jc>// Produces "\t\t{\n\t\t\t'foo':'bar'\n\t\t}\n"</jc>
240       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
241       * </p>
242       *
243       * @param value
244       *    The new value for this setting.
245       *    <br>The default is <c>0</c>.
246       * @return This object.
247       */
248      @FluentSetter
249      public Builder initialDepth(int value) {
250         initialDepth = value;
251         return this;
252      }
253
254      /**
255       * Max traversal depth.
256       *
257       * <p>
258       * When enabled, abort traversal if specified depth is reached in the POJO tree.
259       *
260       * <p>
261       * If this depth is exceeded, an exception is thrown.
262       *
263       * <p>
264       * This prevents stack overflows from occurring when trying to traverse models with recursive references.
265       *
266       * <h5 class='section'>Example:</h5>
267       * <p class='bjava'>
268       *    <jc>// Create a serializer that throws an exception if the depth reaches greater than 20.</jc>
269       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
270       *       .<jsm>create</jsm>()
271       *       .maxDepth(20)
272       *       .build();
273       * </p>
274       *
275       * <h5 class='section'>See Also:</h5><ul>
276       *    <li class='jm'>{@link Builder#maxDepth(int)}
277       * </ul>
278       *
279       * @param value
280       *    The new value for this setting.
281       *    <br>The default is <c>100</c>.
282       * @return This object.
283       */
284      @FluentSetter
285      public Builder maxDepth(int value) {
286         maxDepth = value;
287         return this;
288      }
289
290      // <FluentSetters>
291
292      @Override /* GENERATED - org.apache.juneau.Context.Builder */
293      public Builder annotations(Annotation...values) {
294         super.annotations(values);
295         return this;
296      }
297
298      @Override /* GENERATED - org.apache.juneau.Context.Builder */
299      public Builder apply(AnnotationWorkList work) {
300         super.apply(work);
301         return this;
302      }
303
304      @Override /* GENERATED - org.apache.juneau.Context.Builder */
305      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
306         super.applyAnnotations(fromClasses);
307         return this;
308      }
309
310      @Override /* GENERATED - org.apache.juneau.Context.Builder */
311      public Builder applyAnnotations(Method...fromMethods) {
312         super.applyAnnotations(fromMethods);
313         return this;
314      }
315
316      @Override /* GENERATED - org.apache.juneau.Context.Builder */
317      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
318         super.cache(value);
319         return this;
320      }
321
322      @Override /* GENERATED - org.apache.juneau.Context.Builder */
323      public Builder debug() {
324         super.debug();
325         return this;
326      }
327
328      @Override /* GENERATED - org.apache.juneau.Context.Builder */
329      public Builder debug(boolean value) {
330         super.debug(value);
331         return this;
332      }
333
334      @Override /* GENERATED - org.apache.juneau.Context.Builder */
335      public Builder impl(Context value) {
336         super.impl(value);
337         return this;
338      }
339
340      @Override /* GENERATED - org.apache.juneau.Context.Builder */
341      public Builder type(Class<? extends org.apache.juneau.Context> value) {
342         super.type(value);
343         return this;
344      }
345
346      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
347      public Builder beanClassVisibility(Visibility value) {
348         super.beanClassVisibility(value);
349         return this;
350      }
351
352      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
353      public Builder beanConstructorVisibility(Visibility value) {
354         super.beanConstructorVisibility(value);
355         return this;
356      }
357
358      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
359      public Builder beanContext(BeanContext value) {
360         super.beanContext(value);
361         return this;
362      }
363
364      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
365      public Builder beanContext(BeanContext.Builder value) {
366         super.beanContext(value);
367         return this;
368      }
369
370      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
371      public Builder beanDictionary(java.lang.Class<?>...values) {
372         super.beanDictionary(values);
373         return this;
374      }
375
376      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
377      public Builder beanFieldVisibility(Visibility value) {
378         super.beanFieldVisibility(value);
379         return this;
380      }
381
382      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
383      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
384         super.beanInterceptor(on, value);
385         return this;
386      }
387
388      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
389      public Builder beanMapPutReturnsOldValue() {
390         super.beanMapPutReturnsOldValue();
391         return this;
392      }
393
394      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
395      public Builder beanMethodVisibility(Visibility value) {
396         super.beanMethodVisibility(value);
397         return this;
398      }
399
400      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
401      public Builder beanProperties(Map<String,Object> values) {
402         super.beanProperties(values);
403         return this;
404      }
405
406      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
407      public Builder beanProperties(Class<?> beanClass, String properties) {
408         super.beanProperties(beanClass, properties);
409         return this;
410      }
411
412      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
413      public Builder beanProperties(String beanClassName, String properties) {
414         super.beanProperties(beanClassName, properties);
415         return this;
416      }
417
418      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
419      public Builder beanPropertiesExcludes(Map<String,Object> values) {
420         super.beanPropertiesExcludes(values);
421         return this;
422      }
423
424      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
425      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
426         super.beanPropertiesExcludes(beanClass, properties);
427         return this;
428      }
429
430      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
431      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
432         super.beanPropertiesExcludes(beanClassName, properties);
433         return this;
434      }
435
436      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
437      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
438         super.beanPropertiesReadOnly(values);
439         return this;
440      }
441
442      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
443      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
444         super.beanPropertiesReadOnly(beanClass, properties);
445         return this;
446      }
447
448      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
449      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
450         super.beanPropertiesReadOnly(beanClassName, properties);
451         return this;
452      }
453
454      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
455      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
456         super.beanPropertiesWriteOnly(values);
457         return this;
458      }
459
460      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
461      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
462         super.beanPropertiesWriteOnly(beanClass, properties);
463         return this;
464      }
465
466      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
467      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
468         super.beanPropertiesWriteOnly(beanClassName, properties);
469         return this;
470      }
471
472      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
473      public Builder beansRequireDefaultConstructor() {
474         super.beansRequireDefaultConstructor();
475         return this;
476      }
477
478      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
479      public Builder beansRequireSerializable() {
480         super.beansRequireSerializable();
481         return this;
482      }
483
484      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
485      public Builder beansRequireSettersForGetters() {
486         super.beansRequireSettersForGetters();
487         return this;
488      }
489
490      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
491      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
492         super.dictionaryOn(on, values);
493         return this;
494      }
495
496      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
497      public Builder disableBeansRequireSomeProperties() {
498         super.disableBeansRequireSomeProperties();
499         return this;
500      }
501
502      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
503      public Builder disableIgnoreMissingSetters() {
504         super.disableIgnoreMissingSetters();
505         return this;
506      }
507
508      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
509      public Builder disableIgnoreTransientFields() {
510         super.disableIgnoreTransientFields();
511         return this;
512      }
513
514      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
515      public Builder disableIgnoreUnknownNullBeanProperties() {
516         super.disableIgnoreUnknownNullBeanProperties();
517         return this;
518      }
519
520      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
521      public Builder disableInterfaceProxies() {
522         super.disableInterfaceProxies();
523         return this;
524      }
525
526      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
527      public <T> Builder example(Class<T> pojoClass, T o) {
528         super.example(pojoClass, o);
529         return this;
530      }
531
532      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
533      public <T> Builder example(Class<T> pojoClass, String json) {
534         super.example(pojoClass, json);
535         return this;
536      }
537
538      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
539      public Builder findFluentSetters() {
540         super.findFluentSetters();
541         return this;
542      }
543
544      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
545      public Builder findFluentSetters(Class<?> on) {
546         super.findFluentSetters(on);
547         return this;
548      }
549
550      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
551      public Builder ignoreInvocationExceptionsOnGetters() {
552         super.ignoreInvocationExceptionsOnGetters();
553         return this;
554      }
555
556      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
557      public Builder ignoreInvocationExceptionsOnSetters() {
558         super.ignoreInvocationExceptionsOnSetters();
559         return this;
560      }
561
562      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
563      public Builder ignoreUnknownBeanProperties() {
564         super.ignoreUnknownBeanProperties();
565         return this;
566      }
567
568      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
569      public Builder ignoreUnknownEnumValues() {
570         super.ignoreUnknownEnumValues();
571         return this;
572      }
573
574      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
575      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
576         super.implClass(interfaceClass, implClass);
577         return this;
578      }
579
580      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
581      public Builder implClasses(Map<Class<?>,Class<?>> values) {
582         super.implClasses(values);
583         return this;
584      }
585
586      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
587      public Builder interfaceClass(Class<?> on, Class<?> value) {
588         super.interfaceClass(on, value);
589         return this;
590      }
591
592      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
593      public Builder interfaces(java.lang.Class<?>...value) {
594         super.interfaces(value);
595         return this;
596      }
597
598      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
599      public Builder locale(Locale value) {
600         super.locale(value);
601         return this;
602      }
603
604      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
605      public Builder mediaType(MediaType value) {
606         super.mediaType(value);
607         return this;
608      }
609
610      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
611      public Builder notBeanClasses(java.lang.Class<?>...values) {
612         super.notBeanClasses(values);
613         return this;
614      }
615
616      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
617      public Builder notBeanPackages(String...values) {
618         super.notBeanPackages(values);
619         return this;
620      }
621
622      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
623      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
624         super.propertyNamer(value);
625         return this;
626      }
627
628      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
629      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
630         super.propertyNamer(on, value);
631         return this;
632      }
633
634      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
635      public Builder sortProperties() {
636         super.sortProperties();
637         return this;
638      }
639
640      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
641      public Builder sortProperties(java.lang.Class<?>...on) {
642         super.sortProperties(on);
643         return this;
644      }
645
646      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
647      public Builder stopClass(Class<?> on, Class<?> value) {
648         super.stopClass(on, value);
649         return this;
650      }
651
652      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
653      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
654         super.swap(normalClass, swappedClass, swapFunction);
655         return this;
656      }
657
658      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
659      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
660         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
661         return this;
662      }
663
664      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
665      public Builder swaps(java.lang.Class<?>...values) {
666         super.swaps(values);
667         return this;
668      }
669
670      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
671      public Builder timeZone(TimeZone value) {
672         super.timeZone(value);
673         return this;
674      }
675
676      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
677      public Builder typeName(Class<?> on, String value) {
678         super.typeName(on, value);
679         return this;
680      }
681
682      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
683      public Builder typePropertyName(String value) {
684         super.typePropertyName(value);
685         return this;
686      }
687
688      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
689      public Builder typePropertyName(Class<?> on, String value) {
690         super.typePropertyName(on, value);
691         return this;
692      }
693
694      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
695      public Builder useEnumNames() {
696         super.useEnumNames();
697         return this;
698      }
699
700      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
701      public Builder useJavaBeanIntrospector() {
702         super.useJavaBeanIntrospector();
703         return this;
704      }
705
706      // </FluentSetters>
707   }
708
709   //-------------------------------------------------------------------------------------------------------------------
710   // Instance
711   //-------------------------------------------------------------------------------------------------------------------
712
713   final int initialDepth, maxDepth;
714   final boolean
715      detectRecursions,
716      ignoreRecursions;
717
718   private final boolean actualDetectRecursions;
719
720   /**
721    * Constructor
722    *
723    * @param builder The builder for this object.
724    */
725   protected BeanTraverseContext(Builder builder) {
726      super(builder);
727
728      maxDepth = builder.maxDepth;
729      initialDepth = builder.initialDepth;
730      ignoreRecursions = builder.ignoreRecursions;
731      detectRecursions = builder.detectRecursions;
732
733      actualDetectRecursions = detectRecursions || ignoreRecursions || super.isDebug();
734   }
735
736   @Override /* Context */
737   public abstract Builder copy();
738
739   //-----------------------------------------------------------------------------------------------------------------
740   // Properties
741   //-----------------------------------------------------------------------------------------------------------------
742
743   /**
744    * Automatically detect POJO recursions.
745    *
746    * @see Builder#detectRecursions()
747    * @return
748    *    <jk>true</jk> if recursions should be checked for during traversal.
749    */
750   public final boolean isDetectRecursions() {
751      return actualDetectRecursions;
752   }
753
754   /**
755    * Ignore recursion errors.
756    *
757    * @see Builder#ignoreRecursions()
758    * @return
759    *    <jk>true</jk> if when we encounter the same object when traversing a tree, we set the value to <jk>null</jk>.
760    *    <br>Otherwise, an exception is thrown with the message <js>"Recursion occurred, stack=..."</js>.
761    */
762   public final boolean isIgnoreRecursions() {
763      return ignoreRecursions;
764   }
765
766   /**
767    * Initial depth.
768    *
769    * @see Builder#initialDepth(int)
770    * @return
771    *    The initial indentation level at the root.
772    */
773   public final int getInitialDepth() {
774      return initialDepth;
775   }
776
777   /**
778    * Max traversal depth.
779    *
780    * @see Builder#maxDepth(int)
781    * @return
782    *    The depth at which traversal is aborted if depth is reached in the POJO tree.
783    * <br>If this depth is exceeded, an exception is thrown.
784    */
785   public final int getMaxDepth() {
786      return maxDepth;
787   }
788
789   //-----------------------------------------------------------------------------------------------------------------
790   // Other methods
791   //-----------------------------------------------------------------------------------------------------------------
792
793   @Override /* Context */
794   protected JsonMap properties() {
795      return filteredMap("detectRecursions", detectRecursions, "maxDepth", maxDepth, "ignoreRecursions", ignoreRecursions, "initialDepth", initialDepth);
796   }
797}