Почему поведение PropertyDescriptor изменилось с Java 1.6 на 1.7?
=================================================================

Обновление: Oracle подтвердил это как ошибку.

Резюме: определенный обычай`BeanInfo`с и`PropertyDescriptor`Если JDK 1.6 не работает, в JDK 1.7 происходит сбой, а некоторые - только после того, как сборщик мусора запустил и очистил определенные SoftReferences.

Edit: This will also break the `ExtendedBeanInfo` in Spring 3.1 as noted at the bottom of the post.

Edit: If you invoke sections 7.1 or 8.3 of the JavaBeans spec, explain
 exactly where those parts of the spec require anything. The
 language is not imperative or normative in those sections. The
 language in those sections is that of examples, which are at best
 ambiguous as a specification. Furthermore, the `BeanInfo` API
 specifically allows one to change the default behavior, and it is
 clearly broken in the second example below.

Спецификация Java Beans ищет методы установки по умолчанию с возвращаемым типом void, но позволяет настраивать методы получения и установки через`java.beans.PropertyDescriptor`, Простейшим способом его использования было указание имен получателя и установщика.

Это работало в JDK 1.5 и JDK 1.6 для указания имени установщика, даже если его тип возврата не является недействительным, как в тестовом примере ниже:

Пример кастома`BeanInfo`s, которые позволяют программный контроль`PropertyDescriptor`В спецификации Java Beans все используют типы возвращаемых значений void для своих сеттеров, но ничто в спецификации не указывает на то, что эти примеры являются нормативными, и теперь поведение этой низкоуровневой утилиты изменилось в новых классах Java, которые, как оказалось, сломались какой-то код, над которым я работаю.

Есть многочисленные изменения в`java.beans` пакет между JDK 1.6 и 1.7, но тот, который вызывает этот тест, кажется, находится в этом diff:

Вместо того, чтобы просто принять метод с правильным именем и параметрами,`PropertyDescriptor` теперь также проверяет тип возвращаемого значения, чтобы определить, является ли он пустым, поэтому установщик беглого языка больше не используется.`PropertyDescriptor` бросает`IntrospectionException` в этом случае: «Метод не найден: setI».

Однако проблема гораздо более коварна, чем простой тест, описанный выше. Другой способ указать методы получения и установки в`PropertyDescriptor` для обычая`BeanInfo` это использовать фактическое`Method` объекты:

Теперь приведенный выше кодwill пройти модульное тестирование как в 1.6, так и в 1.7, но код начнет давать сбой в какой-то момент времени в течение срока службы экземпляра JVM из-за того же самого изменения, которое приводит к немедленному отказу первого примера. Во втором примере единственным признаком того, что что-то пошло не так, является попытка использовать`PropertyDescriptor`, Сеттер имеет значение null, и в большинстве служебных программ это значение означает, что свойство доступно только для чтения.

Код в diff находится внутри`PropertyDescriptor.getWriteMethod()`, Это выполняется, когда`SoftReference` удерживая фактического сеттера`Method` пустой. Этот код вызывается`PropertyDescriptor` конструктор в первом примере, который принимает метод доступаnames выше, потому что изначально нет`Method` сохранены в`SoftReference`удерживает фактического геттера и сеттера.

Во втором примере метод чтения и метод записи хранятся в`SoftReference` объекты в`PropertyDescriptor` конструктором, и сначала они будут содержать ссылки на`readMethod` а также`writeMethod` геттер и сеттер`Method`дано конструктору. Если в какой-то момент эти программные ссылки будут очищены, поскольку сборщик мусора может это сделать (и это будет делать), то`getWriteMethod()` код увидит, что`SoftReference` возвращает null, и он попытается обнаружить сеттер.This timeиспользуя тот же путь кода внутри`PropertyDescriptor` это приводит к сбою первого примера в JDK 1.7, это установит запись`Method` в`null` потому что тип возвращаемого значения не`void`, (Тип возвратаnot часть Java[подпись метода](https://docs.oracle.com/javase/specs/jls/se5.0/html/classes.html#8.4.2).)

Изменение поведения со временем при использовании пользовательских`BeanInfo` может быть очень запутанным. Попытка дублировать условия, из-за которых сборщик мусора очищает эти`SoftReferences` также утомительно (хотя, может быть, поможет какой-то насмешливый инструмент)

Весна`ExtendedBeanInfo` класс имеет тесты, похожие на те, что выше. Вот фактический тестовый модуль Spring 3.1.1 от`ExtendedBeanInfoTest` это пройдет в режиме модульного тестирования, но тестируемый код потерпит неудачу в коварном режиме после GC:

Одно из предположений заключается в том, что мы можем поддерживать текущий код в работе с установщиками без пустот, не допуская, чтобы методы сеттера были доступны только мягко. Похоже, что это сработает, но это скорее хак вокруг измененного поведения в JDK 1.7.

Q: Есть ли определенная спецификация, утверждающая, что не пустые сеттеры должны быть анафемой? Я ничего не нашел и сейчас считаю это ошибкой в библиотеках JDK 1.7.
Я не прав и почему?

 `ExtendedBeanInfo` модульные тесты, которые ожидают, что код не будет нарушен, и поскольку изменение поведения после сборки мусора, очевидно, является ошибкой, я отвечу на это и запомню номера ошибок Java. Ошибки все еще не видны во внешней базе данных ошибок Java, но я надеюсь, что они станут видимыми в какой-то момент:

[http: //bugs.sun.com/bugdatabase/view\_bug.do bug\_id = 7172854](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7172854) (Oracle закрыл это как дубликат ошибки ниже, так как они имеют одну и ту же причину, несмотря на различные проявления.)

[http: //bugs.sun.com/bugdatabase/view\_bug.do bug\_id = 7172865](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7172865)

 (Ошибки были отправлены 30 мая 2012 года.)

 По состоянию на 20 июня 2012 года ошибки видны во внешней базе данных по ссылкам выше.



 спецификация не изменилась (для этого требуется установщик пустот), но реализация была обновлена, чтобы разрешить только установщики пустот.

Спецификация

[http: //www.oracle.com/technetwork/java/javase/documentation/spec-136004.htm](http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html)

 Более подробно см. Раздел 7.1 (методы доступа) и 8.3 (шаблоны проектирования для простых свойств)

 См. Некоторые из последующих ответов в этом вопрос

 [Разрешает ли установщик Java bean вернуть это?](https://stackoverflow.com/questions/5741369/does-java-beans-setter-permit-return-this)



 

 Однако в Java Beans использование имен методов и типов, соответствующих шаблонам проектирования, совершенно необязательно. Если программист готов явно указать свои свойства, методы и события, используя интерфейс BeanInfo, он может вызывать свои методы и типы по своему усмотрению. Тем не мение, **эти методы и типы по-прежнему должны соответствовать требуемым сигнатурам типов, поскольку это важно для их работы**.

 (выделение добавлено)

 Кроме того, я считаю, что сигнатуры методов, показанные в 7.1 и 8.3, фактически являются нормативными. Они являются примерами только в том смысле, что они используют «foo» в качестве имени свойства примера.



 что запрещение не пустых сеттеров - ошибка. Это просто делает **эффективное программирование** невозможно. Вот почему этодолжно быт быть изменен