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