src/share/classes/com/sun/corba/se/impl/orbutil/ObjectUtility.java

Mon, 14 Jun 2010 11:28:53 -0700

author
jjg
date
Mon, 14 Jun 2010 11:28:53 -0700
changeset 173
032585ad970d
parent 158
91006f157c46
child 205
b2fff4b7e8cd
permissions
-rw-r--r--

6960831: fix CORBA build warnings
Reviewed-by: darcy

duke@1 1 /*
ohair@158 2 * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
ohair@158 7 * published by the Free Software Foundation. Oracle designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
ohair@158 9 * by Oracle in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
ohair@158 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@158 22 * or visit www.oracle.com if you need additional information or have any
ohair@158 23 * questions.
duke@1 24 */
duke@1 25
duke@1 26 package com.sun.corba.se.impl.orbutil;
duke@1 27
duke@1 28 import java.security.PrivilegedAction;
duke@1 29 import java.security.AccessController;
duke@1 30 import java.util.ArrayList;
duke@1 31 import java.util.Arrays;
duke@1 32 import java.util.Map;
duke@1 33 import java.util.List;
duke@1 34 import java.util.ListIterator;
duke@1 35 import java.util.Set;
duke@1 36 import java.util.Map.Entry;
duke@1 37 import java.util.Collection;
duke@1 38 import java.util.HashMap;
duke@1 39 import java.util.HashSet;
duke@1 40 import java.util.Hashtable;
duke@1 41 import java.util.Iterator;
duke@1 42 import java.util.Enumeration;
duke@1 43 import java.util.Properties;
duke@1 44 import java.util.IdentityHashMap;
duke@1 45 import java.lang.reflect.Array;
duke@1 46 import java.lang.reflect.Field;
duke@1 47 import java.lang.reflect.Method;
duke@1 48 import java.lang.reflect.Modifier;
duke@1 49 import java.math.BigInteger ;
duke@1 50 import java.math.BigDecimal ;
duke@1 51
duke@1 52 public final class ObjectUtility {
duke@1 53 private boolean useToString ;
duke@1 54 private boolean isIndenting ;
duke@1 55 private int initialLevel ;
duke@1 56 private int increment ;
duke@1 57 private ClassMap classToPrinter = new ClassMap() ;
duke@1 58
duke@1 59 private static ObjectUtility standard = new ObjectUtility( false, true,
duke@1 60 0, 4 ) ;
duke@1 61 private static ObjectUtility compact = new ObjectUtility( true, false,
duke@1 62 0, 4 ) ;
duke@1 63
duke@1 64 private ObjectUtility( boolean useToString, boolean isIndenting,
duke@1 65 int initialLevel, int increment )
duke@1 66 {
duke@1 67 this.useToString = useToString ;
duke@1 68 this.isIndenting = isIndenting ;
duke@1 69 this.initialLevel = initialLevel ;
duke@1 70 this.increment = increment ;
duke@1 71 classToPrinter.put( Properties.class, propertiesPrinter ) ;
duke@1 72 classToPrinter.put( Collection.class, collectionPrinter ) ;
duke@1 73 classToPrinter.put( Map.class, mapPrinter ) ;
duke@1 74 }
duke@1 75
duke@1 76 /** Construct an Utility instance with the desired objectToString
duke@1 77 * behavior.
duke@1 78 */
duke@1 79 public static ObjectUtility make( boolean useToString, boolean isIndenting,
duke@1 80 int initialLevel, int increment )
duke@1 81 {
duke@1 82 return new ObjectUtility( useToString, isIndenting, initialLevel,
duke@1 83 increment ) ;
duke@1 84 }
duke@1 85
duke@1 86 /** Construct an Utility instance with the desired objectToString
duke@1 87 * behavior.
duke@1 88 */
duke@1 89 public static ObjectUtility make( boolean useToString, boolean isIndenting )
duke@1 90 {
duke@1 91 return new ObjectUtility( useToString, isIndenting, 0, 4 ) ;
duke@1 92 }
duke@1 93
duke@1 94 /** Get the standard Utility object that supports objectToString with
duke@1 95 * indented display and no use of toString() methods.
duke@1 96 */
duke@1 97 public static ObjectUtility make()
duke@1 98 {
duke@1 99 return standard ;
duke@1 100 }
duke@1 101
duke@1 102 /** A convenience method that gives the default behavior: use indenting
duke@1 103 * to display the object's structure and do not use built-in toString
duke@1 104 * methods.
duke@1 105 */
duke@1 106 public static String defaultObjectToString( java.lang.Object object )
duke@1 107 {
duke@1 108 return standard.objectToString( object ) ;
duke@1 109 }
duke@1 110
duke@1 111 public static String compactObjectToString( java.lang.Object object )
duke@1 112 {
duke@1 113 return compact.objectToString( object ) ;
duke@1 114 }
duke@1 115
duke@1 116 /** objectToString handles display of arbitrary objects. It correctly
duke@1 117 * handles objects whose elements form an arbitrary graph. It uses
duke@1 118 * reflection to display the contents of any kind of object.
duke@1 119 * An object's toString() method may optionally be used, but the default
duke@1 120 * is to ignore all toString() methods except for those defined for
duke@1 121 * primitive types, primitive type wrappers, and strings.
duke@1 122 */
duke@1 123 public String objectToString(java.lang.Object obj)
duke@1 124 {
duke@1 125 IdentityHashMap printed = new IdentityHashMap() ;
duke@1 126 ObjectWriter result = ObjectWriter.make( isIndenting, initialLevel,
duke@1 127 increment ) ;
duke@1 128 objectToStringHelper( printed, result, obj ) ;
duke@1 129 return result.toString() ;
duke@1 130 }
duke@1 131
duke@1 132 // Perform a deep structural equality comparison of the two objects.
duke@1 133 // This handles all arrays, maps, and sets specially, otherwise
duke@1 134 // it just calls the object's equals() method.
duke@1 135 public static boolean equals( java.lang.Object obj1, java.lang.Object obj2 )
duke@1 136 {
duke@1 137 // Set of pairs of objects that have been (or are being) considered for
duke@1 138 // equality. Such pairs are presumed to be equals. If they are not,
duke@1 139 // this will be detected eventually and the equals method will return
duke@1 140 // false.
duke@1 141 Set considered = new HashSet() ;
duke@1 142
duke@1 143 // Map that gives the corresponding component of obj2 for a component
duke@1 144 // of obj1. This is used to check for the same aliasing and use of
duke@1 145 // equal objects in both objects.
duke@1 146 Map counterpart = new IdentityHashMap() ;
duke@1 147
duke@1 148 return equalsHelper( counterpart, considered, obj1, obj2 ) ;
duke@1 149 }
duke@1 150
duke@1 151 /** If arr1 and arr2 are both arrays of the same component type,
duke@1 152 * return an array of that component type that consists of the
duke@1 153 * elements of arr1 followed by the elements of arr2.
duke@1 154 * Throws IllegalArgumentException otherwise.
duke@1 155 */
duke@1 156 public static Object concatenateArrays( Object arr1, Object arr2 )
duke@1 157 {
duke@1 158 Class comp1 = arr1.getClass().getComponentType() ;
duke@1 159 Class comp2 = arr2.getClass().getComponentType() ;
duke@1 160 int len1 = Array.getLength( arr1 ) ;
duke@1 161 int len2 = Array.getLength( arr2 ) ;
duke@1 162
duke@1 163 if ((comp1 == null) || (comp2 == null))
duke@1 164 throw new IllegalStateException( "Arguments must be arrays" ) ;
duke@1 165 if (!comp1.equals( comp2 ))
duke@1 166 throw new IllegalStateException(
duke@1 167 "Arguments must be arrays with the same component type" ) ;
duke@1 168
duke@1 169 Object result = Array.newInstance( comp1, len1 + len2 ) ;
duke@1 170
duke@1 171 int index = 0 ;
duke@1 172
duke@1 173 for (int ctr=0; ctr<len1; ctr++)
duke@1 174 Array.set( result, index++, Array.get( arr1, ctr ) ) ;
duke@1 175
duke@1 176 for (int ctr=0; ctr<len2; ctr++)
duke@1 177 Array.set( result, index++, Array.get( arr2, ctr ) ) ;
duke@1 178
duke@1 179 return result ;
duke@1 180 }
duke@1 181
duke@1 182 //===========================================================================
duke@1 183 // Implementation
duke@1 184 //===========================================================================
duke@1 185
duke@1 186 private void objectToStringHelper( IdentityHashMap printed,
duke@1 187 ObjectWriter result, java.lang.Object obj)
duke@1 188 {
duke@1 189 if (obj==null) {
duke@1 190 result.append( "null" ) ;
duke@1 191 result.endElement() ;
duke@1 192 } else {
duke@1 193 Class cls = obj.getClass() ;
duke@1 194 result.startObject( obj ) ;
duke@1 195
duke@1 196 if (printed.keySet().contains( obj )) {
duke@1 197 result.endObject( "*VISITED*" ) ;
duke@1 198 } else {
duke@1 199 printed.put( obj, null ) ;
duke@1 200
duke@1 201 if (mustUseToString(cls)) {
duke@1 202 result.endObject( obj.toString() ) ;
duke@1 203 } else {
duke@1 204 // First, handle any classes that have special printer
duke@1 205 // methods defined. This is useful when the class
duke@1 206 // overrides toString with something that
duke@1 207 // is not sufficiently detailed.
duke@1 208 ObjectPrinter printer = (ObjectPrinter)(classToPrinter.get(
duke@1 209 cls )) ;
duke@1 210 if (printer != null) {
duke@1 211 printer.print( printed, result, obj ) ;
duke@1 212 result.endObject() ;
duke@1 213 } else {
duke@1 214 Class compClass = cls.getComponentType() ;
duke@1 215
duke@1 216 if (compClass == null)
duke@1 217 // handleObject always calls endObject
duke@1 218 handleObject( printed, result, obj ) ;
duke@1 219 else {
duke@1 220 handleArray( printed, result, obj ) ;
duke@1 221 result.endObject() ;
duke@1 222 }
duke@1 223 }
duke@1 224 }
duke@1 225 }
duke@1 226 }
duke@1 227 }
duke@1 228
duke@1 229 private static interface ObjectPrinter {
duke@1 230 void print( IdentityHashMap printed, ObjectWriter buff,
duke@1 231 java.lang.Object obj ) ;
duke@1 232 }
duke@1 233
duke@1 234 private ObjectPrinter propertiesPrinter = new ObjectPrinter() {
duke@1 235 public void print( IdentityHashMap printed, ObjectWriter buff,
duke@1 236 java.lang.Object obj )
duke@1 237 {
duke@1 238 if (!(obj instanceof Properties))
duke@1 239 throw new Error() ;
duke@1 240
duke@1 241 Properties props = (Properties)obj ;
duke@1 242 Enumeration keys = props.propertyNames() ;
duke@1 243 while (keys.hasMoreElements()) {
duke@1 244 String key = (String)(keys.nextElement()) ;
duke@1 245 String value = props.getProperty( key ) ;
duke@1 246 buff.startElement() ;
duke@1 247 buff.append( key ) ;
duke@1 248 buff.append( "=" ) ;
duke@1 249 buff.append( value ) ;
duke@1 250 buff.endElement() ;
duke@1 251 }
duke@1 252 }
duke@1 253 } ;
duke@1 254
duke@1 255 private ObjectPrinter collectionPrinter = new ObjectPrinter() {
duke@1 256 public void print( IdentityHashMap printed, ObjectWriter buff,
duke@1 257 java.lang.Object obj )
duke@1 258 {
duke@1 259 if (!(obj instanceof Collection))
duke@1 260 throw new Error() ;
duke@1 261
duke@1 262 Collection coll = (Collection)obj ;
duke@1 263 Iterator iter = coll.iterator() ;
duke@1 264 while (iter.hasNext()) {
duke@1 265 java.lang.Object element = iter.next() ;
duke@1 266 buff.startElement() ;
duke@1 267 objectToStringHelper( printed, buff, element ) ;
duke@1 268 buff.endElement() ;
duke@1 269 }
duke@1 270 }
duke@1 271 } ;
duke@1 272
duke@1 273 private ObjectPrinter mapPrinter = new ObjectPrinter() {
duke@1 274 public void print( IdentityHashMap printed, ObjectWriter buff,
duke@1 275 java.lang.Object obj )
duke@1 276 {
duke@1 277 if (!(obj instanceof Map))
duke@1 278 throw new Error() ;
duke@1 279
duke@1 280 Map map = (Map)obj ;
duke@1 281 Iterator iter = map.entrySet().iterator() ;
duke@1 282 while (iter.hasNext()) {
duke@1 283 Entry entry = (Entry)(iter.next()) ;
duke@1 284 buff.startElement() ;
duke@1 285 objectToStringHelper( printed, buff, entry.getKey() ) ;
duke@1 286 buff.append( "=>" ) ;
duke@1 287 objectToStringHelper( printed, buff, entry.getValue() ) ;
duke@1 288 buff.endElement() ;
duke@1 289 }
duke@1 290 }
duke@1 291 } ;
duke@1 292
duke@1 293 private static class ClassMap {
duke@1 294 ArrayList data ;
duke@1 295
duke@1 296 public ClassMap()
duke@1 297 {
duke@1 298 data = new ArrayList() ;
duke@1 299 }
duke@1 300
duke@1 301 /** Return the first element of the ClassMap that is assignable to cls.
duke@1 302 * The order is determined by the order in which the put method was
duke@1 303 * called. Returns null if there is no match.
duke@1 304 */
duke@1 305 public java.lang.Object get( Class cls )
duke@1 306 {
duke@1 307 Iterator iter = data.iterator() ;
duke@1 308 while (iter.hasNext()) {
duke@1 309 java.lang.Object[] arr = (java.lang.Object[])(iter.next()) ;
duke@1 310 Class key = (Class)(arr[0]) ;
duke@1 311 if (key.isAssignableFrom( cls ))
duke@1 312 return arr[1] ;
duke@1 313 }
duke@1 314
duke@1 315 return null ;
duke@1 316 }
duke@1 317
duke@1 318 /** Add obj to the map with key cls. Note that order matters,
duke@1 319 * as the first match is returned.
duke@1 320 */
duke@1 321 public void put( Class cls, java.lang.Object obj )
duke@1 322 {
duke@1 323 java.lang.Object[] pair = { cls, obj } ;
duke@1 324 data.add( pair ) ;
duke@1 325 }
duke@1 326 }
duke@1 327
duke@1 328 private boolean mustUseToString( Class cls )
duke@1 329 {
duke@1 330 // These probably never occur
duke@1 331 if (cls.isPrimitive())
duke@1 332 return true ;
duke@1 333
duke@1 334 // We must use toString for all primitive wrappers, since
duke@1 335 // otherwise the code recurses endlessly (access value field
duke@1 336 // inside Integer, returns another Integer through reflection).
duke@1 337 if ((cls == Integer.class) ||
duke@1 338 (cls == BigInteger.class) ||
duke@1 339 (cls == BigDecimal.class) ||
duke@1 340 (cls == String.class) ||
duke@1 341 (cls == StringBuffer.class) ||
duke@1 342 (cls == Long.class) ||
duke@1 343 (cls == Short.class) ||
duke@1 344 (cls == Byte.class) ||
duke@1 345 (cls == Character.class) ||
duke@1 346 (cls == Float.class) ||
duke@1 347 (cls == Double.class) ||
duke@1 348 (cls == Boolean.class))
duke@1 349 return true ;
duke@1 350
duke@1 351 if (useToString) {
duke@1 352 try {
jjg@173 353 cls.getDeclaredMethod( "toString", (Class[])null ) ;
duke@1 354 return true ;
duke@1 355 } catch (Exception exc) {
duke@1 356 return false ;
duke@1 357 }
duke@1 358 }
duke@1 359
duke@1 360 return false ;
duke@1 361 }
duke@1 362
duke@1 363 private void handleObject( IdentityHashMap printed, ObjectWriter result,
duke@1 364 java.lang.Object obj )
duke@1 365 {
duke@1 366 Class cls = obj.getClass() ;
duke@1 367
duke@1 368 try {
duke@1 369 Field[] fields;
duke@1 370 SecurityManager security = System.getSecurityManager();
duke@1 371 if (security != null && !Modifier.isPublic(cls.getModifiers())) {
duke@1 372 fields = new Field[0];
duke@1 373 } else {
duke@1 374 fields = cls.getDeclaredFields();
duke@1 375 }
duke@1 376
duke@1 377 for (int ctr=0; ctr<fields.length; ctr++ ) {
duke@1 378 final Field fld = fields[ctr] ;
duke@1 379 int modifiers = fld.getModifiers() ;
duke@1 380
duke@1 381 // Do not display field if it is static, since these fields
duke@1 382 // are always the same for every instances. This could
duke@1 383 // be made configurable, but I don't think it is
duke@1 384 // useful to do so.
duke@1 385 if (!Modifier.isStatic( modifiers )) {
duke@1 386 if (security != null) {
duke@1 387 if (!Modifier.isPublic(modifiers))
duke@1 388 continue;
duke@1 389 }
duke@1 390 result.startElement() ;
duke@1 391 result.append( fld.getName() ) ;
duke@1 392 result.append( ":" ) ;
duke@1 393
duke@1 394 try {
duke@1 395 // Make sure that we can read the field if it is
duke@1 396 // not public
duke@1 397 AccessController.doPrivileged( new PrivilegedAction() {
duke@1 398 public Object run() {
duke@1 399 fld.setAccessible( true ) ;
duke@1 400 return null ;
duke@1 401 }
duke@1 402 } ) ;
duke@1 403
duke@1 404 java.lang.Object value = fld.get( obj ) ;
duke@1 405 objectToStringHelper( printed, result, value ) ;
duke@1 406 } catch (Exception exc2) {
duke@1 407 result.append( "???" ) ;
duke@1 408 }
duke@1 409
duke@1 410 result.endElement() ;
duke@1 411 }
duke@1 412 }
duke@1 413
duke@1 414 result.endObject() ;
duke@1 415 } catch (Exception exc2) {
duke@1 416 result.endObject( obj.toString() ) ;
duke@1 417 }
duke@1 418 }
duke@1 419
duke@1 420 private void handleArray( IdentityHashMap printed, ObjectWriter result,
duke@1 421 java.lang.Object obj )
duke@1 422 {
duke@1 423 Class compClass = obj.getClass().getComponentType() ;
duke@1 424 if (compClass == boolean.class) {
duke@1 425 boolean[] arr = (boolean[])obj ;
duke@1 426 for (int ctr=0; ctr<arr.length; ctr++) {
duke@1 427 result.startElement() ;
duke@1 428 result.append( arr[ctr] ) ;
duke@1 429 result.endElement() ;
duke@1 430 }
duke@1 431 } else if (compClass == byte.class) {
duke@1 432 byte[] arr = (byte[])obj ;
duke@1 433 for (int ctr=0; ctr<arr.length; ctr++) {
duke@1 434 result.startElement() ;
duke@1 435 result.append( arr[ctr] ) ;
duke@1 436 result.endElement() ;
duke@1 437 }
duke@1 438 } else if (compClass == short.class) {
duke@1 439 short[] arr = (short[])obj ;
duke@1 440 for (int ctr=0; ctr<arr.length; ctr++) {
duke@1 441 result.startElement() ;
duke@1 442 result.append( arr[ctr] ) ;
duke@1 443 result.endElement() ;
duke@1 444 }
duke@1 445 } else if (compClass == int.class) {
duke@1 446 int[] arr = (int[])obj ;
duke@1 447 for (int ctr=0; ctr<arr.length; ctr++) {
duke@1 448 result.startElement() ;
duke@1 449 result.append( arr[ctr] ) ;
duke@1 450 result.endElement() ;
duke@1 451 }
duke@1 452 } else if (compClass == long.class) {
duke@1 453 long[] arr = (long[])obj ;
duke@1 454 for (int ctr=0; ctr<arr.length; ctr++) {
duke@1 455 result.startElement() ;
duke@1 456 result.append( arr[ctr] ) ;
duke@1 457 result.endElement() ;
duke@1 458 }
duke@1 459 } else if (compClass == char.class) {
duke@1 460 char[] arr = (char[])obj ;
duke@1 461 for (int ctr=0; ctr<arr.length; ctr++) {
duke@1 462 result.startElement() ;
duke@1 463 result.append( arr[ctr] ) ;
duke@1 464 result.endElement() ;
duke@1 465 }
duke@1 466 } else if (compClass == float.class) {
duke@1 467 float[] arr = (float[])obj ;
duke@1 468 for (int ctr=0; ctr<arr.length; ctr++) {
duke@1 469 result.startElement() ;
duke@1 470 result.append( arr[ctr] ) ;
duke@1 471 result.endElement() ;
duke@1 472 }
duke@1 473 } else if (compClass == double.class) {
duke@1 474 double[] arr = (double[])obj ;
duke@1 475 for (int ctr=0; ctr<arr.length; ctr++) {
duke@1 476 result.startElement() ;
duke@1 477 result.append( arr[ctr] ) ;
duke@1 478 result.endElement() ;
duke@1 479 }
duke@1 480 } else { // array of object
duke@1 481 java.lang.Object[] arr = (java.lang.Object[])obj ;
duke@1 482 for (int ctr=0; ctr<arr.length; ctr++) {
duke@1 483 result.startElement() ;
duke@1 484 objectToStringHelper( printed, result, arr[ctr] ) ;
duke@1 485 result.endElement() ;
duke@1 486 }
duke@1 487 }
duke@1 488 }
duke@1 489
duke@1 490 private static class Pair
duke@1 491 {
duke@1 492 private java.lang.Object obj1 ;
duke@1 493 private java.lang.Object obj2 ;
duke@1 494
duke@1 495 Pair( java.lang.Object obj1, java.lang.Object obj2 )
duke@1 496 {
duke@1 497 this.obj1 = obj1 ;
duke@1 498 this.obj2 = obj2 ;
duke@1 499 }
duke@1 500
duke@1 501 public boolean equals( java.lang.Object obj )
duke@1 502 {
duke@1 503 if (!(obj instanceof Pair))
duke@1 504 return false ;
duke@1 505
duke@1 506 Pair other = (Pair)obj ;
duke@1 507 return other.obj1 == obj1 && other.obj2 == obj2 ;
duke@1 508 }
duke@1 509
duke@1 510 public int hashCode()
duke@1 511 {
duke@1 512 return System.identityHashCode( obj1 ) ^
duke@1 513 System.identityHashCode( obj2 ) ;
duke@1 514 }
duke@1 515 }
duke@1 516
duke@1 517 private static boolean equalsHelper( Map counterpart, Set considered,
duke@1 518 java.lang.Object obj1, java.lang.Object obj2 )
duke@1 519 {
duke@1 520 if ((obj1 == null) || (obj2 == null))
duke@1 521 return obj1 == obj2 ;
duke@1 522
duke@1 523 java.lang.Object other2 = counterpart.get( obj1 ) ;
duke@1 524 if (other2 == null) {
duke@1 525 other2 = obj2 ;
duke@1 526 counterpart.put( obj1, other2 ) ;
duke@1 527 }
duke@1 528
duke@1 529 if (obj1 == other2)
duke@1 530 return true ;
duke@1 531
duke@1 532 if (obj2 != other2)
duke@1 533 return false ;
duke@1 534
duke@1 535 Pair pair = new Pair( obj1, obj2 ) ;
duke@1 536 if (considered.contains( pair ))
duke@1 537 return true ;
duke@1 538 else
duke@1 539 considered.add( pair ) ;
duke@1 540
duke@1 541 if (obj1 instanceof java.lang.Object[] &&
duke@1 542 obj2 instanceof java.lang.Object[])
duke@1 543 return equalArrays( counterpart, considered,
duke@1 544 (java.lang.Object[])obj1, (java.lang.Object[])obj2 ) ;
duke@1 545 else if (obj1 instanceof Map && obj2 instanceof Map)
duke@1 546 return equalMaps( counterpart, considered,
duke@1 547 (Map)obj1, (Map)obj2 ) ;
duke@1 548 else if (obj1 instanceof Set && obj2 instanceof Set)
duke@1 549 return equalSets( counterpart, considered,
duke@1 550 (Set)obj1, (Set)obj2 ) ;
duke@1 551 else if (obj1 instanceof List && obj2 instanceof List)
duke@1 552 return equalLists( counterpart, considered,
duke@1 553 (List)obj1, (List)obj2 ) ;
duke@1 554 else if (obj1 instanceof boolean[] && obj2 instanceof boolean[])
duke@1 555 return Arrays.equals( (boolean[])obj1, (boolean[])obj2 ) ;
duke@1 556 else if (obj1 instanceof byte[] && obj2 instanceof byte[])
duke@1 557 return Arrays.equals( (byte[])obj1, (byte[])obj2 ) ;
duke@1 558 else if (obj1 instanceof char[] && obj2 instanceof char[])
duke@1 559 return Arrays.equals( (char[])obj1, (char[])obj2 ) ;
duke@1 560 else if (obj1 instanceof double[] && obj2 instanceof double[])
duke@1 561 return Arrays.equals( (double[])obj1, (double[])obj2 ) ;
duke@1 562 else if (obj1 instanceof float[] && obj2 instanceof float[])
duke@1 563 return Arrays.equals( (float[])obj1, (float[])obj2 ) ;
duke@1 564 else if (obj1 instanceof int[] && obj2 instanceof int[])
duke@1 565 return Arrays.equals( (int[])obj1, (int[])obj2 ) ;
duke@1 566 else if (obj1 instanceof long[] && obj2 instanceof long[])
duke@1 567 return Arrays.equals( (long[])obj1, (long[])obj2 ) ;
duke@1 568 else {
duke@1 569 Class cls = obj1.getClass() ;
duke@1 570 if (cls != obj2.getClass())
duke@1 571 return obj1.equals( obj2 ) ;
duke@1 572 else
duke@1 573 return equalsObject( counterpart, considered, cls, obj1, obj2 ) ;
duke@1 574 }
duke@1 575 }
duke@1 576
duke@1 577 private static boolean equalsObject( Map counterpart, Set considered,
duke@1 578 Class cls, java.lang.Object obj1, java.lang.Object obj2 )
duke@1 579 {
duke@1 580 Class objectClass = java.lang.Object.class ;
duke@1 581 if (cls == objectClass)
duke@1 582 return true ;
duke@1 583
duke@1 584 Class[] equalsTypes = { objectClass } ;
duke@1 585 try {
duke@1 586 Method equalsMethod = cls.getDeclaredMethod( "equals",
duke@1 587 equalsTypes ) ;
duke@1 588 return obj1.equals( obj2 ) ;
duke@1 589 } catch (Exception exc) {
duke@1 590 if (equalsObjectFields( counterpart, considered,
duke@1 591 cls, obj1, obj2 ))
duke@1 592 return equalsObject( counterpart, considered,
duke@1 593 cls.getSuperclass(), obj1, obj2 ) ;
duke@1 594 else
duke@1 595 return false ;
duke@1 596 }
duke@1 597 }
duke@1 598
duke@1 599 private static boolean equalsObjectFields( Map counterpart, Set considered,
duke@1 600 Class cls, java.lang.Object obj1, java.lang.Object obj2 )
duke@1 601 {
duke@1 602 Field[] fields = cls.getDeclaredFields() ;
duke@1 603 for (int ctr=0; ctr<fields.length; ctr++) {
duke@1 604 try {
duke@1 605 final Field field = fields[ctr] ;
duke@1 606 // Ignore static fields
duke@1 607 if (!Modifier.isStatic( field.getModifiers())) {
duke@1 608 AccessController.doPrivileged(new PrivilegedAction() {
duke@1 609 public Object run() {
duke@1 610 field.setAccessible( true ) ;
duke@1 611 return null ;
duke@1 612 }
duke@1 613 } ) ;
duke@1 614
duke@1 615 java.lang.Object value1 = field.get( obj1 ) ;
duke@1 616 java.lang.Object value2 = field.get( obj2 ) ;
duke@1 617 if (!equalsHelper( counterpart, considered, value1,
duke@1 618 value2 ))
duke@1 619 return false ;
duke@1 620 }
duke@1 621 } catch (IllegalAccessException exc) {
duke@1 622 return false ;
duke@1 623 }
duke@1 624 }
duke@1 625
duke@1 626 return true ;
duke@1 627 }
duke@1 628
duke@1 629 private static boolean equalArrays( Map counterpart, Set considered,
duke@1 630 java.lang.Object[] arr1, java.lang.Object[] arr2 )
duke@1 631 {
duke@1 632 int len = arr1.length ;
duke@1 633 if (len != arr2.length)
duke@1 634 return false ;
duke@1 635
duke@1 636 for (int ctr = 0; ctr<len; ctr++ )
duke@1 637 if (!equalsHelper( counterpart, considered, arr1[ctr], arr2[ctr] ))
duke@1 638 return false ;
duke@1 639
duke@1 640 return true ;
duke@1 641 }
duke@1 642
duke@1 643 private static boolean equalMaps( Map counterpart, Set considered,
duke@1 644 Map map1, Map map2 )
duke@1 645 {
duke@1 646 if (map2.size() != map1.size())
duke@1 647 return false;
duke@1 648
duke@1 649 try {
duke@1 650 Iterator i = map1.entrySet().iterator();
duke@1 651 while (i.hasNext()) {
duke@1 652 Entry e = (Entry) i.next();
duke@1 653 java.lang.Object key = e.getKey();
duke@1 654 java.lang.Object value = e.getValue();
duke@1 655 if (value == null) {
duke@1 656 if (!(map2.get(key)==null && map2.containsKey(key)))
duke@1 657 return false;
duke@1 658 } else {
duke@1 659 if (!equalsHelper( counterpart, considered,
duke@1 660 value, map2.get(key)))
duke@1 661 return false;
duke@1 662 }
duke@1 663 }
duke@1 664 } catch(ClassCastException unused) {
duke@1 665 return false;
duke@1 666 } catch(NullPointerException unused) {
duke@1 667 return false;
duke@1 668 }
duke@1 669
duke@1 670 return true;
duke@1 671 }
duke@1 672
duke@1 673 // Obviously this is an inefficient quadratic algorithm.
duke@1 674 // This is taken pretty directly from AbstractSet and AbstractCollection
duke@1 675 // in the JDK.
duke@1 676 // For HashSet, an O(n) (with a good hash function) algorithm
duke@1 677 // is possible, and likewise TreeSet, since it is
duke@1 678 // ordered, is O(n). But this is not worth the effort here.
duke@1 679 // Note that the inner loop uses equals, not equalsHelper.
duke@1 680 // This is needed because of the searching behavior of this test.
duke@1 681 // However, note that this will NOT correctly handle sets that
duke@1 682 // contain themselves as members, or that have members that reference
duke@1 683 // themselves. These cases will cause infinite regress!
duke@1 684 private static boolean equalSets( Map counterpart, Set considered,
duke@1 685 Set set1, Set set2 )
duke@1 686 {
duke@1 687 if (set1.size() != set2.size())
duke@1 688 return false ;
duke@1 689
duke@1 690 Iterator e1 = set1.iterator() ;
duke@1 691 while (e1.hasNext()) {
duke@1 692 java.lang.Object obj1 = e1.next() ;
duke@1 693
duke@1 694 boolean found = false ;
duke@1 695 Iterator e2 = set2.iterator() ;
duke@1 696 while (e2.hasNext() && !found) {
duke@1 697 java.lang.Object obj2 = e2.next() ;
duke@1 698 found = equals( obj1, obj2 ) ;
duke@1 699 }
duke@1 700
duke@1 701 if (!found)
duke@1 702 return false ;
duke@1 703 }
duke@1 704
duke@1 705 return true ;
duke@1 706 }
duke@1 707
duke@1 708 private static boolean equalLists( Map counterpart, Set considered,
duke@1 709 List list1, List list2 )
duke@1 710 {
duke@1 711 ListIterator e1 = list1.listIterator();
duke@1 712 ListIterator e2 = list2.listIterator();
duke@1 713 while(e1.hasNext() && e2.hasNext()) {
duke@1 714 java.lang.Object o1 = e1.next();
duke@1 715 java.lang.Object o2 = e2.next();
duke@1 716 if (!(o1==null ? o2==null : equalsHelper(
duke@1 717 counterpart, considered, o1, o2)))
duke@1 718 return false;
duke@1 719 }
duke@1 720 return !(e1.hasNext() || e2.hasNext());
duke@1 721 }
duke@1 722 }

mercurial