Mon, 14 Jun 2010 11:28:53 -0700
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 | } |