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