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 * https://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; 021import org.apache.commons.lang3.StringUtils; 022 023/** 024 * Works with {@link ToStringBuilder} to create a "deep" {@code toString}. 025 * But instead a single line like the {@link RecursiveToStringStyle} this creates a multiline String 026 * similar to the {@link ToStringStyle#MULTI_LINE_STYLE}. 027 * 028 * <p>To use this class write code as follows:</p> 029 * 030 * <pre> 031 * public class Job { 032 * String title; 033 * ... 034 * } 035 * 036 * public class Person { 037 * String name; 038 * int age; 039 * boolean smoker; 040 * Job job; 041 * 042 * ... 043 * 044 * public String toString() { 045 * return new ReflectionToStringBuilder(this, new MultilineRecursiveToStringStyle()).toString(); 046 * } 047 * } 048 * </pre> 049 * 050 * <p> 051 * This will produce a toString of the format:<br> 052 * {@code Person@7f54[ <br> 053 * name=Stephen, <br> 054 * age=29, <br> 055 * smokealse, <br> 056 * job=Job@43cd2[ <br> 057 * title=Manager <br> 058 * ] <br> 059 * ] 060 * } 061 * </p> 062 * 063 * @since 3.4 064 */ 065public class MultilineRecursiveToStringStyle extends RecursiveToStringStyle { 066 067 /** 068 * Required for serialization support. 069 * 070 * @see java.io.Serializable 071 */ 072 private static final long serialVersionUID = 1L; 073 074 /** Indenting of inner lines. */ 075 private static final int INDENT = 2; 076 077 /** Current indenting. */ 078 private int spaces = 2; 079 080 /** 081 * Constructs a new instance. 082 */ 083 public MultilineRecursiveToStringStyle() { 084 resetIndent(); 085 } 086 087 @Override 088 protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) { 089 spaces += INDENT; 090 resetIndent(); 091 super.appendDetail(buffer, fieldName, array); 092 spaces -= INDENT; 093 resetIndent(); 094 } 095 096 @Override 097 protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) { 098 spaces += INDENT; 099 resetIndent(); 100 super.appendDetail(buffer, fieldName, array); 101 spaces -= INDENT; 102 resetIndent(); 103 } 104 105 @Override 106 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) { 107 spaces += INDENT; 108 resetIndent(); 109 super.appendDetail(buffer, fieldName, array); 110 spaces -= INDENT; 111 resetIndent(); 112 } 113 114 @Override 115 protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) { 116 spaces += INDENT; 117 resetIndent(); 118 super.appendDetail(buffer, fieldName, array); 119 spaces -= INDENT; 120 resetIndent(); 121 } 122 123 @Override 124 protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) { 125 spaces += INDENT; 126 resetIndent(); 127 super.appendDetail(buffer, fieldName, array); 128 spaces -= INDENT; 129 resetIndent(); 130 } 131 132 @Override 133 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) { 134 spaces += INDENT; 135 resetIndent(); 136 super.appendDetail(buffer, fieldName, array); 137 spaces -= INDENT; 138 resetIndent(); 139 } 140 141 @Override 142 protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) { 143 spaces += INDENT; 144 resetIndent(); 145 super.appendDetail(buffer, fieldName, array); 146 spaces -= INDENT; 147 resetIndent(); 148 } 149 150 @Override 151 public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { 152 if (!ClassUtils.isPrimitiveWrapper(value.getClass()) && !String.class.equals(value.getClass()) 153 && accept(value.getClass())) { 154 spaces += INDENT; 155 resetIndent(); 156 buffer.append(ReflectionToStringBuilder.toString(value, this)); 157 spaces -= INDENT; 158 resetIndent(); 159 } else { 160 super.appendDetail(buffer, fieldName, value); 161 } 162 } 163 164 @Override 165 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) { 166 spaces += INDENT; 167 resetIndent(); 168 super.appendDetail(buffer, fieldName, array); 169 spaces -= INDENT; 170 resetIndent(); 171 } 172 173 @Override 174 protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) { 175 spaces += INDENT; 176 resetIndent(); 177 super.appendDetail(buffer, fieldName, array); 178 spaces -= INDENT; 179 resetIndent(); 180 } 181 182 @Override 183 protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) { 184 spaces += INDENT; 185 resetIndent(); 186 super.reflectionAppendArrayDetail(buffer, fieldName, array); 187 spaces -= INDENT; 188 resetIndent(); 189 } 190 191 /** 192 * Resets the fields responsible for the line breaks and indenting. 193 * Must be invoked after changing the {@link #spaces} value. 194 */ 195 private void resetIndent() { 196 setArrayStart("{" + System.lineSeparator() + spacer(spaces)); 197 setArraySeparator("," + System.lineSeparator() + spacer(spaces)); 198 setArrayEnd(System.lineSeparator() + spacer(spaces - INDENT) + "}"); 199 200 setContentStart("[" + System.lineSeparator() + spacer(spaces)); 201 setFieldSeparator("," + System.lineSeparator() + spacer(spaces)); 202 setContentEnd(System.lineSeparator() + spacer(spaces - INDENT) + "]"); 203 } 204 205 /** 206 * Creates a StringBuilder responsible for the indenting. 207 * 208 * @param spaces how far to indent 209 * @return a StringBuilder with {spaces} leading space characters. 210 */ 211 private String spacer(final int spaces) { 212 return StringUtils.repeat(' ', spaces); 213 } 214 215}