001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.lang3.builder; 019 020import org.apache.commons.lang3.ClassUtils; 021 022/** 023 * Works with {@link ToStringBuilder} to create a "deep" {@code toString}. 024 * But instead a single line like the {@link RecursiveToStringStyle} this creates a multiline String 025 * similar to the {@link ToStringStyle#MULTI_LINE_STYLE}. 026 * 027 * <p>To use this class write code as follows:</p> 028 * 029 * <pre> 030 * public class Job { 031 * String title; 032 * ... 033 * } 034 * 035 * public class Person { 036 * String name; 037 * int age; 038 * boolean smoker; 039 * Job job; 040 * 041 * ... 042 * 043 * public String toString() { 044 * return new ReflectionToStringBuilder(this, new MultilineRecursiveToStringStyle()).toString(); 045 * } 046 * } 047 * </pre> 048 * 049 * <p> 050 * This will produce a toString of the format:<br> 051 * <code>Person@7f54[ <br> 052 * name=Stephen, <br> 053 * age=29, <br> 054 * smoker=false, <br> 055 * job=Job@43cd2[ <br> 056 * title=Manager <br> 057 * ] <br> 058 * ] 059 * </code> 060 * </p> 061 * 062 * @since 3.4 063 */ 064public class MultilineRecursiveToStringStyle extends RecursiveToStringStyle { 065 066 /** 067 * Required for serialization support. 068 * @see java.io.Serializable 069 */ 070 private static final long serialVersionUID = 1L; 071 072 /** Indenting of inner lines. */ 073 private static final int INDENT = 2; 074 075 /** Current indenting. */ 076 private int spaces = 2; 077 078 /** 079 * Constructor. 080 */ 081 public MultilineRecursiveToStringStyle() { 082 resetIndent(); 083 } 084 085 @Override 086 protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) { 087 spaces += INDENT; 088 resetIndent(); 089 super.appendDetail(buffer, fieldName, array); 090 spaces -= INDENT; 091 resetIndent(); 092 } 093 094 @Override 095 protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) { 096 spaces += INDENT; 097 resetIndent(); 098 super.appendDetail(buffer, fieldName, array); 099 spaces -= INDENT; 100 resetIndent(); 101 } 102 103 @Override 104 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) { 105 spaces += INDENT; 106 resetIndent(); 107 super.appendDetail(buffer, fieldName, array); 108 spaces -= INDENT; 109 resetIndent(); 110 } 111 112 @Override 113 protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) { 114 spaces += INDENT; 115 resetIndent(); 116 super.appendDetail(buffer, fieldName, array); 117 spaces -= INDENT; 118 resetIndent(); 119 } 120 121 @Override 122 protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) { 123 spaces += INDENT; 124 resetIndent(); 125 super.appendDetail(buffer, fieldName, array); 126 spaces -= INDENT; 127 resetIndent(); 128 } 129 130 @Override 131 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) { 132 spaces += INDENT; 133 resetIndent(); 134 super.appendDetail(buffer, fieldName, array); 135 spaces -= INDENT; 136 resetIndent(); 137 } 138 139 @Override 140 protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) { 141 spaces += INDENT; 142 resetIndent(); 143 super.appendDetail(buffer, fieldName, array); 144 spaces -= INDENT; 145 resetIndent(); 146 } 147 148 @Override 149 public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { 150 if (!ClassUtils.isPrimitiveWrapper(value.getClass()) && !String.class.equals(value.getClass()) 151 && accept(value.getClass())) { 152 spaces += INDENT; 153 resetIndent(); 154 buffer.append(ReflectionToStringBuilder.toString(value, this)); 155 spaces -= INDENT; 156 resetIndent(); 157 } else { 158 super.appendDetail(buffer, fieldName, value); 159 } 160 } 161 162 @Override 163 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) { 164 spaces += INDENT; 165 resetIndent(); 166 super.appendDetail(buffer, fieldName, array); 167 spaces -= INDENT; 168 resetIndent(); 169 } 170 171 @Override 172 protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) { 173 spaces += INDENT; 174 resetIndent(); 175 super.appendDetail(buffer, fieldName, array); 176 spaces -= INDENT; 177 resetIndent(); 178 } 179 180 @Override 181 protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) { 182 spaces += INDENT; 183 resetIndent(); 184 super.reflectionAppendArrayDetail(buffer, fieldName, array); 185 spaces -= INDENT; 186 resetIndent(); 187 } 188 189 /** 190 * Resets the fields responsible for the line breaks and indenting. 191 * Must be invoked after changing the {@link #spaces} value. 192 */ 193 private void resetIndent() { 194 setArrayStart("{" + System.lineSeparator() + spacer(spaces)); 195 setArraySeparator("," + System.lineSeparator() + spacer(spaces)); 196 setArrayEnd(System.lineSeparator() + spacer(spaces - INDENT) + "}"); 197 198 setContentStart("[" + System.lineSeparator() + spacer(spaces)); 199 setFieldSeparator("," + System.lineSeparator() + spacer(spaces)); 200 setContentEnd(System.lineSeparator() + spacer(spaces - INDENT) + "]"); 201 } 202 203 /** 204 * Creates a StringBuilder responsible for the indenting. 205 * 206 * @param spaces how far to indent 207 * @return a StringBuilder with {spaces} leading space characters. 208 */ 209 private StringBuilder spacer(final int spaces) { 210 final StringBuilder sb = new StringBuilder(); 211 for (int i = 0; i < spaces; i++) { 212 sb.append(" "); 213 } 214 return sb; 215 } 216 217}