2362N/A * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 2362N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 2362N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2362N/A * or visit www.oracle.com if you need additional information or have any 353N/A * <p>A converter between Java types and the limited set of classes 353N/A * defined by Open MBeans.</p> 353N/A * <p>A Java type is an instance of java.lang.reflect.Type. For our 353N/A * purposes, it is either a Class, such as String.class or int.class; 353N/A * or a ParameterizedType, such as List<String> or Map<Integer, 353N/A * String[]>. On J2SE 1.4 and earlier, it can only be a Class.</p> 353N/A * <p>Each Type is associated with an DefaultMXBeanMappingFactory. The 353N/A * DefaultMXBeanMappingFactory defines an OpenType corresponding to the Type, plus a 353N/A * Java class corresponding to the OpenType. For example:</p> 353N/A * Type Open class OpenType 353N/A * ---- ---------- -------- 353N/A * Integer Integer SimpleType.INTEGER 353N/A * int int SimpleType.INTEGER 353N/A * Integer[] Integer[] ArrayType(1, SimpleType.INTEGER) 353N/A * int[] Integer[] ArrayType(SimpleType.INTEGER, true) 353N/A * String[][] String[][] ArrayType(2, SimpleType.STRING) 353N/A * List<String> String[] ArrayType(1, SimpleType.STRING) 353N/A * ThreadState (an Enum) String SimpleType.STRING 353N/A * Map<Integer, String[]> TabularData TabularType( 353N/A * {"key", SimpleType.INTEGER}, 353N/A * SimpleType.STRING)}), 353N/A * <p>Apart from simple types, arrays, and collections, Java types are 353N/A * converted through introspection into CompositeType. The Java type 353N/A * must have at least one getter (method such as "int getSize()" or 353N/A * "boolean isBig()"), and we must be able to deduce how to 353N/A * reconstruct an instance of the Java class from the values of the 353N/A * getters using one of various heuristics.</p> 353N/A * <p>True if and only if this MXBeanMapping's toOpenValue and 353N/A * fromOpenValue methods are the identity function.</p> 1790N/A /** Following List simply serves to keep a reference to predefined 1790N/A MXBeanMappings so they don't get garbage collected. */ 0N/A /* Set up the mappings for Java types that map to SimpleType. */ 0N/A // the classes that these predefined types declare must exist! 0N/A // OK: must not be a primitive wrapper 0N/A // Should not reach here 0N/A /** Get the converter for the given Java type, creating it if necessary. */ 0N/A /* It's not yet worth formalizing these tests by having for example 0N/A an array of factory classes, each of which says whether it 0N/A recognizes the Type (Chain of Responsibility pattern). */ 0N/A // Huge hack to avoid compiler warnings here. The ElementType 0N/A // parameter is ignored but allows us to obtain a type variable 0N/A // T that matches <T extends Enum<T>>. 0N/A /* Make the converter for an array type, or a collection such as 0N/A * List<String> or Set<Integer>. We never see one-dimensional 0N/A * primitive arrays (e.g. int[]) here because they use the identity 0N/A * converter and are registered as such in the static initializer. 0N/A /* We know how to translate List<E>, Set<E>, SortedSet<E>, 0N/A Map<K,V>, SortedMap<K,V>, and that's it. We don't accept 0N/A subtypes of those because we wouldn't know how to deserialize 0N/A them. We don't accept Queue<E> because it is unlikely people 0N/A would use that as a parameter or return type in an MBean. */ 0N/A // For historical reasons GcInfo implements CompositeData but we 0N/A // shouldn't count its CompositeData.getCompositeType() field as 0N/A // an item in the computed CompositeType. 0N/A /* Select public methods that look like "T getX()" or "boolean 0N/A isX()", where T is not void and X is not the empty 0N/A string. Exclude "Class getClass()" inherited from Object. */ 0N/A "Class " + c.
getName() +
" has method name clash: " +
0N/A " to an open data type");
0N/A /* Converter for classes where the open data is identical to the 0N/A original data. This is true for any of the SimpleType types, 0N/A and for an any-dimension array of those. It is also true for 353N/A primitive types as of JMX 1.3, since an int[] 0N/A can be directly represented by an ArrayType, and an int needs no mapping 0N/A because reflection takes care of it. */ 353N/A * DefaultMXBeanMappingFactory for the elements of this array. If this is an 353N/A * array of arrays, the converter converts the second-level arrays, 353N/A * not the deepest elements. 0N/A /* Determine the concrete class to be used when converting 0N/A back to this Java type. We convert all Lists to ArrayList 0N/A and all Sets to TreeSet. (TreeSet because it is a SortedSet, 0N/A so works for both Set and SortedSet.) */ 0N/A else {
// can't happen 0N/A "Cannot convert SortedSet with non-null comparator: " +
0N/A "Could not add " + o +
" to " +
0N/A " (duplicate set element?)";
0N/A "Cannot convert MXBean interface in this context";
0N/A "Cannot convert SortedMap with non-null comparator: " +
0N/A "Duplicate entry in TabularData: key=" +
key;
0N/A /** Determine how to convert back from the CompositeData into 0N/A the original Java type. For a type that is not reconstructible, 0N/A this method will fail every time, and will throw the right 0N/A /* In this 2D array, each subarray is a set of builders where 0N/A there is no point in consulting the ones after the first if 0N/A the first refuses. */ 0N/A /* We try to make a meaningful exception message by 0N/A concatenating each Builder's explanation of why it 0N/A isn't applicable. */ 0N/A break;
// skip other builders in this group 688N/A msg +=
". Remaining exceptions show a POSSIBLE cause.";
0N/A /** Converts from a CompositeData to an instance of the targetClass. */ 0N/A /** If the subclass is appropriate for targetClass, then the 0N/A method returns null. If the subclass is not appropriate, 0N/A then the method returns an explanation of why not. If the 0N/A subclass should be appropriate but there is a problem, 0N/A then the method throws InvalidObjectException. */ 688N/A /** If the subclass returns an explanation of why it is not applicable, 688N/A it can additionally indicate an exception with details. This is 688N/A potentially confusing, because the real problem could be that one 688N/A of the other subclasses is supposed to be applicable but isn't. 688N/A But the advantage of less information loss probably outweighs the 688N/A disadvantage of possible confusion. */ 0N/A /** Builder for when the target class has a method "public static 0N/A from(CompositeData)". */ 0N/A // See if it has a method "T from(CompositeData)" 0N/A // as is conventional for a CompositeDataView 0N/A "Method from(CompositeData) is not static";
0N/A "Method from(CompositeData) returns " +
0N/A // OK: it doesn't have the method 0N/A return "no method from(CompositeData)";
0N/A /** This builder never actually returns success. It simply serves 0N/A to check whether the other builders in the same group have any 0N/A chance of success. If any getter in the targetClass returns 0N/A a type that we don't know how to reconstruct, then we will 0N/A not be able to make a builder, and there is no point in repeating 0N/A the error about the problematic getter as many times as there are 0N/A candidate builders. Instead, the "applicable" method will return 0N/A an explanatory string, and the other builders will be skipped. 0N/A If all the getters are OK, then the "applicable" method will return 0N/A an empty string and the other builders will be tried. */ 0N/A "that cannot be mapped back from OpenData";
0N/A /** Builder for when the target class has a setter for every getter. */ 0N/A return "does not have a public no-arg constructor";
0N/A return "not all getters have corresponding setters " +
0N/A /** Builder for when the target class has a constructor that is 0N/A annotated with @ConstructorProperties so we can see the correspondence 0N/A // Applicable if and only if there are any annotated constructors 0N/A return "no constructor has @ConstructorProperties annotation";
0N/A // Now check that all the annotated constructors are valid 0N/A // and throw an exception if not. 0N/A // First link the itemNames to their getter indexes. 0N/A // Run through the constructors making the checks in the spec. 0N/A // For each constructor, remember the correspondence between its 0N/A // parameters and the items. The int[] for a constructor says 0N/A // what parameter index should get what item. For example, 0N/A // if element 0 is 2 then that means that item 0 in the 0N/A // CompositeData goes to parameter 2 of the constructor. If an 0N/A // element is -1, that item isn't given to the constructor. 0N/A // Also remember the set of properties in that constructor 0N/A // so we can test unambiguity. 0N/A "Number of constructor params does not match " +
0N/A "@ConstructorProperties annotation: " +
constr;
688N/A " which does not correspond to a property";
688N/A msg +=
" (differs only in case from property " +
0N/A "@ConstructorProperties contains property " +
0N/A "More than one constructor has a @ConstructorProperties " +
0N/A "annotation with this set of names: " +
0N/A /* Check that no possible set of items could lead to an ambiguous 0N/A * choice of constructor (spec requires this check). For any 0N/A * pair of constructors, their union would be the minimal 0N/A * ambiguous set. If this set itself corresponds to a constructor, 0N/A * there is no ambiguity for that pair. In the usual case, one 0N/A * of the constructors is a superset of the other so the union is 0N/A * just the bigger constuctor. 0N/A * The algorithm here is quadratic in the number of constructors 0N/A * with a @ConstructorProperties annotation. Typically this corresponds 0N/A * to the number of versions of the class there have been. Ten 0N/A * would already be a large number, so although it's probably 0N/A * possible to have an O(n lg n) algorithm it wouldn't be 0N/A * worth the complexity. 0N/A "Constructors with @ConstructorProperties annotation " +
0N/A " would be ambiguous for these items: " +
0N/A // The CompositeData might come from an earlier version where 0N/A // not all the items were present. We look for a constructor 0N/A // that accepts just the items that are present. Because of 0N/A // the ambiguity check in applicable(), we know there must be 0N/A // at most one maximally applicable constructor. 0N/A "No constructor has a @ConstructorProperties for this set of " +
0N/A /** Builder for when the target class is an interface and contains 0N/A no methods other than getters. Then we can make an instance 0N/A using a dynamic proxy that forwards the getters to the source 0N/A return "not an interface";
0N/A /* If the interface has any methods left over, they better be 0N/A * public methods that are already present in java.lang.Object. 0N/A /* We don't catch SecurityException since it shouldn't 0N/A * happen for a method in Object and if it does we would 0N/A * like to know about it rather than mysteriously complaining. 0N/A return "contains methods other than getters (" +
bad +
")";
0N/A * Utility method to take a string and convert it to normal Java variable 0N/A * name capitalization. This normally means converting the first 0N/A * character from upper case to lower case, but in the (unusual) special 0N/A * case when there is more than one character and both the first and 0N/A * second characters are upper case, we leave it alone. 0N/A * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays 0N/A * @param name The string to be decapitalized. 0N/A * @return The decapitalized version of the string. 0N/A // Should be name.offsetByCodePoints but 6242664 makes this fail 0N/A * Reverse operation for java.beans.Introspector.decapitalize. For any s, 0N/A * capitalize(decapitalize(s)).equals(s). The reverse is not true: 0N/A * e.g. capitalize("uRL") produces "URL" which is unchanged by 0N/A // really an IdentityHashSet but that doesn't exist