Интроспекция Java - странное поведение

Ниже приведен небольшой пример, который легко воспроизводит проблему. Поэтому у меня есть переменная типа String, на которой установлено значение по умолчанию. У меня есть 3 метода:

  • геттер
  • сеттер
  • метод удобства, который преобразует строку в boolean

Интроспекция не возвращает getter как readMethod и setter как метод writeMethod. Вместо этого он возвращает метод isTest() как метод readMethod. Установщик пуст.

Из документации я понимаю, что если тип будет логическим, метод "is" имеет более высокий приоритет над get, но тип - String, поэтому не имеет смысла даже искать "is-xxx", метод?

public class Test {
    public class Arguments {
        private String test = Boolean.toString(true);

        public boolean isTest() {
            return Boolean.parseBoolean(test);
        }

        public String getTest() {
            return test;
        }

        public void setTest(String test) {
            this.test = test;
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IntrospectionException {
        BeanInfo info = Introspector.getBeanInfo(Arguments.class);
        System.out.println("Getter: " + info.getPropertyDescriptors()[1].getReadMethod());
        System.out.println("Setter: " + info.getPropertyDescriptors()[1].getWriteMethod());
        PropertyDescriptor descr = new PropertyDescriptor("test", Arguments.class);
        System.out.println("T");
    }

}

Есть ли кто-нибудь, кто имеет представление об этом?

Дополнительная информация:

  • Заказ не изменяет результат. Метод isTest() всегда рассматривается как readMethod
  • Если я просто переименую isTest() в bsTest(), он выбирает getter и setter как readMethod и writeMethod. Таким образом, это имеет какое-то отношение к "is-xxx".

Ответ 1

Результат, который вы получаете, на самом деле является ожидаемым результатом в соответствии с спецификацией JavaBeans.

Указание пункта 8.3.1 для простых свойств:

Если мы обнаружим совпадающую пару методов get<PropertyName> и set<PropertyName>которые принимают и возвращают один и тот же тип, тогда мы рассматриваем эти методы как определяющие свойство чтения-записи, имя которого будет <propertyName>.

Затем, цитируя пункт 8.3.2 для булевых свойств:

Этот метод is<PropertyName> может быть предоставлен вместо метода get<PropertyName> или может быть предоставлен в дополнение к методу get<PropertyName>.

В любом случае, если метод is<PropertyName> присутствует для логического свойства, то мы будем использовать метод is<PropertyName> для чтения значения свойства.

В вашем примере Introspector обнаруживает метод isTest и getTest. Поскольку isTest имеет приоритет над getTest, он использует isTest для определения типа свойства test как boolean. Но тогда Introspector ожидает, что сеттер будет иметь подпись void setTest(boolean test) и не найдет его, поэтому метод setter null.

Важно отметить, что Introspector не читает поля. Он использует подпись методов getter/setter, чтобы определить, какие поля присутствуют, и их соответствующие типы. isTest подпись метода задает свойство с именем test типа boolean, поэтому, независимо от фактического типа test, Introspector будет считать, что ваш класс имеет свойство boolean test.

Фактически, для всего Инспектора существует свойство test, возможно, даже не существует! Вы можете убедиться в этом со следующим кодом:

class Test {

    public class Arguments {
        public boolean isTest() {
            return true;
        }
    }

    public static void main(String[] args) throws IntrospectionException {
        BeanInfo info = Introspector.getBeanInfo(Arguments.class);
        System.out.println("Getter: " + info.getPropertyDescriptors()[1].getReadMethod());
        System.out.println("Name of property: " + info.getPropertyDescriptors()[1].getName());
    }

}

Ответ 2

Действительный член совершенно не имеет отношения к Introspector. Например, вы можете использовать метод getName(), который возвращает только фиксированный String, и Introspector найдет его получателем для члена с именем "name". У вас может даже быть сеттер, если член не существует. Вы даже можете предоставить интерфейс для Introspector, и он будет определять свойства этого, даже если не могут быть какие-либо реальные члены.

Другими словами, свойства определяются наличием методов getter и setter, а не фактическим поиском переменных.