MultilineRecursiveToStringStyle.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.lang3.builder;

  18. import org.apache.commons.lang3.ClassUtils;
  19. import org.apache.commons.lang3.StringUtils;

  20. /**
  21.  * Works with {@link ToStringBuilder} to create a "deep" {@code toString}.
  22.  * But instead a single line like the {@link RecursiveToStringStyle} this creates a multiline String
  23.  * similar to the {@link ToStringStyle#MULTI_LINE_STYLE}.
  24.  *
  25.  * <p>To use this class write code as follows:</p>
  26.  *
  27.  * <pre>
  28.  * public class Job {
  29.  *   String title;
  30.  *   ...
  31.  * }
  32.  *
  33.  * public class Person {
  34.  *   String name;
  35.  *   int age;
  36.  *   boolean smoker;
  37.  *   Job job;
  38.  *
  39.  *   ...
  40.  *
  41.  *   public String toString() {
  42.  *     return new ReflectionToStringBuilder(this, new MultilineRecursiveToStringStyle()).toString();
  43.  *   }
  44.  * }
  45.  * </pre>
  46.  *
  47.  * <p>
  48.  * This will produce a toString of the format:<br>
  49.  * {@code Person@7f54[ <br>
  50.  * &nbsp; name=Stephen, <br>
  51.  * &nbsp; age=29, <br>
  52.  * &nbsp; smokealse, <br>
  53.  * &nbsp; job=Job@43cd2[ <br>
  54.  * &nbsp; &nbsp; title=Manager <br>
  55.  * &nbsp;  ] <br>
  56.  * ]
  57.  * }
  58.  * </p>
  59.  *
  60.  * @since 3.4
  61.  */
  62. public class MultilineRecursiveToStringStyle extends RecursiveToStringStyle {

  63.     /**
  64.      * Required for serialization support.
  65.      * @see java.io.Serializable
  66.      */
  67.     private static final long serialVersionUID = 1L;

  68.     /** Indenting of inner lines. */
  69.     private static final int INDENT = 2;

  70.     /** Current indenting. */
  71.     private int spaces = 2;

  72.     /**
  73.      * Constructs a new instance.
  74.      */
  75.     public MultilineRecursiveToStringStyle() {
  76.         resetIndent();
  77.     }

  78.     @Override
  79.     protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) {
  80.         spaces += INDENT;
  81.         resetIndent();
  82.         super.appendDetail(buffer, fieldName, array);
  83.         spaces -= INDENT;
  84.         resetIndent();
  85.     }

  86.     @Override
  87.     protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) {
  88.         spaces += INDENT;
  89.         resetIndent();
  90.         super.appendDetail(buffer, fieldName, array);
  91.         spaces -= INDENT;
  92.         resetIndent();
  93.     }

  94.     @Override
  95.     protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) {
  96.         spaces += INDENT;
  97.         resetIndent();
  98.         super.appendDetail(buffer, fieldName, array);
  99.         spaces -= INDENT;
  100.         resetIndent();
  101.     }

  102.     @Override
  103.     protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) {
  104.         spaces += INDENT;
  105.         resetIndent();
  106.         super.appendDetail(buffer, fieldName, array);
  107.         spaces -= INDENT;
  108.         resetIndent();
  109.     }

  110.     @Override
  111.     protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) {
  112.         spaces += INDENT;
  113.         resetIndent();
  114.         super.appendDetail(buffer, fieldName, array);
  115.         spaces -= INDENT;
  116.         resetIndent();
  117.     }

  118.     @Override
  119.     protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) {
  120.         spaces += INDENT;
  121.         resetIndent();
  122.         super.appendDetail(buffer, fieldName, array);
  123.         spaces -= INDENT;
  124.         resetIndent();
  125.     }

  126.     @Override
  127.     protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) {
  128.         spaces += INDENT;
  129.         resetIndent();
  130.         super.appendDetail(buffer, fieldName, array);
  131.         spaces -= INDENT;
  132.         resetIndent();
  133.     }

  134.     @Override
  135.     public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) {
  136.         if (!ClassUtils.isPrimitiveWrapper(value.getClass()) && !String.class.equals(value.getClass())
  137.                 && accept(value.getClass())) {
  138.             spaces += INDENT;
  139.             resetIndent();
  140.             buffer.append(ReflectionToStringBuilder.toString(value, this));
  141.             spaces -= INDENT;
  142.             resetIndent();
  143.         } else {
  144.             super.appendDetail(buffer, fieldName, value);
  145.         }
  146.     }

  147.     @Override
  148.     protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) {
  149.         spaces += INDENT;
  150.         resetIndent();
  151.         super.appendDetail(buffer, fieldName, array);
  152.         spaces -= INDENT;
  153.         resetIndent();
  154.     }

  155.     @Override
  156.     protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) {
  157.         spaces += INDENT;
  158.         resetIndent();
  159.         super.appendDetail(buffer, fieldName, array);
  160.         spaces -= INDENT;
  161.         resetIndent();
  162.     }

  163.     @Override
  164.     protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) {
  165.         spaces += INDENT;
  166.         resetIndent();
  167.         super.reflectionAppendArrayDetail(buffer, fieldName, array);
  168.         spaces -= INDENT;
  169.         resetIndent();
  170.     }

  171.     /**
  172.      * Resets the fields responsible for the line breaks and indenting.
  173.      * Must be invoked after changing the {@link #spaces} value.
  174.      */
  175.     private void resetIndent() {
  176.         setArrayStart("{" + System.lineSeparator() + spacer(spaces));
  177.         setArraySeparator("," + System.lineSeparator() + spacer(spaces));
  178.         setArrayEnd(System.lineSeparator() + spacer(spaces - INDENT) + "}");

  179.         setContentStart("[" + System.lineSeparator() + spacer(spaces));
  180.         setFieldSeparator("," + System.lineSeparator() + spacer(spaces));
  181.         setContentEnd(System.lineSeparator() + spacer(spaces - INDENT) + "]");
  182.     }

  183.     /**
  184.      * Creates a StringBuilder responsible for the indenting.
  185.      *
  186.      * @param spaces how far to indent
  187.      * @return a StringBuilder with {spaces} leading space characters.
  188.      */
  189.     private String spacer(final int spaces) {
  190.         return StringUtils.repeat(' ', spaces);
  191.     }

  192. }