Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8144122

Class.getDeclaredMethods() return value includes shadowed methods

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • tbd
    • 6, 7, 8, 9
    • core-libs

      FULL PRODUCT VERSION :
      java version "1.8.0_60"
      Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
      Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

      A DESCRIPTION OF THE PROBLEM :
      According to the JavaDoc of Class.getDeclaredMethods(), which cites:
      "Returns an array of {@code Method} objects reflecting all the methods declared by the class or interface represented by this {@code Class} object. This includes public, protected, default (package) access, and private methods, but excludes inherited methods. (...)",
      only methods declared on the class should be returned. However, the returned value also includes shadowed methods.

      This causes problems when the method is used in order to determine a return type of a particular method, which overrides one from its parent.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create a file named Main.java, containing attached source code.
      2. Compile it from command line:
      "javac Main.java"
      3. Run it with enable asserts option:
      "java -ea Main"

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Number of declared methods is 2.
      ACTUAL -
      Number of declared methods is 4.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      public class Main {

          public static void main(String[] args) {
              int declaredMethods = IntegerStringAdapter.class.getDeclaredMethods().length;
              System.out.println(String.format("Number of declared methods is %s.", declaredMethods));
          }

          static class XmlAdapter<ValueType, BoundType> {
              public BoundType unmarshal(ValueType v) {return null;}
              public ValueType marshal(BoundType v) {return null;}
          }

          static class IntegerStringAdapter extends XmlAdapter<Integer, String> {
              public String unmarshal(Integer i) {
                  return i.toString();
              }
              public Integer marshal(String s) {
                  return Integer.getInteger(s);
              }
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Post-process the returned array of Methods and manually shadow the inherited shadowed methods, effectively excluding them from the search space.

      The following code examples illustrate that:
      --------------------------------
      1. Ambiguous result - BAD. Calling this code might return the return type of the shadowed method.

      public static Class<?> getBoundTypeFromAdapterClass(Class<? extends XmlAdapter> adapterClass) {
              for (Method method : adapterClass.getDeclaredMethods()) {
                  if (method.getName().equals("unmarshal")) {
                      return method.getReturnType();
                  }
              }
              return null;
          }

      --------------------------------
      2. Deterministic result - GOOD. Calling this code will return the return type of the shadowing method.

      public static Class<?> getBoundTypeFromAdapterClass(Class<? extends XmlAdapter> adapterClass) {

              for (Method method : adapterClass.getDeclaredMethods()) {
                  if (method.getName().equals("unmarshal")) {
                      Class<?> methodReturnType = method.getReturnType();
                      if (methodReturnType != Object.class) {
                          return methodReturnType;
                      }
                  }
              }
              return Object.class;
          }

            darcy Joe Darcy
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: