001: /* Objects.java
002:
003: {{IS_NOTE
004:
005: Purpose: Utilities related to Object.
006: Description:
007: History:
008: 2001/5/12, Tom M. Yeh: Created.
009:
010: }}IS_NOTE
011:
012: Copyright (C) 2001 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.lang;
020:
021: import java.math.BigDecimal;
022: import java.math.BigInteger;
023: import java.util.Date;
024: import java.util.Collection;
025: import java.lang.reflect.Method;
026: import java.rmi.MarshalledObject;
027:
028: import org.zkoss.util.ArraysX;
029: import org.zkoss.util.CollectionsX;
030: import org.zkoss.util.logging.Log;
031: import org.zkoss.text.DateFormats;
032:
033: /**
034: * Utilities related to the Object class.
035: *
036: * @author tomyeh
037: */
038: public class Objects {
039: private static final Log log = Log.lookup(Objects.class);
040:
041: /** Denotes unknown. It is useful if both null and unknown is required.
042: */
043: public static final Object UNKNOWN = new Object() { //anonymous class
044: public final String toString() {
045: return "(null)"; //a little different from null
046: }
047: };
048:
049: /** The zero long.
050: */
051: public static final Long ZERO_LONG = new Long(0L);
052: /** The zero integer.
053: */
054: public static final Integer ZERO_INTEGER = new Integer(0);
055: /** The zero short.
056: */
057: public static final Short ZERO_SHORT = new Short((short) 0);
058: /** The zero integer.
059: */
060: public static final Byte ZERO_BYTE = new Byte((byte) 0);
061: /** The zero float.
062: */
063: public static final Float ZERO_FLOAT = new Float(0F);
064: /** The zero double.
065: */
066: public static final Double ZERO_DOUBLE = new Double(0D);
067: /** Represents 0 in big decimal.
068: * The same as {@link org.zkoss.math.BigDecimals#ZERO}.
069: * @see org.zkoss.math.BigDecimals#ONE
070: */
071: public static final BigDecimal ZERO_BIG_DECIMAL = new BigDecimal(0D);
072: /** Represents 0 in big integer.
073: * Same as {@link org.zkoss.math.BigIntegers#ZERO}.
074: */
075: public static final BigInteger ZERO_BIG_INTEGER = BigInteger.ZERO;
076: /** The null character.
077: */
078: public static final Character NULL_CHARACTER = new Character(
079: '\u0000');
080:
081: /** A separator char that is from the Unicode reserved area.
082: */
083: public static final char SEPARATOR_CHAR = 0xf77a; //DON'T CHANGE IT (Or, db broke)
084: /** The second separator char that is from the Unicode reserved area.
085: */
086: public static final char SEPARATOR_CHAR2 = (char) (SEPARATOR_CHAR - 1); //DON'T CHANGE IT (Or, db broke)
087: /** A separator char that is from the Unicode reserved area.
088: */
089: public static final String SEPARATOR_STRING = "" + SEPARATOR_CHAR;
090:
091: /** The path seperator character that is used to construct a path.
092: * See org.zkoss.i3.ds.Path.
093: */
094: public static final char PATH_SEPARATOR_CHAR = '/';
095: /** The path seperator string that is used to construct a path.
096: * See org.zkoss.i3.ds.Path.
097: */
098: public static final String PATH_SEPARATOR_STRING = ""
099: + PATH_SEPARATOR_CHAR;
100:
101: /** The horizontal bar 0 (i.e., .........). */
102: public static final String BAR0_STRING = "..\t\t..............................";
103: /** The horizontal bar 1 (i.e., ---------). */
104: public static final String BAR1_STRING = "--\t\t------------------------------";
105: /** The horizontal bar 2 (i.e., =========). */
106: public static final String BAR2_STRING = "==\t\t==============================";
107:
108: /**
109: * Returns the next hash value by giving the previous one and a new one.
110: * The caller usually uses a loop to accumulate all related fields.
111: *
112: * @param prevHashVal the previous hash value returned by this method; 0
113: * if it is the first call.
114: * @param newVal the new value to put in
115: * @return the new hash value
116: */
117: public static final int nextHashCode(int prevHashVal, int newVal) {
118: return prevHashVal * 31 + newVal;
119: }
120:
121: /**
122: * Generates hash codes for an array of boolean.
123: * It is suggested to cache the hash code.
124: *
125: * @param v the array
126: * @return the hash code
127: */
128: public static final int hashCode(boolean[] v) {
129: int h = 1; //not to return 0 if possible, so caller cache it easily
130: for (int j = v.length; --j >= 0;)
131: h = nextHashCode(h, v[j] ? 1 : 0);
132: return h;
133: }
134:
135: /**
136: * Generates hash codes for an array of bytes.
137: * It is suggested to cache the hash code.
138: *
139: * @param v the array
140: * @return the hash code
141: */
142: public static final int hashCode(byte[] v) {
143: int h = 1; //not to return 0 if possible, so caller cache it easily
144: for (int j = v.length; --j >= 0;)
145: h = nextHashCode(h, v[j]);
146: return h;
147: }
148:
149: /**
150: * Generates hash codes for an array of bytes up to the specified length.
151: * It is suggested to cache the hash code.
152: *
153: * @param v the array
154: * @param len the maximal length to generate hashCode
155: * @return the hash code
156: */
157: public static final int hashCode(byte[] v, int len) {
158: int h = 1; //not to return 0 if possible, so caller cache it easily
159: if (len > v.length)
160: len = v.length;
161: for (int j = len; --j >= 0;)
162: h = nextHashCode(h, v[j]);
163: return h;
164: }
165:
166: /**
167: * Generates hash codes for an array.
168: * It is suggested to cache the hash code.
169: *
170: * @param v the array
171: * @return the hash code
172: */
173: public static final int hashCode(char[] v) {
174: int h = 1; //not to return 0 if possible, so caller cache it easily
175: for (int j = v.length; --j >= 0;)
176: h = nextHashCode(h, v[j]);
177: return h;
178: }
179:
180: /**
181: * Generates hash codes for an array.
182: * It is suggested to cache the hash code.
183: *
184: * @param v the array
185: * @return the hash code
186: */
187: public static final int hashCode(short[] v) {
188: int h = 1; //not to return 0 if possible, so caller cache it easily
189: for (int j = v.length; --j >= 0;)
190: h = nextHashCode(h, v[j]);
191: return h;
192: }
193:
194: /**
195: * Generates hash codes for an array.
196: * It is suggested to cache the hash code.
197: *
198: * @param v the byte array
199: * @return the hash code
200: */
201: public static final int hashCode(int[] v) {
202: int h = 1; //not to return 0 if possible, so caller cache it easily
203: for (int j = v.length; --j >= 0;)
204: h = nextHashCode(h, v[j]);
205: return h;
206: }
207:
208: /**
209: * Generates hash codes for an array.
210: * It is suggested to cache the hash code.
211: *
212: * @param v the array
213: * @return the hash code
214: */
215: public static final int hashCode(long[] v) {
216: int h = 1; //not to return 0 if possible, so caller cache it easily
217: for (int j = v.length; --j >= 0;) {
218: h = nextHashCode(h, (int) v[j]);
219: h = nextHashCode(h, (int) (v[j] >> 32));
220: }
221: return h;
222: }
223:
224: /** Returns the object's hash code, or zero if null. */
225: public static final int hashCode(Object o) {
226: return o == null ? 0 : o.hashCode();
227: }
228:
229: /**
230: * Tests whether two objects are equals.
231: *
232: * <p>It takes care of the null case. Thus, it is helpful to implement
233: * Object.equals.
234: *
235: * <p>Notice: it uses compareTo if BigDecimal is found. So, in this case,
236: * a.equals(b) might not be the same as Objects.equals(a, b).
237: *
238: * <p>If both a and b are Object[], they are compared item-by-item.
239: */
240: public static final boolean equals(Object a, Object b) {
241: if (a == b || (a != null && b != null && a.equals(b)))
242: return true;
243: if ((a instanceof BigDecimal) && (b instanceof BigDecimal))
244: return ((BigDecimal) a).compareTo((BigDecimal) b) == 0;
245:
246: if (a == null || !a.getClass().isArray())
247: return false;
248:
249: if ((a instanceof Object[]) && (b instanceof Object[])) {
250: final Object[] as = (Object[]) a;
251: final Object[] bs = (Object[]) b;
252: if (as.length != bs.length)
253: return false;
254: for (int j = as.length; --j >= 0;)
255: if (!equals(as[j], bs[j])) //recursive
256: return false;
257: return true;
258: }
259: if ((a instanceof int[]) && (b instanceof int[])) {
260: final int[] as = (int[]) a;
261: final int[] bs = (int[]) b;
262: if (as.length != bs.length)
263: return false;
264: for (int j = as.length; --j >= 0;)
265: if (as[j] != bs[j])
266: return false;
267: return true;
268: }
269: if ((a instanceof byte[]) && (b instanceof byte[])) {
270: final byte[] as = (byte[]) a;
271: final byte[] bs = (byte[]) b;
272: if (as.length != bs.length)
273: return false;
274: for (int j = as.length; --j >= 0;)
275: if (as[j] != bs[j])
276: return false;
277: return true;
278: }
279: if ((a instanceof char[]) && (b instanceof char[])) {
280: final char[] as = (char[]) a;
281: final char[] bs = (char[]) b;
282: if (as.length != bs.length)
283: return false;
284: for (int j = as.length; --j >= 0;)
285: if (as[j] != bs[j])
286: return false;
287: return true;
288: }
289: if ((a instanceof long[]) && (b instanceof long[])) {
290: final long[] as = (long[]) a;
291: final long[] bs = (long[]) b;
292: if (as.length != bs.length)
293: return false;
294: for (int j = as.length; --j >= 0;)
295: if (as[j] != bs[j])
296: return false;
297: return true;
298: }
299: if ((a instanceof short[]) && (b instanceof short[])) {
300: final short[] as = (short[]) a;
301: final short[] bs = (short[]) b;
302: if (as.length != bs.length)
303: return false;
304: for (int j = as.length; --j >= 0;)
305: if (as[j] != bs[j])
306: return false;
307: return true;
308: }
309: if ((a instanceof double[]) && (b instanceof double[])) {
310: final double[] as = (double[]) a;
311: final double[] bs = (double[]) b;
312: if (as.length != bs.length)
313: return false;
314: for (int j = as.length; --j >= 0;)
315: if (as[j] != bs[j])
316: return false;
317: return true;
318: }
319: if ((a instanceof float[]) && (b instanceof float[])) {
320: final float[] as = (float[]) a;
321: final float[] bs = (float[]) b;
322: if (as.length != bs.length)
323: return false;
324: for (int j = as.length; --j >= 0;)
325: if (as[j] != bs[j])
326: return false;
327: return true;
328: }
329: if ((a instanceof boolean[]) && (b instanceof boolean[])) {
330: final boolean[] as = (boolean[]) a;
331: final boolean[] bs = (boolean[]) b;
332: if (as.length != bs.length)
333: return false;
334: for (int j = as.length; --j >= 0;)
335: if (as[j] != bs[j])
336: return false;
337: return true;
338: }
339: return false;
340: }
341:
342: /**
343: * Converts any object to a character array.
344: *
345: * @param o the object to convert
346: * @return the char array or null if o is null
347: */
348: public static final char[] toCharArray(Object o) {
349: if (o == null)
350: return null;
351: if (o instanceof char[])
352: return (char[]) o;
353:
354: if (o instanceof String)
355: return ((String) o).toCharArray();
356:
357: try {
358: Method m = o.getClass().getMethod("toCharArray", null);
359: return (char[]) m.invoke(o, null);
360: } catch (Exception ex) {
361: return (o.toString()).toCharArray();
362: }
363: }
364:
365: /**
366: * Converts any object to a string.
367: * If o is an object array, it invokes {@link ArraysX#toString}
368: * to make the string more readable.
369: */
370: public static final String toString(Object o) {
371: if (o == null)
372: return null;
373: if (o instanceof Date)
374: return DateFormats.format((Date) o, false);
375: if (o instanceof Class) {
376: final Class cls = (Class) o;
377: final String clsnm = cls.getName();
378: if (!clsnm.startsWith("$Proxy"))
379: return "class " + clsnm;
380:
381: final Class[] ifs = cls.getInterfaces();
382: switch (ifs.length) {
383: case 0:
384: return "class " + clsnm;
385: case 1:
386: return "proxy " + Objects.toString(ifs[0]);
387: default:
388: return "proxy " + Objects.toString(ifs);
389: }
390: }
391: if (o.getClass().isArray()) {
392: if (o instanceof Object[])
393: return ArraysX.toString((Object[]) o);
394: if (o instanceof int[])
395: return ArraysX.toString((int[]) o);
396: if (o instanceof short[])
397: return ArraysX.toString((short[]) o);
398: if (o instanceof long[])
399: return ArraysX.toString((long[]) o);
400: if (o instanceof double[])
401: return ArraysX.toString((double[]) o);
402: if (o instanceof byte[])
403: return ArraysX.toString((byte[]) o);
404: if (o instanceof boolean[])
405: return ArraysX.toString((boolean[]) o);
406: if (o instanceof char[])
407: return ArraysX.toString((char[]) o);
408: if (o instanceof float[])
409: return ArraysX.toString((float[]) o);
410: }
411: return o.toString();
412: }
413:
414: /** Converts an integer to a big-endian byte array.
415: */
416: public static final byte[] toByteArray(int v) {
417: return new byte[] { (byte) (v >>> 24), (byte) (v >>> 16),
418: (byte) (v >>> 8), (byte) v };
419: }
420:
421: /** Converts a long to a big-endian byte array.
422: */
423: public static final byte[] toByteArray(long v) {
424: return new byte[] { (byte) (v >>> 56), (byte) (v >>> 48),
425: (byte) (v >>> 40), (byte) (v >>> 32),
426: (byte) (v >>> 24), (byte) (v >>> 16), (byte) (v >>> 8),
427: (byte) v };
428: }
429:
430: /** Converts a short to a big-endian byte array.
431: */
432: public static final byte[] toByteArray(short v) {
433: return new byte[] { (byte) (v >>> 8), (byte) v };
434: }
435:
436: /** Converts a byte to a big-endian byte array.
437: */
438: public static final byte[] toByteArray(byte v) {
439: return new byte[] { v };
440: }
441:
442: /**
443: * Clones the specified object. Use clone() if Cloeable.
444: * Otherwise, try to serialize/deserialize it by use of MarshalledObject.
445: *
446: * <p>If o is null, null is returned.
447: *
448: * @exception SystemException if failed to clone
449: */
450: public static final Object clone(Object o) {
451: if (o == null)
452: return o;
453:
454: try {
455: final Class kls = o.getClass();
456: if (kls.isArray())
457: return ArraysX.clone(o);
458:
459: if (o instanceof Cloneable) {
460: try {
461: return kls.getMethod("clone", null).invoke(o, null);
462: } catch (NoSuchMethodException ex) {
463: if (D.ON)
464: log.warning("No clone() for " + kls);
465: }
466: }
467:
468: //:TODO: MarshalledObject is said with very bad performance, change it
469: //if exists other good deep clone method.
470: return new MarshalledObject(o).get();
471: } catch (Exception ex) {
472: throw SystemException.Aide.wrap(ex);
473: }
474: }
475: }
|