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 /** 086 * Resets the fields responsible for the line breaks and indenting. 087 * Must be invoked after changing the {@link #spaces} value. 088 */ 089 private void resetIndent() { 090 setArrayStart("{" + System.lineSeparator() + spacer(spaces)); 091 setArraySeparator("," + System.lineSeparator() + spacer(spaces)); 092 setArrayEnd(System.lineSeparator() + spacer(spaces - INDENT) + "}"); 093 094 setContentStart("[" + System.lineSeparator() + spacer(spaces)); 095 setFieldSeparator("," + System.lineSeparator() + spacer(spaces)); 096 setContentEnd(System.lineSeparator() + spacer(spaces - INDENT) + "]"); 097 } 098 099 /** 100 * Creates a StringBuilder responsible for the indenting. 101 * 102 * @param spaces how far to indent 103 * @return a StringBuilder with {spaces} leading space characters. 104 */ 105 private StringBuilder spacer(final int spaces) { 106 final StringBuilder sb = new StringBuilder(); 107 for (int i = 0; i < spaces; i++) { 108 sb.append(" "); 109 } 110 return sb; 111 } 112 113 @Override 114 public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { 115 if (!ClassUtils.isPrimitiveWrapper(value.getClass()) && !String.class.equals(value.getClass()) 116 && accept(value.getClass())) { 117 spaces += INDENT; 118 resetIndent(); 119 buffer.append(ReflectionToStringBuilder.toString(value, this)); 120 spaces -= INDENT; 121 resetIndent(); 122 } else { 123 super.appendDetail(buffer, fieldName, value); 124 } 125 } 126 127 @Override 128 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) { 129 spaces += INDENT; 130 resetIndent(); 131 super.appendDetail(buffer, fieldName, array); 132 spaces -= INDENT; 133 resetIndent(); 134 } 135 136 @Override 137 protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) { 138 spaces += INDENT; 139 resetIndent(); 140 super.reflectionAppendArrayDetail(buffer, fieldName, array); 141 spaces -= INDENT; 142 resetIndent(); 143 } 144 145 @Override 146 protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) { 147 spaces += INDENT; 148 resetIndent(); 149 super.appendDetail(buffer, fieldName, array); 150 spaces -= INDENT; 151 resetIndent(); 152 } 153 154 @Override 155 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) { 156 spaces += INDENT; 157 resetIndent(); 158 super.appendDetail(buffer, fieldName, array); 159 spaces -= INDENT; 160 resetIndent(); 161 } 162 163 @Override 164 protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) { 165 spaces += INDENT; 166 resetIndent(); 167 super.appendDetail(buffer, fieldName, array); 168 spaces -= INDENT; 169 resetIndent(); 170 } 171 172 @Override 173 protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) { 174 spaces += INDENT; 175 resetIndent(); 176 super.appendDetail(buffer, fieldName, array); 177 spaces -= INDENT; 178 resetIndent(); 179 } 180 181 @Override 182 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) { 183 spaces += INDENT; 184 resetIndent(); 185 super.appendDetail(buffer, fieldName, array); 186 spaces -= INDENT; 187 resetIndent(); 188 } 189 190 @Override 191 protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) { 192 spaces += INDENT; 193 resetIndent(); 194 super.appendDetail(buffer, fieldName, array); 195 spaces -= INDENT; 196 resetIndent(); 197 } 198 199 @Override 200 protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) { 201 spaces += INDENT; 202 resetIndent(); 203 super.appendDetail(buffer, fieldName, array); 204 spaces -= INDENT; 205 resetIndent(); 206 } 207 208 @Override 209 protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) { 210 spaces += INDENT; 211 resetIndent(); 212 super.appendDetail(buffer, fieldName, array); 213 spaces -= INDENT; 214 resetIndent(); 215 } 216 217}