jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java
author emcmanus
Fri, 08 Aug 2008 15:08:57 +0200
changeset 1018 9f07e65e9653
parent 832 5484c7a35278
child 1221 e3dc70e4e610
permissions -rw-r--r--
6334663: TabularDataSupport should be able to return values in the insertion order Reviewed-by: dfuchs
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
715
f16baef3a20e 6719955: Update copyright year
xdono
parents: 687
diff changeset
     2
 * Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package com.sun.jmx.mbeanserver;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import static com.sun.jmx.mbeanserver.Util.*;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    29
import java.lang.annotation.ElementType;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    30
import javax.management.openmbean.MXBeanMappingClass;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import static javax.management.openmbean.SimpleType.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
import com.sun.jmx.remote.util.EnvHelp;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
import java.beans.ConstructorProperties;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
import java.io.InvalidObjectException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
import java.lang.annotation.ElementType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
import java.lang.ref.WeakReference;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
import java.lang.reflect.Array;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
import java.lang.reflect.Constructor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
import java.lang.reflect.Field;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
import java.lang.reflect.GenericArrayType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
import java.lang.reflect.Method;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
import java.lang.reflect.Modifier;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
import java.lang.reflect.ParameterizedType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
import java.lang.reflect.Proxy;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
import java.lang.reflect.Type;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
import java.util.ArrayList;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
import java.util.Arrays;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
import java.util.BitSet;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
import java.util.Collection;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
import java.util.Comparator;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
import java.util.HashSet;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
import java.util.List;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
import java.util.Map;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
import java.util.Set;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
import java.util.SortedMap;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
import java.util.SortedSet;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
import java.util.TreeSet;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
import java.util.WeakHashMap;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
import javax.management.JMX;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
import javax.management.ObjectName;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
import javax.management.openmbean.ArrayType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
import javax.management.openmbean.CompositeData;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
import javax.management.openmbean.CompositeDataInvocationHandler;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
import javax.management.openmbean.CompositeDataSupport;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
import javax.management.openmbean.CompositeDataView;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
import javax.management.openmbean.CompositeType;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    71
import javax.management.openmbean.MXBeanMapping;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    72
import javax.management.openmbean.MXBeanMappingFactory;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
import javax.management.openmbean.OpenDataException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
import javax.management.openmbean.OpenType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
import javax.management.openmbean.SimpleType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
import javax.management.openmbean.TabularData;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
import javax.management.openmbean.TabularDataSupport;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
import javax.management.openmbean.TabularType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
/**
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    81
 *   <p>A converter between Java types and the limited set of classes
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    82
 *   defined by Open MBeans.</p>
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    83
 *
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    84
 *   <p>A Java type is an instance of java.lang.reflect.Type.  For our
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    85
 *   purposes, it is either a Class, such as String.class or int.class;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    86
 *   or a ParameterizedType, such as List<String> or Map<Integer,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    87
 *   String[]>.  On J2SE 1.4 and earlier, it can only be a Class.</p>
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    88
 *
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    89
 *   <p>Each Type is associated with an DefaultMXBeanMappingFactory.  The
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    90
 *   DefaultMXBeanMappingFactory defines an OpenType corresponding to the Type, plus a
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    91
 *   Java class corresponding to the OpenType.  For example:</p>
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    92
 *
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    93
 *   <pre>
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    94
 *   Type                     Open class     OpenType
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    95
 *   ----                     ----------     --------
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    96
 *   Integer                Integer        SimpleType.INTEGER
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    97
 *   int                            int            SimpleType.INTEGER
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    98
 *   Integer[]              Integer[]      ArrayType(1, SimpleType.INTEGER)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
    99
 *   int[]                  Integer[]      ArrayType(SimpleType.INTEGER, true)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   100
 *   String[][]             String[][]     ArrayType(2, SimpleType.STRING)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   101
 *   List<String>                   String[]       ArrayType(1, SimpleType.STRING)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   102
 *   ThreadState (an Enum)    String         SimpleType.STRING
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   103
 *   Map<Integer, String[]>   TabularData          TabularType(
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   104
 *                                           CompositeType(
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   105
 *                                             {"key", SimpleType.INTEGER},
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   106
 *                                             {"value",
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   107
 *                                               ArrayType(1,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   108
 *                                                SimpleType.STRING)}),
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   109
 *                                           indexNames={"key"})
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   110
 *   </pre>
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   111
 *
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   112
 *   <p>Apart from simple types, arrays, and collections, Java types are
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   113
 *   converted through introspection into CompositeType.  The Java type
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   114
 *   must have at least one getter (method such as "int getSize()" or
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   115
 *   "boolean isBig()"), and we must be able to deduce how to
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   116
 *   reconstruct an instance of the Java class from the values of the
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   117
 *   getters using one of various heuristics.</p>
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   118
 *
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   119
 * @since 1.6
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   120
 */
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   121
public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   122
    static abstract class NonNullMXBeanMapping extends MXBeanMapping {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   123
        NonNullMXBeanMapping(Type javaType, OpenType openType) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   124
            super(javaType, openType);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   125
        }
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   127
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   128
        public final Object fromOpenValue(Object openValue)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   129
        throws InvalidObjectException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   130
            if (openValue == null)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   131
                return null;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   132
            else
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   133
                return fromNonNullOpenValue(openValue);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   134
        }
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   136
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   137
        public final Object toOpenValue(Object javaValue) throws OpenDataException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   138
            if (javaValue == null)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   139
                return null;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   140
            else
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   141
                return toNonNullOpenValue(javaValue);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   142
        }
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   143
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   144
        abstract Object fromNonNullOpenValue(Object openValue)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   145
        throws InvalidObjectException;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   147
        abstract Object toNonNullOpenValue(Object javaValue)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   148
        throws OpenDataException;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   150
        /**
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   151
         * <p>True if and only if this MXBeanMapping's toOpenValue and
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   152
         * fromOpenValue methods are the identity function.</p>
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   153
         */
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   154
        boolean isIdentity() {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   155
            return false;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   156
        }
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   159
    static boolean isIdentity(MXBeanMapping mapping) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   160
        return (mapping instanceof NonNullMXBeanMapping &&
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   161
                ((NonNullMXBeanMapping) mapping).isIdentity());
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   164
    private static final class Mappings
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   165
        extends WeakHashMap<Type, WeakReference<MXBeanMapping>> {}
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   167
    private static final Map<MXBeanMappingFactory, Mappings> factoryMappings =
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   168
            new WeakHashMap<MXBeanMappingFactory, Mappings>();
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   169
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   170
    private static final Map<Type, MXBeanMapping> permanentMappings = newMap();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   172
    private static synchronized MXBeanMapping getMapping(
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   173
            Type type, MXBeanMappingFactory factory) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   174
        Mappings mappings = factoryMappings.get(factory);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   175
        if (mappings == null) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   176
            mappings = new Mappings();
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   177
            factoryMappings.put(factory, mappings);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   178
        }
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   179
        WeakReference<MXBeanMapping> wr = mappings.get(type);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
        return (wr == null) ? null : wr.get();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   183
    private static synchronized void putMapping(
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   184
            Type type, MXBeanMapping mapping, MXBeanMappingFactory factory) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   185
        Mappings mappings = factoryMappings.get(factory);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   186
        if (mappings == null) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   187
            mappings = new Mappings();
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   188
            factoryMappings.put(factory, mappings);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   189
        }
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   190
        WeakReference<MXBeanMapping> wr =
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   191
            new WeakReference<MXBeanMapping>(mapping);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   192
        mappings.put(type, wr);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
    static {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
        /* Set up the mappings for Java types that map to SimpleType.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
        final OpenType[] simpleTypes = {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
            BIGDECIMAL, BIGINTEGER, BOOLEAN, BYTE, CHARACTER, DATE,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
            DOUBLE, FLOAT, INTEGER, LONG, OBJECTNAME, SHORT, STRING,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
            VOID,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
        };
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
        for (int i = 0; i < simpleTypes.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
            final OpenType t = simpleTypes[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
            Class c;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
                c = Class.forName(t.getClassName(), false,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
                                  ObjectName.class.getClassLoader());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
            } catch (ClassNotFoundException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
                // the classes that these predefined types declare must exist!
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
                throw new Error(e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
            }
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   214
            final MXBeanMapping mapping = new IdentityMapping(c, t);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   215
            permanentMappings.put(c, mapping);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
            if (c.getName().startsWith("java.lang.")) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
                    final Field typeField = c.getField("TYPE");
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   220
                    final Class<?> primitiveType = (Class<?>) typeField.get(null);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   221
                    final MXBeanMapping primitiveMapping =
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   222
                        new IdentityMapping(primitiveType, t);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   223
                    permanentMappings.put(primitiveType, primitiveMapping);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
                    if (primitiveType != void.class) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
                        final Class<?> primitiveArrayType =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
                            Array.newInstance(primitiveType, 0).getClass();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
                        final OpenType primitiveArrayOpenType =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
                            ArrayType.getPrimitiveArrayType(primitiveArrayType);
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   229
                        final MXBeanMapping primitiveArrayMapping =
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   230
                            new IdentityMapping(primitiveArrayType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   231
                                                primitiveArrayOpenType);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   232
                        permanentMappings.put(primitiveArrayType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   233
                                              primitiveArrayMapping);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
                } catch (NoSuchFieldException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
                    // OK: must not be a primitive wrapper
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
                } catch (IllegalAccessException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
                    // Should not reach here
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
                    assert(false);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
    /** Get the converter for the given Java type, creating it if necessary. */
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   246
    @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   247
    public synchronized MXBeanMapping mappingForType(Type objType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   248
                                                     MXBeanMappingFactory factory)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
            throws OpenDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
        if (inProgress.containsKey(objType))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
            throw new OpenDataException("Recursive data structure");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   253
        MXBeanMapping mapping;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   255
        mapping = getMapping(objType, null);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   256
        if (mapping != null)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   257
            return mapping;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
        inProgress.put(objType, objType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
        try {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   261
            mapping = makeMapping(objType, factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
        } finally {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
            inProgress.remove(objType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   266
        putMapping(objType, mapping, factory);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   267
        return mapping;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   270
    private MXBeanMapping makeMapping(Type objType, MXBeanMappingFactory factory)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   271
    throws OpenDataException {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
        /* It's not yet worth formalizing these tests by having for example
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
           an array of factory classes, each of which says whether it
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
           recognizes the Type (Chain of Responsibility pattern).  */
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   276
        MXBeanMapping mapping = permanentMappings.get(objType);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   277
        if (mapping != null)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   278
            return mapping;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   279
        Class<?> erasure = erasure(objType);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   280
        MXBeanMappingClass mappingClass =
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   281
                erasure.getAnnotation(MXBeanMappingClass.class);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   282
        if (mappingClass != null)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   283
            return makeAnnotationMapping(mappingClass, objType, factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
        if (objType instanceof GenericArrayType) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
            Type componentType =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
                ((GenericArrayType) objType).getGenericComponentType();
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   287
            return makeArrayOrCollectionMapping(objType, componentType, factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
        } else if (objType instanceof Class) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
            Class<?> objClass = (Class<?>) objType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
            if (objClass.isEnum()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
                // Huge hack to avoid compiler warnings here.  The ElementType
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
                // parameter is ignored but allows us to obtain a type variable
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
                // T that matches <T extends Enum<T>>.
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   294
                return makeEnumMapping((Class) objClass, ElementType.class);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
            } else if (objClass.isArray()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   296
                Type componentType = objClass.getComponentType();
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   297
                return makeArrayOrCollectionMapping(objClass, componentType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   298
                        factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
            } else if (JMX.isMXBeanInterface(objClass)) {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   300
                return makeMXBeanRefMapping(objClass);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
            } else {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   302
                return makeCompositeMapping(objClass, factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
        } else if (objType instanceof ParameterizedType) {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   305
            return makeParameterizedTypeMapping((ParameterizedType) objType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   306
                                                factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
        } else
90ce3da70b43 Initial load
duke
parents:
diff changeset
   308
            throw new OpenDataException("Cannot map type: " + objType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   309
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   310
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   311
    private static MXBeanMapping
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   312
            makeAnnotationMapping(MXBeanMappingClass mappingClass,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   313
                                  Type objType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   314
                                  MXBeanMappingFactory factory)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   315
    throws OpenDataException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   316
        Class<? extends MXBeanMapping> c = mappingClass.value();
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   317
        Constructor<? extends MXBeanMapping> cons;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   318
        try {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   319
            cons = c.getConstructor(Type.class);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   320
        } catch (NoSuchMethodException e) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   321
            final String msg =
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   322
                    "Annotation @" + MXBeanMappingClass.class.getName() +
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   323
                    " must name a class with a public constructor that has a " +
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   324
                    "single " + Type.class.getName() + " argument";
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   325
            OpenDataException ode = new OpenDataException(msg);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   326
            ode.initCause(e);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   327
            throw ode;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   328
        }
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   329
        try {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   330
            return cons.newInstance(objType);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   331
        } catch (Exception e) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   332
            final String msg =
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   333
                    "Could not construct a " + c.getName() + " for @" +
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   334
                    MXBeanMappingClass.class.getName();
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   335
            OpenDataException ode = new OpenDataException(msg);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   336
            ode.initCause(e);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   337
            throw ode;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   338
        }
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   339
    }
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   340
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   341
    private static Class<?> erasure(Type t) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   342
        if (t instanceof Class<?>)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   343
            return (Class<?>) t;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   344
        if (t instanceof ParameterizedType)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   345
            return erasure(((ParameterizedType) t).getRawType());
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   346
        /* Other cases: GenericArrayType, TypeVariable, WildcardType.
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   347
         * Returning the erasure of GenericArrayType is not necessary because
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   348
         * anyway we will be recursing on the element type, and we'll erase
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   349
         * then.  Returning the erasure of the other two would mean returning
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   350
         * the type bound (e.g. Foo in <T extends Foo> or <? extends Foo>)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   351
         * and since we don't treat this as Foo elsewhere we shouldn't here.
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   352
         */
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   353
        return Object.class;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   354
    }
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   355
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   356
    private static <T extends Enum<T>> MXBeanMapping
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   357
            makeEnumMapping(Class enumClass, Class<T> fake) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   358
        return new EnumMapping<T>(Util.<Class<T>>cast(enumClass));
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
    /* Make the converter for an array type, or a collection such as
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
     * List<String> or Set<Integer>.  We never see one-dimensional
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
     * primitive arrays (e.g. int[]) here because they use the identity
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
     * converter and are registered as such in the static initializer.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
     */
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   366
    private MXBeanMapping
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   367
        makeArrayOrCollectionMapping(Type collectionType, Type elementType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   368
                                     MXBeanMappingFactory factory)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
            throws OpenDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   371
        final MXBeanMapping elementMapping = factory.mappingForType(elementType, factory);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   372
        final OpenType<?> elementOpenType = elementMapping.getOpenType();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
        final ArrayType<?> openType = ArrayType.getArrayType(elementOpenType);
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   374
        final Class<?> elementOpenClass = elementMapping.getOpenClass();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
        final Class<?> openArrayClass;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
        final String openArrayClassName;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
        if (elementOpenClass.isArray())
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
            openArrayClassName = "[" + elementOpenClass.getName();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
        else
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
            openArrayClassName = "[L" + elementOpenClass.getName() + ";";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
            openArrayClass = Class.forName(openArrayClassName);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
        } catch (ClassNotFoundException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
            throw openDataException("Cannot obtain array class", e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
        if (collectionType instanceof ParameterizedType) {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   389
            return new CollectionMapping(collectionType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   390
                                         openType, openArrayClass,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   391
                                         elementMapping);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
        } else {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   393
            if (isIdentity(elementMapping)) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   394
                return new IdentityMapping(collectionType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   395
                                           openType);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
            } else {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   397
                return new ArrayMapping(collectionType,
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
                                          openType,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
                                          openArrayClass,
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   400
                                          elementMapping);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
    private static final String[] keyArray = {"key"};
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
    private static final String[] keyValueArray = {"key", "value"};
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   408
    private MXBeanMapping
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   409
        makeTabularMapping(Type objType, boolean sortedMap,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   410
                           Type keyType, Type valueType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   411
                           MXBeanMappingFactory factory)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
            throws OpenDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
        final String objTypeName = objType.toString();
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   415
        final MXBeanMapping keyMapping = factory.mappingForType(keyType, factory);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   416
        final MXBeanMapping valueMapping = factory.mappingForType(valueType, factory);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   417
        final OpenType keyOpenType = keyMapping.getOpenType();
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   418
        final OpenType valueOpenType = valueMapping.getOpenType();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
        final CompositeType rowType =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   420
            new CompositeType(objTypeName,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   421
                              objTypeName,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   422
                              keyValueArray,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   423
                              keyValueArray,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   424
                              new OpenType[] {keyOpenType, valueOpenType});
90ce3da70b43 Initial load
duke
parents:
diff changeset
   425
        final TabularType tabularType =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   426
            new TabularType(objTypeName, objTypeName, rowType, keyArray);
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   427
        return new TabularMapping(objType, sortedMap, tabularType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   428
                                    keyMapping, valueMapping);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   429
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   430
90ce3da70b43 Initial load
duke
parents:
diff changeset
   431
    /* We know how to translate List<E>, Set<E>, SortedSet<E>,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   432
       Map<K,V>, SortedMap<K,V>, and that's it.  We don't accept
90ce3da70b43 Initial load
duke
parents:
diff changeset
   433
       subtypes of those because we wouldn't know how to deserialize
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
       them.  We don't accept Queue<E> because it is unlikely people
90ce3da70b43 Initial load
duke
parents:
diff changeset
   435
       would use that as a parameter or return type in an MBean.  */
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   436
    private MXBeanMapping
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   437
            makeParameterizedTypeMapping(ParameterizedType objType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   438
                                         MXBeanMappingFactory factory)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   439
            throws OpenDataException {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   440
90ce3da70b43 Initial load
duke
parents:
diff changeset
   441
        final Type rawType = objType.getRawType();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   442
90ce3da70b43 Initial load
duke
parents:
diff changeset
   443
        if (rawType instanceof Class) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   444
            Class c = (Class<?>) rawType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   445
            if (c == List.class || c == Set.class || c == SortedSet.class) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   446
                Type[] actuals = objType.getActualTypeArguments();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   447
                assert(actuals.length == 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   448
                if (c == SortedSet.class)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   449
                    mustBeComparable(c, actuals[0]);
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   450
                return makeArrayOrCollectionMapping(objType, actuals[0], factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   451
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   452
                boolean sortedMap = (c == SortedMap.class);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   453
                if (c == Map.class || sortedMap) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   454
                    Type[] actuals = objType.getActualTypeArguments();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   455
                    assert(actuals.length == 2);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   456
                    if (sortedMap)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   457
                        mustBeComparable(c, actuals[0]);
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   458
                    return makeTabularMapping(objType, sortedMap,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   459
                            actuals[0], actuals[1], factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   460
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   461
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   462
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   463
        throw new OpenDataException("Cannot convert type: " + objType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   464
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   465
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   466
    private static MXBeanMapping makeMXBeanRefMapping(Type t)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   467
            throws OpenDataException {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   468
        return new MXBeanRefMapping(t);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   469
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   470
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   471
    private MXBeanMapping makeCompositeMapping(Class c,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   472
                                               MXBeanMappingFactory factory)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   473
            throws OpenDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   474
90ce3da70b43 Initial load
duke
parents:
diff changeset
   475
        // For historical reasons GcInfo implements CompositeData but we
90ce3da70b43 Initial load
duke
parents:
diff changeset
   476
        // shouldn't count its CompositeData.getCompositeType() field as
90ce3da70b43 Initial load
duke
parents:
diff changeset
   477
        // an item in the computed CompositeType.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   478
        final boolean gcInfoHack =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   479
            (c.getName().equals("com.sun.management.GcInfo") &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
   480
                c.getClassLoader() == null);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   481
90ce3da70b43 Initial load
duke
parents:
diff changeset
   482
        final List<Method> methods =
287
bff5501b2a02 6610917: Define a generic NotificationFilter
emcmanus
parents: 268
diff changeset
   483
                MBeanAnalyzer.eliminateCovariantMethods(Arrays.asList(c.getMethods()));
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   484
        final SortedMap<String,Method> getterMap = newSortedMap();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   485
90ce3da70b43 Initial load
duke
parents:
diff changeset
   486
        /* Select public methods that look like "T getX()" or "boolean
90ce3da70b43 Initial load
duke
parents:
diff changeset
   487
           isX()", where T is not void and X is not the empty
90ce3da70b43 Initial load
duke
parents:
diff changeset
   488
           string.  Exclude "Class getClass()" inherited from Object.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   489
        for (Method method : methods) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   490
            final String propertyName = propertyName(method);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   491
90ce3da70b43 Initial load
duke
parents:
diff changeset
   492
            if (propertyName == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   493
                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   494
            if (gcInfoHack && propertyName.equals("CompositeType"))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   495
                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   496
90ce3da70b43 Initial load
duke
parents:
diff changeset
   497
            Method old =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   498
                getterMap.put(decapitalize(propertyName),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   499
                            method);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   500
            if (old != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   501
                final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   502
                    "Class " + c.getName() + " has method name clash: " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   503
                    old.getName() + ", " + method.getName();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   504
                throw new OpenDataException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   505
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   506
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   507
90ce3da70b43 Initial load
duke
parents:
diff changeset
   508
        final int nitems = getterMap.size();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   509
90ce3da70b43 Initial load
duke
parents:
diff changeset
   510
        if (nitems == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   511
            throw new OpenDataException("Can't map " + c.getName() +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   512
                                        " to an open data type");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   513
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   514
90ce3da70b43 Initial load
duke
parents:
diff changeset
   515
        final Method[] getters = new Method[nitems];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   516
        final String[] itemNames = new String[nitems];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   517
        final OpenType[] openTypes = new OpenType[nitems];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   518
        int i = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   519
        for (Map.Entry<String,Method> entry : getterMap.entrySet()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   520
            itemNames[i] = entry.getKey();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   521
            final Method getter = entry.getValue();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   522
            getters[i] = getter;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   523
            final Type retType = getter.getGenericReturnType();
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   524
            openTypes[i] = factory.mappingForType(retType, factory).getOpenType();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   525
            i++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   526
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   527
90ce3da70b43 Initial load
duke
parents:
diff changeset
   528
        CompositeType compositeType =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   529
            new CompositeType(c.getName(),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   530
                              c.getName(),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   531
                              itemNames, // field names
90ce3da70b43 Initial load
duke
parents:
diff changeset
   532
                              itemNames, // field descriptions
90ce3da70b43 Initial load
duke
parents:
diff changeset
   533
                              openTypes);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   534
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   535
        return new CompositeMapping(c,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   536
                                    compositeType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   537
                                    itemNames,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   538
                                    getters,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   539
                                    factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   540
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   541
90ce3da70b43 Initial load
duke
parents:
diff changeset
   542
    /* Converter for classes where the open data is identical to the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   543
       original data.  This is true for any of the SimpleType types,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   544
       and for an any-dimension array of those.  It is also true for
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   545
       primitive types as of JMX 1.3, since an int[]
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   546
       can be directly represented by an ArrayType, and an int needs no mapping
90ce3da70b43 Initial load
duke
parents:
diff changeset
   547
       because reflection takes care of it.  */
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   548
    private static final class IdentityMapping extends NonNullMXBeanMapping {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   549
        IdentityMapping(Type targetType, OpenType openType) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   550
            super(targetType, openType);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   551
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   552
90ce3da70b43 Initial load
duke
parents:
diff changeset
   553
        boolean isIdentity() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   554
            return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   555
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   556
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   557
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   558
        Object fromNonNullOpenValue(Object openValue)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   559
        throws InvalidObjectException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   560
            return openValue;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   561
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   562
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   563
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   564
        Object toNonNullOpenValue(Object javaValue) throws OpenDataException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   565
            return javaValue;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   566
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   567
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   568
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   569
    private static final class EnumMapping<T extends Enum<T>>
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   570
            extends NonNullMXBeanMapping {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   571
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   572
        EnumMapping(Class<T> enumClass) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   573
            super(enumClass, SimpleType.STRING);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   574
            this.enumClass = enumClass;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   575
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   576
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   577
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   578
        final Object toNonNullOpenValue(Object value) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   579
            return ((Enum) value).name();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   580
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   581
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   582
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   583
        final T fromNonNullOpenValue(Object value)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   584
                throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   585
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   586
                return Enum.valueOf(enumClass, (String) value);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   587
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   588
                throw invalidObjectException("Cannot convert to enum: " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   589
                                             value, e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   590
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   591
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   592
90ce3da70b43 Initial load
duke
parents:
diff changeset
   593
        private final Class<T> enumClass;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   594
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   595
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   596
    private static final class ArrayMapping extends NonNullMXBeanMapping {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   597
        ArrayMapping(Type targetType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   598
                     ArrayType openArrayType, Class openArrayClass,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   599
                     MXBeanMapping elementMapping) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   600
            super(targetType, openArrayType);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   601
            this.elementMapping = elementMapping;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   602
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   603
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   604
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   605
        final Object toNonNullOpenValue(Object value)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   606
                throws OpenDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   607
            Object[] valueArray = (Object[]) value;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   608
            final int len = valueArray.length;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   609
            final Object[] openArray = (Object[])
90ce3da70b43 Initial load
duke
parents:
diff changeset
   610
                Array.newInstance(getOpenClass().getComponentType(), len);
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   611
            for (int i = 0; i < len; i++)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   612
                openArray[i] = elementMapping.toOpenValue(valueArray[i]);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   613
            return openArray;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   614
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   615
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   616
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   617
        final Object fromNonNullOpenValue(Object openValue)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   618
                throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   619
            final Object[] openArray = (Object[]) openValue;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   620
            final Type javaType = getJavaType();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   621
            final Object[] valueArray;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   622
            final Type componentType;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   623
            if (javaType instanceof GenericArrayType) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   624
                componentType =
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   625
                    ((GenericArrayType) javaType).getGenericComponentType();
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   626
            } else if (javaType instanceof Class &&
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   627
                       ((Class<?>) javaType).isArray()) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   628
                componentType = ((Class<?>) javaType).getComponentType();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   629
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   630
                throw new IllegalArgumentException("Not an array: " +
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   631
                                                   javaType);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   632
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   633
            valueArray = (Object[]) Array.newInstance((Class<?>) componentType,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   634
                                                      openArray.length);
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   635
            for (int i = 0; i < openArray.length; i++)
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   636
                valueArray[i] = elementMapping.fromOpenValue(openArray[i]);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   637
            return valueArray;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   638
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   639
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   640
        public void checkReconstructible() throws InvalidObjectException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   641
            elementMapping.checkReconstructible();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   642
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   643
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   644
        /**
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   645
         * DefaultMXBeanMappingFactory for the elements of this array.  If this is an
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   646
         *          array of arrays, the converter converts the second-level arrays,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   647
         *          not the deepest elements.
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   648
         */
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   649
        private final MXBeanMapping elementMapping;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   650
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   651
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   652
    private static final class CollectionMapping extends NonNullMXBeanMapping {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   653
        CollectionMapping(Type targetType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   654
                          ArrayType openArrayType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   655
                          Class openArrayClass,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   656
                          MXBeanMapping elementMapping) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   657
            super(targetType, openArrayType);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   658
            this.elementMapping = elementMapping;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   659
90ce3da70b43 Initial load
duke
parents:
diff changeset
   660
            /* Determine the concrete class to be used when converting
90ce3da70b43 Initial load
duke
parents:
diff changeset
   661
               back to this Java type.  We convert all Lists to ArrayList
90ce3da70b43 Initial load
duke
parents:
diff changeset
   662
               and all Sets to TreeSet.  (TreeSet because it is a SortedSet,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   663
               so works for both Set and SortedSet.)  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   664
            Type raw = ((ParameterizedType) targetType).getRawType();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   665
            Class c = (Class<?>) raw;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   666
            if (c == List.class)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   667
                collectionClass = ArrayList.class;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   668
            else if (c == Set.class)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   669
                collectionClass = HashSet.class;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   670
            else if (c == SortedSet.class)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   671
                collectionClass = TreeSet.class;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   672
            else { // can't happen
90ce3da70b43 Initial load
duke
parents:
diff changeset
   673
                assert(false);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   674
                collectionClass = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   675
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   676
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   677
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   678
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   679
        final Object toNonNullOpenValue(Object value)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   680
                throws OpenDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   681
            final Collection valueCollection = (Collection) value;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   682
            if (valueCollection instanceof SortedSet) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   683
                Comparator comparator =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   684
                    ((SortedSet) valueCollection).comparator();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   685
                if (comparator != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   686
                    final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   687
                        "Cannot convert SortedSet with non-null comparator: " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   688
                        comparator;
831
50f701930577 6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents: 687
diff changeset
   689
                    throw openDataException(msg, new IllegalArgumentException(msg));
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   690
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   691
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   692
            final Object[] openArray = (Object[])
90ce3da70b43 Initial load
duke
parents:
diff changeset
   693
                Array.newInstance(getOpenClass().getComponentType(),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   694
                                  valueCollection.size());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   695
            int i = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   696
            for (Object o : valueCollection)
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   697
                openArray[i++] = elementMapping.toOpenValue(o);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   698
            return openArray;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   699
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   700
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   701
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   702
        final Object fromNonNullOpenValue(Object openValue)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   703
                throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   704
            final Object[] openArray = (Object[]) openValue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   705
            final Collection<Object> valueCollection;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   706
            try {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   707
                valueCollection = cast(collectionClass.newInstance());
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   708
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   709
                throw invalidObjectException("Cannot create collection", e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   710
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   711
            for (Object o : openArray) {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   712
                Object value = elementMapping.fromOpenValue(o);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   713
                if (!valueCollection.add(value)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   714
                    final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   715
                        "Could not add " + o + " to " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   716
                        collectionClass.getName() +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   717
                        " (duplicate set element?)";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   718
                    throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   719
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   720
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   721
            return valueCollection;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   722
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   723
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   724
        public void checkReconstructible() throws InvalidObjectException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   725
            elementMapping.checkReconstructible();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   726
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   727
90ce3da70b43 Initial load
duke
parents:
diff changeset
   728
        private final Class<? extends Collection> collectionClass;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   729
        private final MXBeanMapping elementMapping;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   730
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   731
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   732
    private static final class MXBeanRefMapping extends NonNullMXBeanMapping {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   733
        MXBeanRefMapping(Type intf) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   734
            super(intf, SimpleType.OBJECTNAME);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   735
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   736
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   737
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   738
        final Object toNonNullOpenValue(Object javaValue)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   739
                throws OpenDataException {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   740
            MXBeanLookup lookup = lookupNotNull(OpenDataException.class);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   741
            ObjectName name = lookup.mxbeanToObjectName(javaValue);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   742
            if (name == null)
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   743
                throw new OpenDataException("No name for object: " + javaValue);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   744
            return name;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   745
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   746
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   747
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   748
        final Object fromNonNullOpenValue(Object openValue)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   749
                throws InvalidObjectException {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   750
            MXBeanLookup lookup = lookupNotNull(InvalidObjectException.class);
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   751
            ObjectName name = (ObjectName) openValue;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   752
            Object mxbean =
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   753
                lookup.objectNameToMXBean(name, (Class<?>) getJavaType());
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   754
            if (mxbean == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   755
                final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   756
                    "No MXBean for name: " + name;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   757
                throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   758
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   759
            return mxbean;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   760
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   761
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   762
        private <T extends Exception> MXBeanLookup
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   763
            lookupNotNull(Class<T> excClass)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   764
                throws T {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   765
            MXBeanLookup lookup = MXBeanLookup.getLookup();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   766
            if (lookup == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   767
                final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   768
                    "Cannot convert MXBean interface in this context";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   769
                T exc;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   770
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   771
                    Constructor<T> con = excClass.getConstructor(String.class);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   772
                    exc = con.newInstance(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   773
                } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   774
                    throw new RuntimeException(e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   775
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   776
                throw exc;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   777
            }
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   778
            return lookup;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   779
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   780
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   781
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   782
    private static final class TabularMapping extends NonNullMXBeanMapping {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   783
        TabularMapping(Type targetType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   784
                       boolean sortedMap,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   785
                       TabularType tabularType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   786
                       MXBeanMapping keyConverter,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   787
                       MXBeanMapping valueConverter) {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   788
            super(targetType, tabularType);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   789
            this.sortedMap = sortedMap;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   790
            this.keyMapping = keyConverter;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   791
            this.valueMapping = valueConverter;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   792
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   793
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   794
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   795
        final Object toNonNullOpenValue(Object value) throws OpenDataException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   796
            final Map<Object, Object> valueMap = cast(value);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   797
            if (valueMap instanceof SortedMap) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   798
                Comparator comparator = ((SortedMap) valueMap).comparator();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   799
                if (comparator != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   800
                    final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   801
                        "Cannot convert SortedMap with non-null comparator: " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   802
                        comparator;
831
50f701930577 6601652: MXBeans: no IllegalArgumentException in the ex. chain for SortedSet/Map with a non-null comparator()
emcmanus
parents: 687
diff changeset
   803
                    throw openDataException(msg, new IllegalArgumentException(msg));
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   804
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   805
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   806
            final TabularType tabularType = (TabularType) getOpenType();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   807
            final TabularData table = new TabularDataSupport(tabularType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   808
            final CompositeType rowType = tabularType.getRowType();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   809
            for (Map.Entry entry : valueMap.entrySet()) {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   810
                final Object openKey = keyMapping.toOpenValue(entry.getKey());
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   811
                final Object openValue = valueMapping.toOpenValue(entry.getValue());
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   812
                final CompositeData row;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   813
                row =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   814
                    new CompositeDataSupport(rowType, keyValueArray,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   815
                                             new Object[] {openKey,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   816
                                                           openValue});
90ce3da70b43 Initial load
duke
parents:
diff changeset
   817
                table.put(row);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   818
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   819
            return table;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   820
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   821
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   822
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   823
        final Object fromNonNullOpenValue(Object openValue)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   824
                throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   825
            final TabularData table = (TabularData) openValue;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   826
            final Collection<CompositeData> rows = cast(table.values());
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   827
            final Map<Object, Object> valueMap =
1018
9f07e65e9653 6334663: TabularDataSupport should be able to return values in the insertion order
emcmanus
parents: 832
diff changeset
   828
                sortedMap ? newSortedMap() : newInsertionOrderMap();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   829
            for (CompositeData row : rows) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   830
                final Object key =
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   831
                    keyMapping.fromOpenValue(row.get("key"));
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   832
                final Object value =
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   833
                    valueMapping.fromOpenValue(row.get("value"));
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   834
                if (valueMap.put(key, value) != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   835
                    final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   836
                        "Duplicate entry in TabularData: key=" + key;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   837
                    throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   838
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   839
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   840
            return valueMap;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   841
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   842
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   843
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   844
        public void checkReconstructible() throws InvalidObjectException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   845
            keyMapping.checkReconstructible();
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   846
            valueMapping.checkReconstructible();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   847
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   848
90ce3da70b43 Initial load
duke
parents:
diff changeset
   849
        private final boolean sortedMap;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   850
        private final MXBeanMapping keyMapping;
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   851
        private final MXBeanMapping valueMapping;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   852
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   853
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   854
    private final class CompositeMapping extends NonNullMXBeanMapping {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   855
        CompositeMapping(Class targetClass,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   856
                         CompositeType compositeType,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   857
                         String[] itemNames,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   858
                         Method[] getters,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   859
                         MXBeanMappingFactory factory) throws OpenDataException {
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   860
            super(targetClass, compositeType);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   861
90ce3da70b43 Initial load
duke
parents:
diff changeset
   862
            assert(itemNames.length == getters.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   863
90ce3da70b43 Initial load
duke
parents:
diff changeset
   864
            this.itemNames = itemNames;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   865
            this.getters = getters;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   866
            this.getterMappings = new MXBeanMapping[getters.length];
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   867
            for (int i = 0; i < getters.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   868
                Type retType = getters[i].getGenericReturnType();
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   869
                getterMappings[i] = factory.mappingForType(retType, factory);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   870
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   871
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   872
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   873
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   874
        final Object toNonNullOpenValue(Object value)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   875
                throws OpenDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   876
            CompositeType ct = (CompositeType) getOpenType();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   877
            if (value instanceof CompositeDataView)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   878
                return ((CompositeDataView) value).toCompositeData(ct);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   879
            if (value == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   880
                return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   881
90ce3da70b43 Initial load
duke
parents:
diff changeset
   882
            Object[] values = new Object[getters.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   883
            for (int i = 0; i < getters.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   884
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   885
                    Object got = getters[i].invoke(value, (Object[]) null);
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   886
                    values[i] = getterMappings[i].toOpenValue(got);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   887
                } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   888
                    throw openDataException("Error calling getter for " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   889
                                            itemNames[i] + ": " + e, e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   890
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   891
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   892
            return new CompositeDataSupport(ct, itemNames, values);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   893
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   894
90ce3da70b43 Initial load
duke
parents:
diff changeset
   895
        /** Determine how to convert back from the CompositeData into
90ce3da70b43 Initial load
duke
parents:
diff changeset
   896
            the original Java type.  For a type that is not reconstructible,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   897
            this method will fail every time, and will throw the right
90ce3da70b43 Initial load
duke
parents:
diff changeset
   898
            exception. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   899
        private synchronized void makeCompositeBuilder()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   900
                throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   901
            if (compositeBuilder != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   902
                return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   903
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   904
            Class targetClass = (Class<?>) getJavaType();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   905
            /* In this 2D array, each subarray is a set of builders where
90ce3da70b43 Initial load
duke
parents:
diff changeset
   906
               there is no point in consulting the ones after the first if
90ce3da70b43 Initial load
duke
parents:
diff changeset
   907
               the first refuses.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   908
            CompositeBuilder[][] builders = {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   909
                {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   910
                    new CompositeBuilderViaFrom(targetClass, itemNames),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   911
                },
90ce3da70b43 Initial load
duke
parents:
diff changeset
   912
                {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   913
                    new CompositeBuilderViaConstructor(targetClass, itemNames),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   914
                },
90ce3da70b43 Initial load
duke
parents:
diff changeset
   915
                {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   916
                    new CompositeBuilderCheckGetters(targetClass, itemNames,
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   917
                                                     getterMappings),
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   918
                    new CompositeBuilderViaSetters(targetClass, itemNames),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   919
                    new CompositeBuilderViaProxy(targetClass, itemNames),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   920
                },
90ce3da70b43 Initial load
duke
parents:
diff changeset
   921
            };
90ce3da70b43 Initial load
duke
parents:
diff changeset
   922
            CompositeBuilder foundBuilder = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   923
            /* We try to make a meaningful exception message by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   924
               concatenating each Builder's explanation of why it
90ce3da70b43 Initial load
duke
parents:
diff changeset
   925
               isn't applicable.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   926
            final StringBuilder whyNots = new StringBuilder();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   927
        find:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   928
            for (CompositeBuilder[] relatedBuilders : builders) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   929
                for (int i = 0; i < relatedBuilders.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   930
                    CompositeBuilder builder = relatedBuilders[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   931
                    String whyNot = builder.applicable(getters);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   932
                    if (whyNot == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   933
                        foundBuilder = builder;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   934
                        break find;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   935
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   936
                    if (whyNot.length() > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   937
                        if (whyNots.length() > 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   938
                            whyNots.append("; ");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   939
                        whyNots.append(whyNot);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   940
                        if (i == 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   941
                           break; // skip other builders in this group
90ce3da70b43 Initial load
duke
parents:
diff changeset
   942
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   943
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   944
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   945
            if (foundBuilder == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   946
                final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   947
                    "Do not know how to make a " + targetClass.getName() +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   948
                    " from a CompositeData: " + whyNots;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   949
                throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   950
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   951
            compositeBuilder = foundBuilder;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   952
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   953
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   954
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   955
        public void checkReconstructible() throws InvalidObjectException {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   956
            makeCompositeBuilder();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   957
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   958
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   959
        @Override
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   960
        final Object fromNonNullOpenValue(Object value)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   961
                throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   962
            makeCompositeBuilder();
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   963
            return compositeBuilder.fromCompositeData((CompositeData) value,
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   964
                                                      itemNames,
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   965
                                                      getterMappings);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   966
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   967
90ce3da70b43 Initial load
duke
parents:
diff changeset
   968
        private final String[] itemNames;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   969
        private final Method[] getters;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   970
        private final MXBeanMapping[] getterMappings;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   971
        private CompositeBuilder compositeBuilder;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   972
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   973
90ce3da70b43 Initial load
duke
parents:
diff changeset
   974
    /** Converts from a CompositeData to an instance of the targetClass.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   975
    private static abstract class CompositeBuilder {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   976
        CompositeBuilder(Class targetClass, String[] itemNames) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   977
            this.targetClass = targetClass;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   978
            this.itemNames = itemNames;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   979
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   980
90ce3da70b43 Initial load
duke
parents:
diff changeset
   981
        Class<?> getTargetClass() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   982
            return targetClass;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   983
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   984
90ce3da70b43 Initial load
duke
parents:
diff changeset
   985
        String[] getItemNames() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   986
            return itemNames;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   987
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   988
90ce3da70b43 Initial load
duke
parents:
diff changeset
   989
        /** If the subclass is appropriate for targetClass, then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   990
            method returns null.  If the subclass is not appropriate,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   991
            then the method returns an explanation of why not.  If the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   992
            subclass should be appropriate but there is a problem,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   993
            then the method throws InvalidObjectException.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   994
        abstract String applicable(Method[] getters)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   995
                throws InvalidObjectException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   996
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   997
        abstract Object fromCompositeData(CompositeData cd,
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   998
                                          String[] itemNames,
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
   999
                                          MXBeanMapping[] converters)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1000
                throws InvalidObjectException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1001
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1002
        private final Class<?> targetClass;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1003
        private final String[] itemNames;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1004
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1005
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1006
    /** Builder for when the target class has a method "public static
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1007
        from(CompositeData)".  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1008
    private static final class CompositeBuilderViaFrom
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1009
            extends CompositeBuilder {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1010
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1011
        CompositeBuilderViaFrom(Class targetClass, String[] itemNames) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1012
            super(targetClass, itemNames);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1013
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1014
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1015
        String applicable(Method[] getters) throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1016
            // See if it has a method "T from(CompositeData)"
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1017
            // as is conventional for a CompositeDataView
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1018
            Class<?> targetClass = getTargetClass();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1019
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1020
                Method fromMethod =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1021
                    targetClass.getMethod("from",
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1022
                                          new Class[] {CompositeData.class});
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1023
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1024
                if (!Modifier.isStatic(fromMethod.getModifiers())) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1025
                    final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1026
                        "Method from(CompositeData) is not static";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1027
                    throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1028
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1029
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1030
                if (fromMethod.getReturnType() != getTargetClass()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1031
                    final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1032
                        "Method from(CompositeData) returns " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1033
                        fromMethod.getReturnType().getName() +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1034
                        " not " + targetClass.getName();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1035
                    throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1036
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1037
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1038
                this.fromMethod = fromMethod;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1039
                return null; // success!
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1040
            } catch (InvalidObjectException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1041
                throw e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1042
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1043
                // OK: it doesn't have the method
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1044
                return "no method from(CompositeData)";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1045
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1046
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1047
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1048
        final Object fromCompositeData(CompositeData cd,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1049
                                       String[] itemNames,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1050
                                       MXBeanMapping[] converters)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1051
                throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1052
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1053
                return fromMethod.invoke(null, cd);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1054
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1055
                final String msg = "Failed to invoke from(CompositeData)";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1056
                throw invalidObjectException(msg, e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1057
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1058
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1059
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1060
        private Method fromMethod;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1061
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1062
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1063
    /** This builder never actually returns success.  It simply serves
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1064
        to check whether the other builders in the same group have any
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1065
        chance of success.  If any getter in the targetClass returns
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1066
        a type that we don't know how to reconstruct, then we will
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1067
        not be able to make a builder, and there is no point in repeating
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1068
        the error about the problematic getter as many times as there are
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1069
        candidate builders.  Instead, the "applicable" method will return
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1070
        an explanatory string, and the other builders will be skipped.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1071
        If all the getters are OK, then the "applicable" method will return
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1072
        an empty string and the other builders will be tried.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1073
    private static class CompositeBuilderCheckGetters extends CompositeBuilder {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1074
        CompositeBuilderCheckGetters(Class targetClass, String[] itemNames,
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1075
                                     MXBeanMapping[] getterConverters) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1076
            super(targetClass, itemNames);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1077
            this.getterConverters = getterConverters;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1078
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1079
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1080
        String applicable(Method[] getters) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1081
            for (int i = 0; i < getters.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1082
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1083
                    getterConverters[i].checkReconstructible();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1084
                } catch (InvalidObjectException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1085
                    return "method " + getters[i].getName() + " returns type " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1086
                        "that cannot be mapped back from OpenData";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1087
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1088
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1089
            return "";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1090
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1091
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1092
        final Object fromCompositeData(CompositeData cd,
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1093
                                       String[] itemNames,
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1094
                                       MXBeanMapping[] converters) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1095
            throw new Error();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1096
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1097
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1098
        private final MXBeanMapping[] getterConverters;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1099
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1100
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1101
    /** Builder for when the target class has a setter for every getter. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1102
    private static class CompositeBuilderViaSetters extends CompositeBuilder {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1103
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1104
        CompositeBuilderViaSetters(Class<?> targetClass, String[] itemNames) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1105
            super(targetClass, itemNames);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1106
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1107
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1108
        String applicable(Method[] getters) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1109
            try {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1110
                Constructor<?> c = getTargetClass().getConstructor();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1111
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1112
                return "does not have a public no-arg constructor";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1113
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1114
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1115
            Method[] setters = new Method[getters.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1116
            for (int i = 0; i < getters.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1117
                Method getter = getters[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1118
                Class returnType = getter.getReturnType();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1119
                String name = propertyName(getter);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1120
                String setterName = "set" + name;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1121
                Method setter;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1122
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1123
                    setter = getTargetClass().getMethod(setterName, returnType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1124
                    if (setter.getReturnType() != void.class)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1125
                        throw new Exception();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1126
                } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1127
                    return "not all getters have corresponding setters " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1128
                           "(" + getter + ")";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1129
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1130
                setters[i] = setter;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1131
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1132
            this.setters = setters;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1133
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1134
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1135
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1136
        Object fromCompositeData(CompositeData cd,
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1137
                                 String[] itemNames,
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1138
                                 MXBeanMapping[] converters)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1139
                throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1140
            Object o;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1141
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1142
                o = getTargetClass().newInstance();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1143
                for (int i = 0; i < itemNames.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1144
                    if (cd.containsKey(itemNames[i])) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1145
                        Object openItem = cd.get(itemNames[i]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1146
                        Object javaItem =
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1147
                            converters[i].fromOpenValue(openItem);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1148
                        setters[i].invoke(o, javaItem);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1149
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1150
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1151
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1152
                throw invalidObjectException(e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1153
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1154
            return o;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1155
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1156
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1157
        private Method[] setters;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1158
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1159
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1160
    /** Builder for when the target class has a constructor that is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1161
        annotated with @ConstructorProperties so we can see the correspondence
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1162
        to getters.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1163
    private static final class CompositeBuilderViaConstructor
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1164
            extends CompositeBuilder {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1165
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1166
        CompositeBuilderViaConstructor(Class targetClass, String[] itemNames) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1167
            super(targetClass, itemNames);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1168
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1169
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1170
        String applicable(Method[] getters) throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1171
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1172
            final Class<ConstructorProperties> propertyNamesClass = ConstructorProperties.class;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1173
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1174
            Class targetClass = getTargetClass();
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1175
            Constructor[] constrs = targetClass.getConstructors();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1176
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1177
            // Applicable if and only if there are any annotated constructors
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1178
            List<Constructor> annotatedConstrList = newList();
268
aa06754a95de 6643627: JMX source code includes incorrect Java code
emcmanus
parents: 2
diff changeset
  1179
            for (Constructor<?> constr : constrs) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1180
                if (Modifier.isPublic(constr.getModifiers())
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1181
                        && constr.getAnnotation(propertyNamesClass) != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1182
                    annotatedConstrList.add(constr);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1183
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1184
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1185
            if (annotatedConstrList.isEmpty())
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1186
                return "no constructor has @ConstructorProperties annotation";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1187
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1188
            annotatedConstructors = newList();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1189
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1190
            // Now check that all the annotated constructors are valid
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1191
            // and throw an exception if not.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1192
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1193
            // First link the itemNames to their getter indexes.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1194
            Map<String, Integer> getterMap = newMap();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1195
            String[] itemNames = getItemNames();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1196
            for (int i = 0; i < itemNames.length; i++)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1197
                getterMap.put(itemNames[i], i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1198
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1199
            // Run through the constructors making the checks in the spec.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1200
            // For each constructor, remember the correspondence between its
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1201
            // parameters and the items.  The int[] for a constructor says
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1202
            // what parameter index should get what item.  For example,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1203
            // if element 0 is 2 then that means that item 0 in the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1204
            // CompositeData goes to parameter 2 of the constructor.  If an
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1205
            // element is -1, that item isn't given to the constructor.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1206
            // Also remember the set of properties in that constructor
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1207
            // so we can test unambiguity.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1208
            Set<BitSet> getterIndexSets = newSet();
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1209
            for (Constructor constr : annotatedConstrList) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1210
                String[] propertyNames =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1211
                    constr.getAnnotation(propertyNamesClass).value();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1212
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1213
                Type[] paramTypes = constr.getGenericParameterTypes();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1214
                if (paramTypes.length != propertyNames.length) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1215
                    final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1216
                        "Number of constructor params does not match " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1217
                        "@ConstructorProperties annotation: " + constr;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1218
                    throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1219
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1220
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1221
                int[] paramIndexes = new int[getters.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1222
                for (int i = 0; i < getters.length; i++)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1223
                    paramIndexes[i] = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1224
                BitSet present = new BitSet();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1225
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1226
                for (int i = 0; i < propertyNames.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1227
                    String propertyName = propertyNames[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1228
                    if (!getterMap.containsKey(propertyName)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1229
                        final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1230
                            "@ConstructorProperties includes name " + propertyName +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1231
                            " which does not correspond to a property: " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1232
                            constr;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1233
                        throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1234
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1235
                    int getterIndex = getterMap.get(propertyName);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1236
                    paramIndexes[getterIndex] = i;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1237
                    if (present.get(getterIndex)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1238
                        final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1239
                            "@ConstructorProperties contains property " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1240
                            propertyName + " more than once: " + constr;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1241
                        throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1242
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1243
                    present.set(getterIndex);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1244
                    Method getter = getters[getterIndex];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1245
                    Type propertyType = getter.getGenericReturnType();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1246
                    if (!propertyType.equals(paramTypes[i])) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1247
                        final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1248
                            "@ConstructorProperties gives property " + propertyName +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1249
                            " of type " + propertyType + " for parameter " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1250
                            " of type " + paramTypes[i] + ": " + constr;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1251
                        throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1252
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1253
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1254
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1255
                if (!getterIndexSets.add(present)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1256
                    final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1257
                        "More than one constructor has a @ConstructorProperties " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1258
                        "annotation with this set of names: " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1259
                        Arrays.toString(propertyNames);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1260
                    throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1261
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1262
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1263
                Constr c = new Constr(constr, paramIndexes, present);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1264
                annotatedConstructors.add(c);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1265
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1266
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1267
            /* Check that no possible set of items could lead to an ambiguous
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1268
             * choice of constructor (spec requires this check).  For any
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1269
             * pair of constructors, their union would be the minimal
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1270
             * ambiguous set.  If this set itself corresponds to a constructor,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1271
             * there is no ambiguity for that pair.  In the usual case, one
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1272
             * of the constructors is a superset of the other so the union is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1273
             * just the bigger constuctor.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1274
             *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1275
             * The algorithm here is quadratic in the number of constructors
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1276
             * with a @ConstructorProperties annotation.  Typically this corresponds
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1277
             * to the number of versions of the class there have been.  Ten
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1278
             * would already be a large number, so although it's probably
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1279
             * possible to have an O(n lg n) algorithm it wouldn't be
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1280
             * worth the complexity.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1281
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1282
            for (BitSet a : getterIndexSets) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1283
                boolean seen = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1284
                for (BitSet b : getterIndexSets) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1285
                    if (a == b)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1286
                        seen = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1287
                    else if (seen) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1288
                        BitSet u = new BitSet();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1289
                        u.or(a); u.or(b);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1290
                        if (!getterIndexSets.contains(u)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1291
                            Set<String> names = new TreeSet<String>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1292
                            for (int i = u.nextSetBit(0); i >= 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1293
                                 i = u.nextSetBit(i+1))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1294
                                names.add(itemNames[i]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1295
                            final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1296
                                "Constructors with @ConstructorProperties annotation " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1297
                                " would be ambiguous for these items: " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1298
                                names;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1299
                            throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1300
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1301
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1302
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1303
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1304
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1305
            return null; // success!
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1306
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1307
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1308
        final Object fromCompositeData(CompositeData cd,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1309
                                       String[] itemNames,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1310
                                       MXBeanMapping[] mappings)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1311
                throws InvalidObjectException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1312
            // The CompositeData might come from an earlier version where
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1313
            // not all the items were present.  We look for a constructor
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1314
            // that accepts just the items that are present.  Because of
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1315
            // the ambiguity check in applicable(), we know there must be
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1316
            // at most one maximally applicable constructor.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1317
            CompositeType ct = cd.getCompositeType();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1318
            BitSet present = new BitSet();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1319
            for (int i = 0; i < itemNames.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1320
                if (ct.getType(itemNames[i]) != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1321
                    present.set(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1322
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1323
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1324
            Constr max = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1325
            for (Constr constr : annotatedConstructors) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1326
                if (subset(constr.presentParams, present) &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1327
                        (max == null ||
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1328
                         subset(max.presentParams, constr.presentParams)))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1329
                    max = constr;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1330
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1331
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1332
            if (max == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1333
                final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1334
                    "No constructor has a @ConstructorProperties for this set of " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1335
                    "items: " + ct.keySet();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1336
                throw new InvalidObjectException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1337
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1338
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1339
            Object[] params = new Object[max.presentParams.cardinality()];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1340
            for (int i = 0; i < itemNames.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1341
                if (!max.presentParams.get(i))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1342
                    continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1343
                Object openItem = cd.get(itemNames[i]);
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1344
                Object javaItem = mappings[i].fromOpenValue(openItem);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1345
                int index = max.paramIndexes[i];
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1346
                if (index >= 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1347
                    params[index] = javaItem;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1348
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1349
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1350
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1351
                return max.constructor.newInstance(params);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1352
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1353
                final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1354
                    "Exception constructing " + getTargetClass().getName();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1355
                throw invalidObjectException(msg, e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1356
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1357
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1358
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1359
        private static boolean subset(BitSet sub, BitSet sup) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1360
            BitSet subcopy = (BitSet) sub.clone();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1361
            subcopy.andNot(sup);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1362
            return subcopy.isEmpty();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1363
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1364
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1365
        private static class Constr {
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1366
            final Constructor constructor;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1367
            final int[] paramIndexes;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1368
            final BitSet presentParams;
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1369
            Constr(Constructor constructor, int[] paramIndexes,
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1370
                   BitSet presentParams) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1371
                this.constructor = constructor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1372
                this.paramIndexes = paramIndexes;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1373
                this.presentParams = presentParams;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1374
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1375
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1376
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1377
        private List<Constr> annotatedConstructors;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1378
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1379
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1380
    /** Builder for when the target class is an interface and contains
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1381
        no methods other than getters.  Then we can make an instance
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1382
        using a dynamic proxy that forwards the getters to the source
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1383
        CompositeData.  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1384
    private static final class CompositeBuilderViaProxy
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1385
            extends CompositeBuilder {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1386
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1387
        CompositeBuilderViaProxy(Class targetClass, String[] itemNames) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1388
            super(targetClass, itemNames);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1389
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1390
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1391
        String applicable(Method[] getters) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1392
            Class targetClass = getTargetClass();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1393
            if (!targetClass.isInterface())
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1394
                return "not an interface";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1395
            Set<Method> methods =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1396
                newSet(Arrays.asList(targetClass.getMethods()));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1397
            methods.removeAll(Arrays.asList(getters));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1398
            /* If the interface has any methods left over, they better be
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1399
             * public methods that are already present in java.lang.Object.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1400
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1401
            String bad = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1402
            for (Method m : methods) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1403
                String mname = m.getName();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1404
                Class[] mparams = m.getParameterTypes();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1405
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1406
                    Method om = Object.class.getMethod(mname, mparams);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1407
                    if (!Modifier.isPublic(om.getModifiers()))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1408
                        bad = mname;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1409
                } catch (NoSuchMethodException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1410
                    bad = mname;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1411
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1412
                /* We don't catch SecurityException since it shouldn't
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1413
                 * happen for a method in Object and if it does we would
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1414
                 * like to know about it rather than mysteriously complaining.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1415
                 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1416
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1417
            if (bad != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1418
                return "contains methods other than getters (" + bad + ")";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1419
            return null; // success!
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1420
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1421
687
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1422
        final Object fromCompositeData(CompositeData cd,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1423
                                       String[] itemNames,
874e25a9844a 6562936: Support custom type mappings in MXBeans
emcmanus
parents: 287
diff changeset
  1424
                                       MXBeanMapping[] converters) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1425
            final Class targetClass = getTargetClass();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1426
            return
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1427
                Proxy.newProxyInstance(targetClass.getClassLoader(),
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1428
                                       new Class[] {targetClass},
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1429
                                       new CompositeDataInvocationHandler(cd));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1430
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1431
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1432
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1433
    static InvalidObjectException invalidObjectException(String msg,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1434
                                                         Throwable cause) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1435
        return EnvHelp.initCause(new InvalidObjectException(msg), cause);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1436
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1437
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1438
    static InvalidObjectException invalidObjectException(Throwable cause) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1439
        return invalidObjectException(cause.getMessage(), cause);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1440
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1441
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1442
    static OpenDataException openDataException(String msg, Throwable cause) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1443
        return EnvHelp.initCause(new OpenDataException(msg), cause);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1444
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1445
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1446
    static OpenDataException openDataException(Throwable cause) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1447
        return openDataException(cause.getMessage(), cause);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1448
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1449
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1450
    static void mustBeComparable(Class collection, Type element)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1451
            throws OpenDataException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1452
        if (!(element instanceof Class)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1453
            || !Comparable.class.isAssignableFrom((Class<?>) element)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1454
            final String msg =
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1455
                "Parameter class " + element + " of " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1456
                collection.getName() + " does not implement " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1457
                Comparable.class.getName();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1458
            throw new OpenDataException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1459
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1460
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1461
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1462
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1463
     * Utility method to take a string and convert it to normal Java variable
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1464
     * name capitalization.  This normally means converting the first
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1465
     * character from upper case to lower case, but in the (unusual) special
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1466
     * case when there is more than one character and both the first and
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1467
     * second characters are upper case, we leave it alone.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1468
     * <p>
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1469
     * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1470
     * as "URL".
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1471
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1472
     * @param  name The string to be decapitalized.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1473
     * @return  The decapitalized version of the string.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1474
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1475
    public static String decapitalize(String name) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1476
        if (name == null || name.length() == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1477
            return name;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1478
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1479
        int offset1 = Character.offsetByCodePoints(name, 0, 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1480
        // Should be name.offsetByCodePoints but 6242664 makes this fail
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1481
        if (offset1 < name.length() &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1482
                Character.isUpperCase(name.codePointAt(offset1)))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1483
            return name;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1484
        return name.substring(0, offset1).toLowerCase() +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1485
               name.substring(offset1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1486
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1487
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1488
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1489
     * Reverse operation for java.beans.Introspector.decapitalize.  For any s,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1490
     * capitalize(decapitalize(s)).equals(s).  The reverse is not true:
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1491
     * e.g. capitalize("uRL") produces "URL" which is unchanged by
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1492
     * decapitalize.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1493
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1494
    static String capitalize(String name) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1495
        if (name == null || name.length() == 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1496
            return name;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1497
        int offset1 = name.offsetByCodePoints(0, 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1498
        return name.substring(0, offset1).toUpperCase() +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1499
               name.substring(offset1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1500
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1501
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1502
    public static String propertyName(Method m) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1503
        String rest = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1504
        String name = m.getName();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1505
        if (name.startsWith("get"))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1506
            rest = name.substring(3);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1507
        else if (name.startsWith("is") && m.getReturnType() == boolean.class)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1508
            rest = name.substring(2);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1509
        if (rest == null || rest.length() == 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1510
            || m.getParameterTypes().length > 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1511
            || m.getReturnType() == void.class
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1512
            || name.equals("getClass"))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1513
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1514
        return rest;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1515
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1516
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1517
    private final static Map<Type, Type> inProgress = newIdentityHashMap();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1518
    // really an IdentityHashSet but that doesn't exist
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1519
}