001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.style; 018 019import java.lang.reflect.Method; 020import java.util.Collection; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024import java.util.StringJoiner; 025 026import org.springframework.lang.Nullable; 027import org.springframework.util.ClassUtils; 028import org.springframework.util.ObjectUtils; 029 030/** 031 * Converts objects to String form, generally for debugging purposes, 032 * using Spring's {@code toString} styling conventions. 033 * 034 * <p>Uses the reflective visitor pattern underneath the hood to nicely 035 * encapsulate styling algorithms for each type of styled object. 036 * 037 * @author Keith Donald 038 * @author Juergen Hoeller 039 * @since 1.2.2 040 */ 041public class DefaultValueStyler implements ValueStyler { 042 043 private static final String EMPTY = "[[empty]]"; 044 private static final String NULL = "[null]"; 045 private static final String COLLECTION = "collection"; 046 private static final String SET = "set"; 047 private static final String LIST = "list"; 048 private static final String MAP = "map"; 049 private static final String EMPTY_MAP = MAP + EMPTY; 050 private static final String ARRAY = "array"; 051 052 053 @Override 054 public String style(@Nullable Object value) { 055 if (value == null) { 056 return NULL; 057 } 058 else if (value instanceof String) { 059 return "\'" + value + "\'"; 060 } 061 else if (value instanceof Class) { 062 return ClassUtils.getShortName((Class<?>) value); 063 } 064 else if (value instanceof Method) { 065 Method method = (Method) value; 066 return method.getName() + "@" + ClassUtils.getShortName(method.getDeclaringClass()); 067 } 068 else if (value instanceof Map) { 069 return style((Map<?, ?>) value); 070 } 071 else if (value instanceof Map.Entry) { 072 return style((Map.Entry<? ,?>) value); 073 } 074 else if (value instanceof Collection) { 075 return style((Collection<?>) value); 076 } 077 else if (value.getClass().isArray()) { 078 return styleArray(ObjectUtils.toObjectArray(value)); 079 } 080 else { 081 return String.valueOf(value); 082 } 083 } 084 085 private <K, V> String style(Map<K, V> value) { 086 if (value.isEmpty()) { 087 return EMPTY_MAP; 088 } 089 090 StringJoiner result = new StringJoiner(", ", "[", "]"); 091 for (Map.Entry<K, V> entry : value.entrySet()) { 092 result.add(style(entry)); 093 } 094 return MAP + result; 095 } 096 097 private String style(Map.Entry<?, ?> value) { 098 return style(value.getKey()) + " -> " + style(value.getValue()); 099 } 100 101 private String style(Collection<?> value) { 102 String collectionType = getCollectionTypeString(value); 103 104 if (value.isEmpty()) { 105 return collectionType + EMPTY; 106 } 107 108 StringJoiner result = new StringJoiner(", ", "[", "]"); 109 for (Object o : value) { 110 result.add(style(o)); 111 } 112 return collectionType + result; 113 } 114 115 private String getCollectionTypeString(Collection<?> value) { 116 if (value instanceof List) { 117 return LIST; 118 } 119 else if (value instanceof Set) { 120 return SET; 121 } 122 else { 123 return COLLECTION; 124 } 125 } 126 127 private String styleArray(Object[] array) { 128 if (array.length == 0) { 129 return ARRAY + '<' + ClassUtils.getShortName(array.getClass().getComponentType()) + '>' + EMPTY; 130 } 131 132 StringJoiner result = new StringJoiner(", ", "[", "]"); 133 for (Object o : array) { 134 result.add(style(o)); 135 } 136 return ARRAY + '<' + ClassUtils.getShortName(array.getClass().getComponentType()) + '>' + result; 137 } 138 139}