/* * @(#)ORBUtility.java 1.32 02/08/13 * * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.sun.corba.se.impl.orbutil; import java.security.PrivilegedAction; import java.security.AccessController; import java.util.ArrayList; import java.util.Arrays; import java.util.Map; import java.util.List; import java.util.ListIterator; import java.util.Set; import java.util.Map.Entry; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.Enumeration; import java.util.Properties; import java.util.IdentityHashMap; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.math.BigInteger ; import java.math.BigDecimal ; public final class ObjectUtility { private boolean useToString ; private boolean isIndenting ; private int initialLevel ; private int increment ; private ClassMap classToPrinter = new ClassMap() ; private static ObjectUtility standard = new ObjectUtility( false, true, 0, 4 ) ; private static ObjectUtility compact = new ObjectUtility( true, false, 0, 4 ) ; private ObjectUtility( boolean useToString, boolean isIndenting, int initialLevel, int increment ) { this.useToString = useToString ; this.isIndenting = isIndenting ; this.initialLevel = initialLevel ; this.increment = increment ; classToPrinter.put( Properties.class, propertiesPrinter ) ; classToPrinter.put( Collection.class, collectionPrinter ) ; classToPrinter.put( Map.class, mapPrinter ) ; } /** Construct an Utility instance with the desired objectToString * behavior. */ public static ObjectUtility make( boolean useToString, boolean isIndenting, int initialLevel, int increment ) { return new ObjectUtility( useToString, isIndenting, initialLevel, increment ) ; } /** Construct an Utility instance with the desired objectToString * behavior. */ public static ObjectUtility make( boolean useToString, boolean isIndenting ) { return new ObjectUtility( useToString, isIndenting, 0, 4 ) ; } /** Get the standard Utility object that supports objectToString with * indented display and no use of toString() methods. */ public static ObjectUtility make() { return standard ; } /** A convenience method that gives the default behavior: use indenting * to display the object's structure and do not use built-in toString * methods. */ public static String defaultObjectToString( java.lang.Object object ) { return standard.objectToString( object ) ; } public static String compactObjectToString( java.lang.Object object ) { return compact.objectToString( object ) ; } /** objectToString handles display of arbitrary objects. It correctly * handles objects whose elements form an arbitrary graph. It uses * reflection to display the contents of any kind of object. * An object's toString() method may optionally be used, but the default * is to ignore all toString() methods except for those defined for * primitive types, primitive type wrappers, and strings. */ public String objectToString(java.lang.Object obj) { IdentityHashMap printed = new IdentityHashMap() ; ObjectWriter result = ObjectWriter.make( isIndenting, initialLevel, increment ) ; objectToStringHelper( printed, result, obj ) ; return result.toString() ; } // Perform a deep structural equality comparison of the two objects. // This handles all arrays, maps, and sets specially, otherwise // it just calls the object's equals() method. public static boolean equals( java.lang.Object obj1, java.lang.Object obj2 ) { // Set of pairs of objects that have been (or are being) considered for // equality. Such pairs are presumed to be equals. If they are not, // this will be detected eventually and the equals method will return // false. Set considered = new HashSet() ; // Map that gives the corresponding component of obj2 for a component // of obj1. This is used to check for the same aliasing and use of // equal objects in both objects. Map counterpart = new IdentityHashMap() ; return equalsHelper( counterpart, considered, obj1, obj2 ) ; } /** If arr1 and arr2 are both arrays of the same component type, * return an array of that component type that consists of the * elements of arr1 followed by the elements of arr2. * Throws IllegalArgumentException otherwise. */ public static Object concatenateArrays( Object arr1, Object arr2 ) { Class comp1 = arr1.getClass().getComponentType() ; Class comp2 = arr2.getClass().getComponentType() ; int len1 = Array.getLength( arr1 ) ; int len2 = Array.getLength( arr2 ) ; if ((comp1 == null) || (comp2 == null)) throw new IllegalStateException( "Arguments must be arrays" ) ; if (!comp1.equals( comp2 )) throw new IllegalStateException( "Arguments must be arrays with the same component type" ) ; Object result = Array.newInstance( comp1, len1 + len2 ) ; int index = 0 ; for (int ctr=0; ctr" ) ; objectToStringHelper( printed, buff, entry.getValue() ) ; buff.endElement() ; } } } ; private static class ClassMap { ArrayList data ; public ClassMap() { data = new ArrayList() ; } /** Return the first element of the ClassMap that is assignable to cls. * The order is determined by the order in which the put method was * called. Returns null if there is no match. */ public java.lang.Object get( Class cls ) { Iterator iter = data.iterator() ; while (iter.hasNext()) { java.lang.Object[] arr = (java.lang.Object[])(iter.next()) ; Class key = (Class)(arr[0]) ; if (key.isAssignableFrom( cls )) return arr[1] ; } return null ; } /** Add obj to the map with key cls. Note that order matters, * as the first match is returned. */ public void put( Class cls, java.lang.Object obj ) { java.lang.Object[] pair = { cls, obj } ; data.add( pair ) ; } } private boolean mustUseToString( Class cls ) { // These probably never occur if (cls.isPrimitive()) return true ; // We must use toString for all primitive wrappers, since // otherwise the code recurses endlessly (access value field // inside Integer, returns another Integer through reflection). if ((cls == Integer.class) || (cls == BigInteger.class) || (cls == BigDecimal.class) || (cls == String.class) || (cls == StringBuffer.class) || (cls == Long.class) || (cls == Short.class) || (cls == Byte.class) || (cls == Character.class) || (cls == Float.class) || (cls == Double.class) || (cls == Boolean.class)) return true ; if (useToString) { try { cls.getDeclaredMethod( "toString", null ) ; return true ; } catch (Exception exc) { return false ; } } return false ; } private void handleObject( IdentityHashMap printed, ObjectWriter result, java.lang.Object obj ) { Class cls = obj.getClass() ; try { Field[] fields; SecurityManager security = System.getSecurityManager(); if (security != null && !Modifier.isPublic(cls.getModifiers())) { fields = new Field[0]; } else { fields = sun.reflect.misc.FieldUtil.getDeclaredFields(cls); } for (int ctr=0; ctr