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

Introspector ignores default interface methods

    XMLWordPrintable

Details

    • CSR
    • Resolution: Withdrawn
    • P4
    • tbd
    • client-libs
    • None
    • behavioral
    • medium
    • New bean properties may appear in existing applications.
    • Java API

    Description

      Summary

      Update Introspector so that default methods inherited from interfaces are included when scanning for Java bean properties.

      Problem

      Java bean properties are inferred from a class' getter and setter methods. Back when interfaces could contain only abstract instance methods, it was not necessary to inspect methods declared in interfaces for getters and setters because any such methods must be overridden in some other class in the hierarchy.

      Since Java 8, interfaces can contain non-abstract instance methods (default methods). However, the Introspector does not detect those getters and setters because it hasn't been updated to inspect interface default methods.

      Solution

      Update the Introspector so that interface default methods inherited from interfaces are included in the scan for getters and setters.

      Specification

      There is an internal utility class MethodInfo which is used by the introspection code to find all methods which are possible candidates for bean properties. The fix is to update this class so that interfaces are also searched.

      Note that when Class.getMethods() is invoked on an interface class, the returned list contains all methods declared in that interface and all superinterfaces, and no methods declared in java.lang.Object. This is exactly the behavior we want, and it also means no recursion is needed.

      diff --git a/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java b/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java
      index 5216f4423d4..bff450fb2c8 100644
      --- a/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java
      +++ b/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java
      @@ -25,18 +25,33 @@
      
       package com.sun.beans.introspect;
      
      +import java.io.Closeable;
      +import java.io.Externalizable;
      +import java.io.Serializable;
       import java.lang.reflect.Method;
       import java.lang.reflect.Modifier;
       import java.lang.reflect.Type;
       import java.util.ArrayList;
      +import java.util.Arrays;
       import java.util.Collections;
       import java.util.Comparator;
       import java.util.List;
      +import java.util.Set;
      
       import com.sun.beans.TypeResolver;
       import com.sun.beans.finder.MethodFinder;
      
       final class MethodInfo {
      +
      +    static final Set<Class<?>> IGNORABLE_INTERFACES = Set.of(
      +        AutoCloseable.class,
      +        Cloneable.class,
      +        Closeable.class,
      +        Comparable.class,
      +        Externalizable.class,
      +        Serializable.class
      +    );
      +
           final Method method;
           final Class<?> type;
      
      @@ -66,6 +81,8 @@ final class MethodInfo {
           static List<Method> get(Class<?> type) {
               List<Method> list = null;
               if (type != null) {
      +
      +            // Add declared methods
                   boolean inaccessible = !Modifier.isPublic(type.getModifiers());
                   for (Method method : type.getMethods()) {
                       if (method.getDeclaringClass().equals(type)) {
      @@ -81,10 +98,18 @@ final class MethodInfo {
                               }
                           }
                           if (method != null) {
      -                        if (list == null) {
      -                            list = new ArrayList<>();
      -                        }
      -                        list.add(method);
      +                        (list = createIfNeeded(list)).add(method);
      +                    }
      +                }
      +            }
      +
      +            // Add default methods inherited from interfaces
      +            for (Class<?> iface : type.getInterfaces()) {
      +                if (IGNORABLE_INTERFACES.contains(iface))
      +                    continue;
      +                for (Method method : iface.getMethods()) {
      +                    if (!Modifier.isAbstract(method.getModifiers())) {
      +                        (list = createIfNeeded(list)).add(method);
                           }
                       }
                   }
      @@ -96,6 +121,10 @@ final class MethodInfo {
               return Collections.emptyList();
           }
      
      +    private static List<Method> createIfNeeded(List<Method> list) {
      +        return list != null ? list : new ArrayList<>();
      +    }
      +
           /**
            * A comparator that defines a total order so that methods have the same
            * name and identical signatures appear next to each others.

      Attachments

        Issue Links

          Activity

            People

              acobbs Archie Cobbs
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: