View Javadoc

1   /*
2    * Copyright 2004-2005, 2007 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at
7    * 
8    * http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package net.sf.composite.util;
17  
18  import java.lang.reflect.Array;
19  import java.util.ArrayList;
20  import java.util.Calendar;
21  import java.util.Collection;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Stack;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  
29  /***
30   * @author Matt Sgarlata
31   * @since Mar 11, 2005
32   */
33  public class ObjectUtils {
34  
35  	private static final Log log = LogFactory.getLog(ObjectUtils.class);
36  
37  	private static ThreadLocal objectsBeingDescribed = new ThreadLocal() {
38  		protected Object initialValue() {
39  			return new IdentityStack();
40  		}
41  	};
42  
43  	public static String getObjectDescription(Object object) {
44  		if (object == null) {
45  			return "null";
46  		}
47  
48  		try {
49  			// for Calendar objects, convert them to Date objects and then do the
50  			// toString call, because Calendar objects have an awful toString method
51  			if (object instanceof Calendar) {
52  				return ((Calendar) object).getTime().toString() + " (class " + object.getClass() + ")";
53  			}
54  			if (object instanceof Class && ((Class) object).isArray()) {
55  				return "(array of " + getObjectDescription(ClassUtils.getContainedClass((Class) object)) + ")";
56  			}
57  			if (object instanceof Class) {
58  				return "(" + object.toString() + ")";
59  			}
60  			if (object.getClass().isArray()) {
61  				return getArrayDescription(object)
62  					+ " "
63  					+ getObjectDescription(object.getClass());
64  			}
65  			// Prevent StackOverflowError
66  			Stack stack = (Stack) objectsBeingDescribed.get();
67  			if (stack.contains(object)) {
68  				// Already has been described in this control flow, so don't call its toString() method a second time (it was called on the first occasion)
69  				return getDelimiter(object) + "Nested" + object.getClass().getName();
70  			}
71  			// Object hasn't been described before, so use its toString() method, but prevent any nested calls to this method (via toString()) from repeating the invocation
72  			stack.push(object);
73  			String result;
74  			try {
75  				result = getDelimiter(object) + object + getDelimiter(object) + " (class " + object.getClass().getName() + ")";
76  			} finally {
77  				if (object != stack.pop()) {
78  					throw new IllegalStateException("Unexpected " + object.getClass().getName());
79  				}
80  			}
81  			return result;
82  		}
83  		catch (Throwable t) {
84  			// note we don't call object.toString() because that could call an infinite loop
85  			String message = "Could not construct String representation of instance of '"
86  					+ object.getClass().getName() + "'";
87  			if (log.isErrorEnabled()) {
88  				log.error(message, t);
89  			}
90  			return "[ERROR: " + message + "'.  Exception message was '"
91  					+ t.getMessage() + "']";
92  		}
93  	}
94  
95  	private static String getArrayDescription(Object array) {
96  		List toJoin = new ArrayList();
97  		for (int i=0; i<Array.getLength(array); i++) {
98  			Object value = Array.get(array, i);
99  			if (value != null && value.getClass().isArray()) {
100 				toJoin.add(getArrayDescription(value));
101 			}
102 			else {
103 				toJoin.add(value);
104 			}
105 		}
106 		return "[" + StringUtils.join(toJoin, ", ") + "]";
107 	}
108 
109 	private static String getDelimiter(Object object) {
110 		return object instanceof Character ? "'" : object instanceof String ? "\"" : "";
111 	}
112 
113 	public static boolean isEmpty(Object object) {
114 		return object == null || "".equals(object)
115 				|| object.getClass().isArray() && Array.getLength(object) == 0
116 				|| object instanceof Collection && ((Collection) object).isEmpty()
117 				|| object instanceof Map && ((Map) object).isEmpty()
118 				|| object instanceof StringBuffer && ((StringBuffer) object).length() == 0;
119 	}
120 
121 	/***
122 	 * Compares two objects for equality.  This method is safe to use when
123 	 * dealing with the standard Java notion of equality that involves only
124 	 * {@link Object#equals(java.lang.Object)}.
125 	 *
126 	 * @param object1 the first object
127 	 * @param object2 the second object
128 	 * @return <code>true</code> if (A) <code>object1</code> and
129 	 *         <code>object2</code> are both <code>null</code> or (B)
130 	 *         <code>object1</code> and <code>object2</code> are both are
131 	 *         both non- <code>null</code> and equal to each other as defined
132 	 *         by {@link Object#equals(java.lang.Object)} or (C) the objects are
133 	 *         <code>BigDecimal</code> s that contain identical values or <br>
134 	 *         <code>false</code>, otherwise
135 	 */
136 	public static boolean equals(Object object1, Object object2) {
137 		return object1 == object2 || (object1 != null && object1.equals(object2));
138 	}
139 
140 }