FileDocCategorySizeDatePackage
OpenConverter.javaAPI DocJava SE 6 API56824Tue Jun 10 00:22:04 BST 2008com.sun.jmx.mbeanserver

OpenConverter

public abstract class OpenConverter extends Object

A converter between Java types and the limited set of classes defined by Open MBeans.

A Java type is an instance of java.lang.reflect.Type. For our purposes, it is either a Class, such as String.class or int.class; or a ParameterizedType, such as List or Map. On J2SE 1.4 and earlier, it can only be a Class.

Each Type is associated with an OpenConverter. The OpenConverter defines an OpenType corresponding to the Type, plus a Java class corresponding to the OpenType. For example:

Type Open class OpenType
---- ---------- --------
Integer Integer SimpleType.INTEGER
int int SimpleType.INTEGER
Integer[] Integer[] ArrayType(1, SimpleType.INTEGER)
int[] Integer[] ArrayType(SimpleType.INTEGER, true)
String[][] String[][] ArrayType(2, SimpleType.STRING)
List String[] ArrayType(1, SimpleType.STRING)
ThreadState (an Enum) String SimpleType.STRING
Map TabularData TabularType(
CompositeType(
{"key", SimpleType.INTEGER},
{"value",
ArrayType(1,
SimpleType.STRING)}),
indexNames={"key"})

Apart from simple types, arrays, and collections, Java types are converted through introspection into CompositeType. The Java type must have at least one getter (method such as "int getSize()" or "boolean isBig()"), and we must be able to deduce how to reconstruct an instance of the Java class from the values of the getters using one of various heuristics.

since
1.6

Fields Summary
private final Type
targetType
private final OpenType
openType
private final Class
openClass
private static final ConverterMap
converterMap
private static final List
permanentConverters
Following List simply serves to keep a reference to predefined OpenConverters so they don't get garbage collected.
private static final String[]
keyArray
private static final String[]
keyValueArray
private static final Map
inProgress
Constructors Summary
private OpenConverter(Type targetType, OpenType openType, Class openClass)

	this.targetType = targetType;
	this.openType = openType;
	this.openClass = openClass;
    
Methods Summary
static java.lang.Stringcapitalize(java.lang.String name)
Reverse operation for java.beans.Introspector.decapitalize. For any s, capitalize(decapitalize(s)).equals(s). The reverse is not true: e.g. capitalize("uRL") produces "URL" which is unchanged by decapitalize.

        if (name == null || name.length() == 0)
            return name;
        int offset1 = name.offsetByCodePoints(0, 1);
        return name.substring(0, offset1).toUpperCase() +
               name.substring(offset1);
    
voidcheckReconstructible()

Throw an appropriate InvalidObjectException if we will not be able to convert back from the open data to the original Java object.

        // subclasses override if action necessary
    
public static java.lang.Stringdecapitalize(java.lang.String name)
Utility method to take a string and convert it to normal Java variable name capitalization. This normally means converting the first character from upper case to lower case, but in the (unusual) special case when there is more than one character and both the first and second characters are upper case, we leave it alone.

Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays as "URL".

param
name The string to be decapitalized.
return
The decapitalized version of the string.

        if (name == null || name.length() == 0) {
            return name;
        }
        int offset1 = Character.offsetByCodePoints(name, 0, 1);
        // Should be name.offsetByCodePoints but 6242664 makes this fail
        if (offset1 < name.length() &&
                Character.isUpperCase(name.codePointAt(offset1)))
            return name;
        return name.substring(0, offset1).toLowerCase() +
               name.substring(offset1);
    
abstract java.lang.ObjectfromNonNullOpenValue(com.sun.jmx.mbeanserver.MXBeanLookup lookup, java.lang.Object value)

public final java.lang.ObjectfromOpenValue(com.sun.jmx.mbeanserver.MXBeanLookup lookup, java.lang.Object value)

Convert an instance of openClass into an instance of targetType.

        if (value == null)
            return null;
        else
            return fromNonNullOpenValue(lookup, value);
    
private static synchronized com.sun.jmx.mbeanserver.OpenConvertergetConverter(java.lang.reflect.Type type)


          
        WeakReference<OpenConverter> wr = converterMap.get(type);
        return (wr == null) ? null : wr.get();
    
