001/*
002 * Copyright 2002-2012 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.Iterator;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.springframework.util.ClassUtils;
027import org.springframework.util.ObjectUtils;
028
029/**
030 * Converts objects to String form, generally for debugging purposes,
031 * using Spring's {@code toString} styling conventions.
032 *
033 * <p>Uses the reflective visitor pattern underneath the hood to nicely
034 * encapsulate styling algorithms for each type of styled object.
035 *
036 * @author Keith Donald
037 * @author Juergen Hoeller
038 * @since 1.2.2
039 */
040public class DefaultValueStyler implements ValueStyler {
041
042        private static final String EMPTY = "[empty]";
043        private static final String NULL = "[null]";
044        private static final String COLLECTION = "collection";
045        private static final String SET = "set";
046        private static final String LIST = "list";
047        private static final String MAP = "map";
048        private static final String ARRAY = "array";
049
050
051        @Override
052        public String style(Object value) {
053                if (value == null) {
054                        return NULL;
055                }
056                else if (value instanceof String) {
057                        return "\'" + value + "\'";
058                }
059                else if (value instanceof Class) {
060                        return ClassUtils.getShortName((Class<?>) value);
061                }
062                else if (value instanceof Method) {
063                        Method method = (Method) value;
064                        return method.getName() + "@" + ClassUtils.getShortName(method.getDeclaringClass());
065                }
066                else if (value instanceof Map) {
067                        return style((Map<?, ?>) value);
068                }
069                else if (value instanceof Map.Entry) {
070                        return style((Map.Entry<? ,?>) value);
071                }
072                else if (value instanceof Collection) {
073                        return style((Collection<?>) value);
074                }
075                else if (value.getClass().isArray()) {
076                        return styleArray(ObjectUtils.toObjectArray(value));
077                }
078                else {
079                        return String.valueOf(value);
080                }
081        }
082
083        private <K, V> String style(Map<K, V> value) {
084                StringBuilder result = new StringBuilder(value.size() * 8 + 16);
085                result.append(MAP + "[");
086                for (Iterator<Map.Entry<K, V>> it = value.entrySet().iterator(); it.hasNext();) {
087                        Map.Entry<K, V> entry = it.next();
088                        result.append(style(entry));
089                        if (it.hasNext()) {
090                                result.append(',').append(' ');
091                        }
092                }
093                if (value.isEmpty()) {
094                        result.append(EMPTY);
095                }
096                result.append("]");
097                return result.toString();
098        }
099
100        private String style(Map.Entry<?, ?> value) {
101                return style(value.getKey()) + " -> " + style(value.getValue());
102        }
103
104        private String style(Collection<?> value) {
105                StringBuilder result = new StringBuilder(value.size() * 8 + 16);
106                result.append(getCollectionTypeString(value)).append('[');
107                for (Iterator<?> i = value.iterator(); i.hasNext();) {
108                        result.append(style(i.next()));
109                        if (i.hasNext()) {
110                                result.append(',').append(' ');
111                        }
112                }
113                if (value.isEmpty()) {
114                        result.append(EMPTY);
115                }
116                result.append("]");
117                return result.toString();
118        }
119
120        private String getCollectionTypeString(Collection<?> value) {
121                if (value instanceof List) {
122                        return LIST;
123                }
124                else if (value instanceof Set) {
125                        return SET;
126                }
127                else {
128                        return COLLECTION;
129                }
130        }
131
132        private String styleArray(Object[] array) {
133                StringBuilder result = new StringBuilder(array.length * 8 + 16);
134                result.append(ARRAY + "<").append(ClassUtils.getShortName(array.getClass().getComponentType())).append(">[");
135                for (int i = 0; i < array.length - 1; i++) {
136                        result.append(style(array[i]));
137                        result.append(',').append(' ');
138                }
139                if (array.length > 0) {
140                        result.append(style(array[array.length - 1]));
141                }
142                else {
143                        result.append(EMPTY);
144                }
145                result.append("]");
146                return result.toString();
147        }
148
149}