jdk/test/javax/management/Introspector/AnnotationTest.java
changeset 1570 4165709c91e3
parent 2 90ce3da70b43
child 1639 a97859015238
equal deleted inserted replaced
1569:54e1de48703e 1570:4165709c91e3
    37 import java.util.*;
    37 import java.util.*;
    38 import javax.management.*;
    38 import javax.management.*;
    39 
    39 
    40 /*
    40 /*
    41   This test checks that annotations produce Descriptor entries as
    41   This test checks that annotations produce Descriptor entries as
    42   specified in javax.management.DescriptorKey.  It does two things:
    42   specified in javax.management.DescriptorKey and javax.management.DescriptorField.
       
    43   It does the following:
    43 
    44 
    44   - An annotation consisting of an int and a String, each with an
    45   - An annotation consisting of an int and a String, each with an
    45     appropriate @DescriptorKey annotation, is placed on every program
    46     appropriate @DescriptorKey annotation, is placed on every program
    46     element where it can map to a Descriptor, namely:
    47     element where it can map to a Descriptor, namely:
    47 
    48 
    59     . on all of the above for an MXBean instead of an MBean
    60     . on all of the above for an MXBean instead of an MBean
    60 
    61 
    61     The test checks that in each case the corresponding Descriptor
    62     The test checks that in each case the corresponding Descriptor
    62     appears in the appropriate place inside the MBean's MBeanInfo.
    63     appears in the appropriate place inside the MBean's MBeanInfo.
    63 
    64 
       
    65  - A @DescriptorFields annotation defining two fields is placed in the
       
    66    same places and again the test checks that the two fields appear
       
    67    in the corresponding MBean*Info objects.
       
    68 
    64   - An annotation consisting of enough other types to ensure coverage
    69   - An annotation consisting of enough other types to ensure coverage
    65     is placed on a getter.  The test checks that the generated
    70     is placed on a getter.  The test checks that the generated
    66     MBeanAttributeInfo contains the corresponding Descriptor.  The tested
    71     MBeanAttributeInfo contains the corresponding Descriptor.  The tested
    67     types are the following:
    72     types are the following:
    68 
    73 
    75     . an array of enumeration type (RetentionPolicy[])
    80     . an array of enumeration type (RetentionPolicy[])
    76     . boolean[]
    81     . boolean[]
    77  */
    82  */
    78 public class AnnotationTest {
    83 public class AnnotationTest {
    79     private static String failed = null;
    84     private static String failed = null;
    80 
       
    81 //    @Retention(RetentionPolicy.RUNTIME) @Inherited
       
    82 //    @Target(ElementType.METHOD)
       
    83 //    public static @interface DescriptorKey {
       
    84 //        String value();
       
    85 //    }
       
    86 
    85 
    87     @Retention(RetentionPolicy.RUNTIME)
    86     @Retention(RetentionPolicy.RUNTIME)
    88     public static @interface Pair {
    87     public static @interface Pair {
    89         @DescriptorKey("x")
    88         @DescriptorKey("x")
    90         int x();
    89         int x();
   110         RetentionPolicy[] enumArrayValue();
   109         RetentionPolicy[] enumArrayValue();
   111         @DescriptorKey("booleanArray")
   110         @DescriptorKey("booleanArray")
   112         boolean[] booleanArrayValue();
   111         boolean[] booleanArrayValue();
   113     }
   112     }
   114 
   113 
   115     /* We use the annotation @Pair(x = 3, y = "foo") everywhere, and this is
   114     /* We use the annotations @Pair(x = 3, y = "foo")
   116        the Descriptor that it should produce: */
   115        and @DescriptorFields({"foo=bar", "baz="}) everywhere, and this is
       
   116        the Descriptor that they should produce: */
   117     private static Descriptor expectedDescriptor =
   117     private static Descriptor expectedDescriptor =
   118         new ImmutableDescriptor(new String[] {"x", "y"},
   118         new ImmutableDescriptor(new String[] {"x", "y", "foo", "baz"},
   119                                 new Object[] {3, "foo"});
   119                                 new Object[] {3, "foo", "bar", ""});
   120 
   120 
   121     private static Descriptor expectedFullDescriptor =
   121     private static Descriptor expectedFullDescriptor =
   122         new ImmutableDescriptor(new String[] {
   122         new ImmutableDescriptor(new String[] {
   123                                     "class", "enum", "boolean", "stringArray",
   123                                     "class", "enum", "boolean", "stringArray",
   124                                     "classArray", "intArray", "enumArray",
   124                                     "classArray", "intArray", "enumArray",
   134                                     new String[] {RetentionPolicy.RUNTIME.name()},
   134                                     new String[] {RetentionPolicy.RUNTIME.name()},
   135                                     new boolean[] {false, true},
   135                                     new boolean[] {false, true},
   136                                 });
   136                                 });
   137 
   137 
   138     @Pair(x = 3, y = "foo")
   138     @Pair(x = 3, y = "foo")
       
   139     @DescriptorFields({"foo=bar", "baz="})
   139     public static interface ThingMBean {
   140     public static interface ThingMBean {
   140         @Pair(x = 3, y = "foo")
   141         @Pair(x = 3, y = "foo")
       
   142         @DescriptorFields({"foo=bar", "baz="})
   141         @Full(classValue=Full.class,
   143         @Full(classValue=Full.class,
   142               enumValue=RetentionPolicy.RUNTIME,
   144               enumValue=RetentionPolicy.RUNTIME,
   143               booleanValue=false,
   145               booleanValue=false,
   144               stringArrayValue={"foo", "bar"},
   146               stringArrayValue={"foo", "bar"},
   145               classArrayValue={Full.class},
   147               classArrayValue={Full.class},
   147               enumArrayValue={RetentionPolicy.RUNTIME},
   149               enumArrayValue={RetentionPolicy.RUNTIME},
   148               booleanArrayValue={false, true})
   150               booleanArrayValue={false, true})
   149         int getReadOnly();
   151         int getReadOnly();
   150 
   152 
   151         @Pair(x = 3, y = "foo")
   153         @Pair(x = 3, y = "foo")
       
   154         @DescriptorFields({"foo=bar", "baz="})
   152         void setWriteOnly(int x);
   155         void setWriteOnly(int x);
   153 
   156 
   154         @Pair(x = 3, y = "foo")
   157         @Pair(x = 3, y = "foo")
       
   158         @DescriptorFields({"foo=bar", "baz="})
   155         int getReadWrite1();
   159         int getReadWrite1();
   156         void setReadWrite1(int x);
   160         void setReadWrite1(int x);
   157 
   161 
   158         @Pair(x = 3, y = "foo")
   162         @Pair(x = 3, y = "foo")
       
   163         @DescriptorFields({"foo=bar", "baz="})
   159         int getReadWrite2();
   164         int getReadWrite2();
   160         @Pair(x = 3, y = "foo")
   165         @Pair(x = 3, y = "foo")
       
   166         @DescriptorFields({"foo=bar", "baz="})
   161         void setReadWrite2(int x);
   167         void setReadWrite2(int x);
   162 
   168 
   163         int getReadWrite3();
   169         int getReadWrite3();
   164         @Pair(x = 3, y = "foo")
   170         @Pair(x = 3, y = "foo")
       
   171         @DescriptorFields({"foo=bar", "baz="})
   165         void setReadWrite3(int x);
   172         void setReadWrite3(int x);
   166 
   173 
   167         @Pair(x = 3, y = "foo")
   174         @Pair(x = 3, y = "foo")
   168         int operation(@Pair(x = 3, y = "foo") int p1,
   175         @DescriptorFields({"foo=bar", "baz="})
   169                       @Pair(x = 3, y = "foo") int p2);
   176         int operation(@Pair(x = 3, y = "foo")
       
   177                       @DescriptorFields({"foo=bar", "baz="})
       
   178                       int p1,
       
   179                       @Pair(x = 3, y = "foo")
       
   180                       @DescriptorFields({"foo=bar", "baz="})
       
   181                       int p2);
   170     }
   182     }
   171 
   183 
   172     public static class Thing implements ThingMBean {
   184     public static class Thing implements ThingMBean {
   173         @Pair(x = 3, y = "foo")
   185         @Pair(x = 3, y = "foo")
       
   186         @DescriptorFields({"foo=bar", "baz="})
   174         public Thing() {}
   187         public Thing() {}
   175 
   188 
   176         @Pair(x = 3, y = "foo")
   189         @Pair(x = 3, y = "foo")
   177         public Thing(@Pair(x = 3, y = "foo") int p1) {}
   190         @DescriptorFields({"foo=bar", "baz="})
       
   191         public Thing(
       
   192                 @Pair(x = 3, y = "foo")
       
   193                 @DescriptorFields({"foo=bar", "baz="})
       
   194                 int p1) {}
   178 
   195 
   179         public int getReadOnly() {return 0;}
   196         public int getReadOnly() {return 0;}
   180 
   197 
   181         public void setWriteOnly(int x) {}
   198         public void setWriteOnly(int x) {}
   182 
   199 
   191 
   208 
   192         public int operation(int p1, int p2) {return 0;}
   209         public int operation(int p1, int p2) {return 0;}
   193     }
   210     }
   194 
   211 
   195     @Pair(x = 3, y = "foo")
   212     @Pair(x = 3, y = "foo")
       
   213     @DescriptorFields({"foo=bar", "baz="})
   196     public static interface ThingMXBean extends ThingMBean {}
   214     public static interface ThingMXBean extends ThingMBean {}
   197 
   215 
   198     public static class ThingImpl implements ThingMXBean {
   216     public static class ThingImpl implements ThingMXBean {
   199         @Pair(x = 3, y = "foo")
   217         @Pair(x = 3, y = "foo")
       
   218         @DescriptorFields({"foo=bar", "baz="})
   200         public ThingImpl() {}
   219         public ThingImpl() {}
   201 
   220 
   202         @Pair(x = 3, y = "foo")
   221         @Pair(x = 3, y = "foo")
   203         public ThingImpl(@Pair(x = 3, y = "foo") int p1) {}
   222         @DescriptorFields({"foo=bar", "baz="})
       
   223         public ThingImpl(
       
   224                 @Pair(x = 3, y = "foo")
       
   225                 @DescriptorFields({"foo=bar", "baz="})
       
   226                 int p1) {}
   204 
   227 
   205         public int getReadOnly() {return 0;}
   228         public int getReadOnly() {return 0;}
   206 
   229 
   207         public void setWriteOnly(int x) {}
   230         public void setWriteOnly(int x) {}
   208 
   231 
   214 
   237 
   215         public int getReadWrite3() {return 0;}
   238         public int getReadWrite3() {return 0;}
   216         public void setReadWrite3(int x) {}
   239         public void setReadWrite3(int x) {}
   217 
   240 
   218         public int operation(int p1, int p2) {return 0;}
   241         public int operation(int p1, int p2) {return 0;}
       
   242     }
       
   243 
       
   244     @Retention(RetentionPolicy.RUNTIME)
       
   245     public static @interface DefaultTest {
       
   246         @DescriptorKey(value = "string1", omitIfDefault = true)
       
   247         String string1() default "";
       
   248         @DescriptorKey(value = "string2", omitIfDefault = true)
       
   249         String string2() default "tiddly pom";
       
   250         @DescriptorKey(value = "int", omitIfDefault = true)
       
   251         int intx() default 23;
       
   252         @DescriptorKey(value = "intarray1", omitIfDefault = true)
       
   253         int[] intArray1() default {};
       
   254         @DescriptorKey(value = "intarray2", omitIfDefault = true)
       
   255         int[] intArray2() default {1, 2};
       
   256         @DescriptorKey(value = "stringarray1", omitIfDefault = true)
       
   257         String[] stringArray1() default {};
       
   258         @DescriptorKey(value = "stringarray2", omitIfDefault = true)
       
   259         String[] stringArray2() default {"foo", "bar"};
       
   260     }
       
   261 
       
   262     @Retention(RetentionPolicy.RUNTIME)
       
   263     public static @interface Expect {
       
   264         String[] value() default {};
       
   265     }
       
   266 
       
   267     public static interface DefaultMBean {
       
   268         @DefaultTest
       
   269         @Expect()
       
   270         public void a();
       
   271 
       
   272         @DefaultTest(string1="")
       
   273         @Expect()
       
   274         public void b();
       
   275 
       
   276         @DefaultTest(string1="nondefault")
       
   277         @Expect("string1=nondefault")
       
   278         public void c();
       
   279 
       
   280         @DefaultTest(string2="tiddly pom")
       
   281         @Expect()
       
   282         public void d();
       
   283 
       
   284         @DefaultTest(intx=23)
       
   285         @Expect()
       
   286         public void e();
       
   287 
       
   288         @DefaultTest(intx=34)
       
   289         @Expect("int=34")
       
   290         public void f();
       
   291 
       
   292         @DefaultTest(intArray1={})
       
   293         @Expect()
       
   294         public void g();
       
   295 
       
   296         @DefaultTest(intArray1={2,3})
       
   297         @Expect("intarray1=[2, 3]")
       
   298         public void h();
       
   299 
       
   300         @DefaultTest(intArray2={})
       
   301         @Expect("intarray2=[]")
       
   302         public void i();
       
   303 
       
   304         @DefaultTest(stringArray1={})
       
   305         @Expect()
       
   306         public void j();
       
   307 
       
   308         @DefaultTest(stringArray1={"foo"})
       
   309         @Expect("stringarray1=[foo]")
       
   310         public void k();
       
   311 
       
   312         @DefaultTest(stringArray2={})
       
   313         @Expect("stringarray2=[]")
       
   314         public void l();
   219     }
   315     }
   220 
   316 
   221     public static void main(String[] args) throws Exception {
   317     public static void main(String[] args) throws Exception {
   222         System.out.println("Testing that annotations are correctly " +
   318         System.out.println("Testing that annotations are correctly " +
   223                            "reflected in Descriptor entries");
   319                            "reflected in Descriptor entries");
   224 
   320 
   225         MBeanServer mbs =
   321         MBeanServer mbs =
   226             java.lang.management.ManagementFactory.getPlatformMBeanServer();
   322             java.lang.management.ManagementFactory.getPlatformMBeanServer();
   227         ObjectName on = new ObjectName("a:b=c");
   323         ObjectName on = new ObjectName("a:b=c");
       
   324 
   228         Thing thing = new Thing();
   325         Thing thing = new Thing();
   229         mbs.registerMBean(thing, on);
   326         mbs.registerMBean(thing, on);
   230         check(mbs, on);
   327         check(mbs, on);
   231         mbs.unregisterMBean(on);
   328         mbs.unregisterMBean(on);
       
   329 
   232         ThingImpl thingImpl = new ThingImpl();
   330         ThingImpl thingImpl = new ThingImpl();
   233         mbs.registerMBean(thingImpl, on);
   331         mbs.registerMBean(thingImpl, on);
       
   332         Descriptor d = mbs.getMBeanInfo(on).getDescriptor();
       
   333         if (!d.getFieldValue("mxbean").equals("true")) {
       
   334             System.out.println("NOT OK: expected MXBean");
       
   335             failed = "Expected MXBean";
       
   336         }
   234         check(mbs, on);
   337         check(mbs, on);
       
   338 
       
   339         System.out.println();
       
   340         System.out.println("Testing that omitIfDefault works");
       
   341         DefaultMBean defaultImpl = (DefaultMBean) Proxy.newProxyInstance(
       
   342                 DefaultMBean.class.getClassLoader(),
       
   343                 new Class<?>[] {DefaultMBean.class},
       
   344                 new InvocationHandler(){
       
   345                     public Object invoke(Object proxy, Method method, Object[] args) {
       
   346                         return null;
       
   347                     }
       
   348                 });
       
   349         DynamicMBean mbean = new StandardMBean(defaultImpl, DefaultMBean.class);
       
   350         MBeanOperationInfo[] ops = mbean.getMBeanInfo().getOperations();
       
   351         for (MBeanOperationInfo op : ops) {
       
   352             String name = op.getName();
       
   353             Expect expect =
       
   354                     DefaultMBean.class.getMethod(name).getAnnotation(Expect.class);
       
   355             Descriptor opd = op.getDescriptor();
       
   356             List<String> fields = new ArrayList<String>();
       
   357             for (String fieldName : opd.getFieldNames()) {
       
   358                 Object value = opd.getFieldValue(fieldName);
       
   359                 String s = Arrays.deepToString(new Object[] {value});
       
   360                 s = s.substring(1, s.length() - 1);
       
   361                 fields.add(fieldName + "=" + s);
       
   362             }
       
   363             Descriptor opds = new ImmutableDescriptor(fields.toArray(new String[0]));
       
   364             Descriptor expd = new ImmutableDescriptor(expect.value());
       
   365             if (opds.equals(expd))
       
   366                 System.out.println("OK: op " + name + ": " + opds);
       
   367             else {
       
   368                 String failure = "Bad descriptor for op " + name + ": " +
       
   369                         "expected " + expd + ", got " + opds;
       
   370                 System.out.println("NOT OK: " + failure);
       
   371                 failed = failure;
       
   372             }
       
   373         }
       
   374         System.out.println();
   235 
   375 
   236         if (failed == null)
   376         if (failed == null)
   237             System.out.println("Test passed");
   377             System.out.println("Test passed");
   238         else if (true)
   378         else
   239             throw new Exception("TEST FAILED: " + failed);
   379             throw new Exception("TEST FAILED: " + failed);
   240         else
       
   241             System.out.println("Test disabled until 6221321 implemented");
       
   242     }
   380     }
   243 
   381 
   244     private static void check(MBeanServer mbs, ObjectName on) throws Exception {
   382     private static void check(MBeanServer mbs, ObjectName on) throws Exception {
   245         MBeanInfo mbi = mbs.getMBeanInfo(on);
   383         MBeanInfo mbi = mbs.getMBeanInfo(on);
   246 
   384 
   293 
   431 
   294     private static void check(DescriptorRead[] xx) {
   432     private static void check(DescriptorRead[] xx) {
   295         for (DescriptorRead x : xx)
   433         for (DescriptorRead x : xx)
   296             check(x);
   434             check(x);
   297     }
   435     }
   298 
       
   299     public static class AnnotatedMBean extends StandardMBean {
       
   300         <T> AnnotatedMBean(T resource, Class<T> interfaceClass, boolean mx) {
       
   301             super(resource, interfaceClass, mx);
       
   302         }
       
   303 
       
   304         private static final String[] attrPrefixes = {"get", "set", "is"};
       
   305 
       
   306         protected void cacheMBeanInfo(MBeanInfo info) {
       
   307             MBeanAttributeInfo[] attrs = info.getAttributes();
       
   308             MBeanOperationInfo[] ops = info.getOperations();
       
   309 
       
   310             for (int i = 0; i < attrs.length; i++) {
       
   311                 MBeanAttributeInfo attr = attrs[i];
       
   312                 String name = attr.getName();
       
   313                 Descriptor d = attr.getDescriptor();
       
   314                 Method m;
       
   315                 if ((m = getMethod("get" + name)) != null)
       
   316                     d = ImmutableDescriptor.union(d, descriptorFor(m));
       
   317                 if (attr.getType().equals("boolean") &&
       
   318                         (m = getMethod("is" + name)) != null)
       
   319                     d = ImmutableDescriptor.union(d, descriptorFor(m));
       
   320                 if ((m = getMethod("set" + name, attr)) != null)
       
   321                     d = ImmutableDescriptor.union(d, descriptorFor(m));
       
   322                 if (!d.equals(attr.getDescriptor())) {
       
   323                     attrs[i] =
       
   324                         new MBeanAttributeInfo(name, attr.getType(),
       
   325                             attr.getDescription(), attr.isReadable(),
       
   326                             attr.isWritable(), attr.isIs(), d);
       
   327                 }
       
   328             }
       
   329 
       
   330             for (int i = 0; i < ops.length; i++) {
       
   331                 MBeanOperationInfo op = ops[i];
       
   332                 String name = op.getName();
       
   333                 Descriptor d = op.getDescriptor();
       
   334                 MBeanParameterInfo[] params = op.getSignature();
       
   335                 Method m = getMethod(name, params);
       
   336                 if (m != null) {
       
   337                     d = ImmutableDescriptor.union(d, descriptorFor(m));
       
   338                     Annotation[][] annots = m.getParameterAnnotations();
       
   339                     for (int pi = 0; pi < params.length; pi++) {
       
   340                         MBeanParameterInfo param = params[pi];
       
   341                         Descriptor pd =
       
   342                                 ImmutableDescriptor.union(param.getDescriptor(),
       
   343                                     descriptorFor(annots[pi]));
       
   344                         params[pi] = new MBeanParameterInfo(param.getName(),
       
   345                                 param.getType(), param.getDescription(), pd);
       
   346                     }
       
   347                     op = new MBeanOperationInfo(op.getName(),
       
   348                             op.getDescription(), params, op.getReturnType(),
       
   349                             op.getImpact(), d);
       
   350                     if (!ops[i].equals(op))
       
   351                         ops[i] = op;
       
   352                 }
       
   353             }
       
   354 
       
   355             Descriptor id = descriptorFor(getMBeanInterface());
       
   356             info = new MBeanInfo(info.getClassName(), info.getDescription(),
       
   357                     attrs, info.getConstructors(), ops, info.getNotifications(),
       
   358                     ImmutableDescriptor.union(id, info.getDescriptor()));
       
   359             super.cacheMBeanInfo(info);
       
   360         }
       
   361 
       
   362         private Descriptor descriptorFor(AnnotatedElement x) {
       
   363             Annotation[] annots = x.getAnnotations();
       
   364             return descriptorFor(annots);
       
   365         }
       
   366 
       
   367         private Descriptor descriptorFor(Annotation[] annots) {
       
   368             if (annots.length == 0)
       
   369                 return ImmutableDescriptor.EMPTY_DESCRIPTOR;
       
   370             Map<String, Object> descriptorMap = new HashMap<String, Object>();
       
   371             for (Annotation a : annots) {
       
   372                 Class<? extends Annotation> c = a.annotationType();
       
   373                 Method[] elements = c.getMethods();
       
   374                 for (Method element : elements) {
       
   375                     DescriptorKey key =
       
   376                         element.getAnnotation(DescriptorKey.class);
       
   377                     if (key != null) {
       
   378                         String name = key.value();
       
   379                         Object value;
       
   380                         try {
       
   381                             value = element.invoke(a);
       
   382                         } catch (Exception e) {
       
   383                             // we don't expect this
       
   384                             throw new RuntimeException(e);
       
   385                         }
       
   386                         Object oldValue = descriptorMap.put(name, value);
       
   387                         if (oldValue != null && !oldValue.equals(value)) {
       
   388                             final String msg =
       
   389                                 "Inconsistent values for descriptor field " +
       
   390                                 name + " from annotations: " + value + " :: " +
       
   391                                 oldValue;
       
   392                             throw new IllegalArgumentException(msg);
       
   393                         }
       
   394                     }
       
   395                 }
       
   396             }
       
   397             if (descriptorMap.isEmpty())
       
   398                 return ImmutableDescriptor.EMPTY_DESCRIPTOR;
       
   399             else
       
   400                 return new ImmutableDescriptor(descriptorMap);
       
   401         }
       
   402 
       
   403         private Method getMethod(String name, MBeanFeatureInfo... params) {
       
   404             Class<?> intf = getMBeanInterface();
       
   405             ClassLoader loader = intf.getClassLoader();
       
   406             Class[] classes = new Class[params.length];
       
   407             for (int i = 0; i < params.length; i++) {
       
   408                 MBeanFeatureInfo param = params[i];
       
   409                 Descriptor d = param.getDescriptor();
       
   410                 String type = (String) d.getFieldValue("originalType");
       
   411                 if (type == null) {
       
   412                     if (param instanceof MBeanAttributeInfo)
       
   413                         type = ((MBeanAttributeInfo) param).getType();
       
   414                     else
       
   415                         type = ((MBeanParameterInfo) param).getType();
       
   416                 }
       
   417                 Class<?> c = primitives.get(type);
       
   418                 if (c == null) {
       
   419                     try {
       
   420                         c = Class.forName(type, false, loader);
       
   421                     } catch (ClassNotFoundException e) {
       
   422                         return null;
       
   423                     }
       
   424                 }
       
   425                 classes[i] = c;
       
   426             }
       
   427             try {
       
   428                 return intf.getMethod(name, classes);
       
   429             } catch (Exception e) {
       
   430                 return null;
       
   431             }
       
   432         }
       
   433 
       
   434         private static final Map<String, Class<?>> primitives =
       
   435                 new HashMap<String, Class<?>>();
       
   436         static {
       
   437             for (Class<?> c :
       
   438                     new Class[] {boolean.class, byte.class, short.class,
       
   439                                  int.class, long.class, float.class,
       
   440                                  double.class, char.class, void.class}) {
       
   441                 primitives.put(c.getName(), c);
       
   442             }
       
   443         }
       
   444     }
       
   445 }
   436 }