final java.lang.ClassgetOpenClass()

	return openClass;
    
final javax.management.openmbean.OpenTypegetOpenType()

	return openType;
    
final java.lang.reflect.TypegetTargetType()

True if and only if isIdentity() and even an array of the underlying type is transformed as the identity. This is true for Integer and ObjectName, for instance, but not for int.

	return targetType;
    
static java.io.InvalidObjectExceptioninvalidObjectException(java.lang.String msg, java.lang.Throwable cause)

        return EnvHelp.initCause(new InvalidObjectException(msg), cause);
    
static java.io.InvalidObjectExceptioninvalidObjectException(java.lang.Throwable cause)

        return invalidObjectException(cause.getMessage(), cause);
    
booleanisIdentity()

True if and only if this OpenConverter's toOpenValue and fromOpenValue methods are the identity function.

	return false;
    
private static com.sun.jmx.mbeanserver.OpenConvertermakeArrayOrCollectionConverter(java.lang.reflect.Type collectionType, java.lang.reflect.Type elementType)


        final OpenConverter elementConverter = toConverter(elementType);
	final OpenType elementOpenType = elementConverter.getOpenType();
	final ArrayType openType = new ArrayType(1, elementOpenType);
	final Class elementOpenClass = elementConverter.getOpenClass();

	final Class openArrayClass;
        final String openArrayClassName;
        if (elementOpenClass.isArray())
            openArrayClassName = "[" + elementOpenClass.getName();
        else
            openArrayClassName = "[L" + elementOpenClass.getName() + ";";
        try {
            openArrayClass = Class.forName(openArrayClassName);
        } catch (ClassNotFoundException e) {
            throw openDataException("Cannot obtain array class", e);
        }

	if (collectionType instanceof ParameterizedType) {
	    return new CollectionConverter(collectionType,
					   openType, openArrayClass,
					   elementConverter);
        } else {
            if (elementConverter.isIdentity()) {
		return new IdentityConverter(collectionType,
                                             openType,
                                             openArrayClass);
	    } else {
		return new ArrayConverter(collectionType,
                                          openType,
                                          openArrayClass,
                                          elementConverter);
	    }
	}
    
private static com.sun.jmx.mbeanserver.OpenConvertermakeCompositeConverter(java.lang.Class c)

        
        // For historical reasons GcInfo implements CompositeData but we
        // shouldn't count its CompositeData.getCompositeType() field as
        // an item in the computed CompositeType.
        final boolean gcInfoHack =
            (c.getName().equals("com.sun.management.GcInfo") &&
                c.getClassLoader() == null);

	final List<Method> methods =
                MBeanAnalyzer.eliminateCovariantMethods(c.getMethods());
	final SortedMap<String,Method> getterMap = newSortedMap();

	/* Select public methods that look like "T getX()" or "boolean
	   isX()", where T is not void and X is not the empty
	   string.  Exclude "Class getClass()" inherited from Object.  */
	for (Method method : methods) {
	    final String propertyName = propertyName(method);

	    if (propertyName == null)
		continue;
            if (gcInfoHack && propertyName.equals("CompositeType"))
                continue;

            Method old =
                getterMap.put(decapitalize(propertyName),
                            method);
            if (old != null) {
                final String msg =
                    "Class " + c.getName() + " has method name clash: " +
                    old.getName() + ", " + method.getName();
                throw new OpenDataException(msg);
            }
	}

        final int nitems = getterMap.size();

	if (nitems == 0) {
	    throw new OpenDataException("Can't map " + c.getName() +
					" to an open data type");
	}

        final Method[] getters = new Method[nitems];
        final String[] itemNames = new String[nitems];
        final OpenType[] openTypes = new OpenType[nitems];
        int i = 0;
        for (Map.Entry<String,Method> entry : getterMap.entrySet()) {
            itemNames[i] = entry.getKey();
            final Method getter = entry.getValue();
            getters[i] = getter;
            final Type retType = getter.getGenericReturnType();
            openTypes[i] = toConverter(retType).getOpenType();
            i++;
        }

        CompositeType compositeType =
	    new CompositeType(c.getName(),
			      c.getName(),
			      itemNames, // field names
			      itemNames, // field descriptions
			      openTypes);

	return new CompositeConverter(c,
				      compositeType,
				      itemNames,
				      getters);
    
private static com.sun.jmx.mbeanserver.OpenConvertermakeConverter(java.lang.reflect.Type objType)

        
	/* It's not yet worth formalizing these tests by having for example
	   an array of factory classes, each of which says whether it
	   recognizes the Type (Chain of Responsibility pattern).  */
        if (objType instanceof GenericArrayType) {
            Type componentType =
                ((GenericArrayType) objType).getGenericComponentType();
            return makeArrayOrCollectionConverter(objType, componentType);
        } else if (objType instanceof Class) {
            Class objClass = (Class<?>) objType;
            if (objClass.isEnum()) {
                return makeEnumConverter(objClass);
            } else if (objClass.isArray()) {
                Type componentType = objClass.getComponentType();
                return makeArrayOrCollectionConverter(objClass, componentType);
            } else if (JMX.isMXBeanInterface(objClass)) {
                return makeMXBeanConverter(objClass);
            } else {
                return makeCompositeConverter(objClass);
            }
        } else if (objType instanceof ParameterizedType) {
            return makeParameterizedConverter((ParameterizedType) objType);
        } else
            throw new OpenDataException("Cannot map type: " + objType);
    
private static com.sun.jmx.mbeanserver.OpenConvertermakeEnumConverter(java.lang.Class enumClass)

	return new EnumConverter<T>(enumClass);
    
private static com.sun.jmx.mbeanserver.OpenConvertermakeMXBeanConverter(java.lang.reflect.Type t)

        return new MXBeanConverter(t);
    
private static com.sun.jmx.mbeanserver.OpenConvertermakeParameterizedConverter(java.lang.reflect.ParameterizedType objType)


        final Type rawType = objType.getRawType();

        if (rawType instanceof Class) {
            Class c = (Class<?>) rawType;
            if (c == List.class || c == Set.class || c == SortedSet.class) {
                Type[] actuals =
                    ((ParameterizedType) objType).getActualTypeArguments();
                assert(actuals.length == 1);
                if (c == SortedSet.class)
                    mustBeComparable(c, actuals[0]);
                return makeArrayOrCollectionConverter(objType, actuals[0]);
            } else {
                boolean sortedMap = (c == SortedMap.class);
                if (c == Map.class || sortedMap) {
                    Type[] actuals =
                            ((ParameterizedType) objType).getActualTypeArguments();
                    assert(actuals.length == 2);
                    if (sortedMap)
                        mustBeComparable(c, actuals[0]);
                    return makeTabularConverter(objType, sortedMap,
                            actuals[0], actuals[1]);
                }
            }
	}
        throw new OpenDataException("Cannot convert type: " + objType);
    
private static com.sun.jmx.mbeanserver.OpenConvertermakeTabularConverter(java.lang.reflect.Type objType, boolean sortedMap, java.lang.reflect.Type keyType, java.lang.reflect.Type valueType)


      
	   
                                
	      

	final String objTypeName = objType.toString();
	final OpenConverter keyConverter = toConverter(keyType);
	final OpenConverter valueConverter = toConverter(valueType);
	final OpenType keyOpenType = keyConverter.getOpenType();
	final OpenType valueOpenType = valueConverter.getOpenType();
	final CompositeType rowType =
	    new CompositeType(objTypeName,
			      objTypeName,
			      keyValueArray,
			      keyValueArray,
			      new OpenType[] {keyOpenType, valueOpenType});
	final TabularType tabularType =
	    new TabularType(objTypeName, objTypeName, rowType, keyArray);
	return new TabularConverter(objType, sortedMap, tabularType,
				    keyConverter, valueConverter);
    
static voidmustBeComparable(java.lang.Class collection, java.lang.reflect.Type element)

        if (!(element instanceof Class)
            || !Comparable.class.isAssignableFrom((Class<?>) element)) {
            final String msg =
                "Parameter class " + element + " of " +
                collection.getName() + " does not implement " +
                Comparable.class.getName();
            throw new OpenDataException(msg);
        }
    
static javax.management.openmbean.OpenDataExceptionopenDataException(java.lang.String msg, java.lang.Throwable cause)

        return EnvHelp.initCause(new OpenDataException(msg), cause);
    
static javax.management.openmbean.OpenDataExceptionopenDataException(java.lang.Throwable cause)

        return openDataException(cause.getMessage(), cause);
    
public static java.lang.StringpropertyName(java.lang.reflect.Method m)

	String rest = null;
	String name = m.getName();
	if (name.startsWith("get"))
	    rest = name.substring(3);
	else if (name.startsWith("is") && m.getReturnType() == boolean.class)
	    rest = name.substring(2);
	if (rest == null || rest.length() == 0
	    || m.getParameterTypes().length > 0
	    || m.getReturnType() == void.class
	    || name.equals("getClass"))
	    return null;
	return rest;
    
private static synchronized voidputConverter(java.lang.reflect.Type type, com.sun.jmx.mbeanserver.OpenConverter conv)

        WeakReference<OpenConverter> wr =
            new WeakReference<OpenConverter>(conv);
        converterMap.put(type, wr);
    
private static synchronized voidputPermanentConverter(java.lang.reflect.Type type, com.sun.jmx.mbeanserver.OpenConverter conv)

        putConverter(type, conv);
        permanentConverters.add(conv);
    
public static synchronized com.sun.jmx.mbeanserver.OpenConvertertoConverter(java.lang.reflect.Type objType)
Get the converter for the given Java type, creating it if necessary.

	/* Set up the mappings for Java types that map to SimpleType.  */

	final OpenType[] simpleTypes = {
	    BIGDECIMAL, BIGINTEGER, BOOLEAN, BYTE, CHARACTER, DATE,
	    DOUBLE, FLOAT, INTEGER, LONG, OBJECTNAME, SHORT, STRING,
	    VOID,
	};

	for (int i = 0; i < simpleTypes.length; i++) {
	    final OpenType t = simpleTypes[i];
	    Class c;
	    try {
		c = Class.forName(t.getClassName(), false,
				  ObjectName.class.getClassLoader());
	    } catch (ClassNotFoundException e) {
		// the classes that these predefined types declare must exist!
		throw new Error(e);
	    }
	    final OpenConverter conv = new IdentityConverter(c, t, c);
            putPermanentConverter(c, conv);

            if (c.getName().startsWith("java.lang.")) {
		try {
		    final Field typeField = c.getField("TYPE");
		    final Class primitiveType = (Class) typeField.get(null);
		    final OpenConverter primitiveConv =
			new IdentityConverter(primitiveType, t, primitiveType);
                    putPermanentConverter(primitiveType,
                                          primitiveConv);
                    if (primitiveType != void.class) {
                        final Class primitiveArrayType =
                            Array.newInstance(primitiveType, 0).getClass();
                        final OpenType primitiveArrayOpenType =
                            ArrayType.getPrimitiveArrayType(primitiveArrayType);
                        final OpenConverter primitiveArrayConv =
                            new IdentityConverter(primitiveArrayType,
                                                  primitiveArrayOpenType,
                                                  primitiveArrayType);
                        putPermanentConverter(primitiveArrayType,
                                              primitiveArrayConv);
                    }
		} catch (NoSuchFieldException e) {
		    // OK: must not be a primitive wrapper
		} catch (IllegalAccessException e) {
		    // Should not reach here
		    assert(false);
		}
	    }
	}
    
        
        if (inProgress.containsKey(objType))
            throw new OpenDataException("Recursive data structure");
        
        OpenConverter conv;

	conv = getConverter(objType);
	if (conv != null)
            return conv;
        
        inProgress.put(objType, objType);
        try {
            conv = makeConverter(objType);
        } finally {
            inProgress.remove(objType);
        }

	putConverter(objType, conv);
        return conv;
    
abstract java.lang.ObjecttoNonNullOpenValue(com.sun.jmx.mbeanserver.MXBeanLookup lookup, java.lang.Object value)

final java.lang.ObjecttoOpenValue(com.sun.jmx.mbeanserver.MXBeanLookup lookup, java.lang.Object value)

Convert an instance of targetType into an instance of openClass.

        if (value == null)
            return null;
        else
            return toNonNullOpenValue(lookup, value);