Отражение Java и боль в Рефакторинге

Java Reflection предоставляет механизм для интроспекции объекта во время выполнения. Никаких вторых мыслей, это отличная функция, но она нарушает все соглашения Refactoring!

Нет простого способа (кроме File Search) даже в современной среде IDE знать, к какому атрибуту относится и где. Это делает Refactorings намного более сложным (утомительным!) И подверженным ошибкам.

Чтобы быть откровенным, это не только Reflection API; Hibernate mapping files (hbm.xml) и JSP files оба относятся к атрибутам как String, и когда вы реорганизуете свое имя атрибута, вам необходимо вручную изменить во всех этих местах.

Хуже того, изменения в файлах сопоставления Hibernate или JSP файлах приводят к ошибкам во время выполнения.

Мне интересно узнать, как другие программисты справляются с этим в Java. Есть ли какие-то инструменты? Я использую Eclipse/IBM RAD в качестве основной платформы разработки. Обычно мы используем constant для определения атрибута и используем его по возможности, но это не всегда возможно.

Мне также будет интересно, как это справятся с другими языками!

Ответ 1

Отражение Java вызывает многие из тех же проблем, которые возникают с динамически типизированными языками, такими как Python и Ruby. Фактически, один из способов думать о динамически типизированных языках состоит в том, что все вызывается с помощью отражения, а языки просто обеспечивают хороший, чистый синтаксис для отражения.

И да, с динамически типизированными языками (или тяжелым использованием рефлексии) рефакторинг трудный. Вы не получаете хороших возможностей рефакторинга Eclipse. Вместо этого grep станет вашим другом.

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

Если вы делаете много статически типизированного кода, у вас большие проблемы, если у вас нет хорошей базы модульных тестов. Если вы делаете много динамически типизированного кода (включая код с большим количеством отражений), у вас нет надежды на успех без хорошей базы модульных тестов.

Ответ 2

В современной среде IDE есть функция, которая при переименовании класса будет искать полное имя, например, в ваших XML файлах, чтобы попытаться переименовать любые ссылки, которые у вас могут быть в них. Не думайте, что это решает проблему - очень часто вы не полностью ссылаетесь на имена классов.

Кроме того, поэтому особое внимание и внимание необходимо проявлять, прежде чем использовать его в своем собственном коде.

Но эта проблема с рефлексией заключается в том, что использование аннотаций становится все более популярным. Проблема уменьшается при использовании аннотаций.

Но позвольте мне сказать, что, как справедливо указывает предыдущий пост, если у вас нет хорошей безопасности от модульных тестов, любой рефакторинг, независимо от того, используете ли вы много отражения или нет, опасен.

Ответ 3

На самом деле мы разработали плагин Eclipse, который в значительной степени заботится об этой проблеме. Он называется RefaFlex: http://www.feu.de/ps/prjs/rf/

Ответ 4

Рефакторинг можно было бы улучшить, введя больше "литералов" на языке. Например. imho.class literal - отличный способ обеспечить безопасность во время компиляции определенных моделей. Однако важно сказать, что иногда я хочу потерять безопасность во время компиляции. Строки - это самый простой, но мощный способ выразить слабосвязанный контракт между двумя слоями, поскольку вы можете манипулировать ими или сопоставлять их с регулярным выражением и т.д.

Реальная проблема отражения - это многоплановое использование API. Это основная стоимость гибкости.

PS

Монета проекта могла бы представить где-то в будущем новую конструкцию языка для улучшения этой области.

Ответ 5

Вам может быть интересно использовать IntelliJ IDEA, который также будет искать рефакторизованные имена классов в комментариях и строковых константах.

Ответ 6

Ну, это еще одна возможность для IDE - продавать дорогие версии премиум-класса, которые будут распознавать имена классов и рефакториев, используемые в определенных файлах конфигурации.

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

Но нет общего решения для прямого, "ручного" использования API отражения, поэтому его обычно обескураживают.

Ответ 7

Как и в стороне, Reflection также вызывает проблемы, если вы хотите защитить свой код посредством обфускации. Типичные инструменты обфускации теперь требуют, чтобы вы поддерживали список всех файлов, которые вы не должны запутывать, чтобы отражение от всех файлов конфигурации XML работало правильно.

Тем не менее, J2EE-версия Eclipse IDE вместе с подходящими плагинами для основных фреймворков, таких как Hibernate, Spring и т.д., будет неплохо работать с рефакторингом. Модульные тесты уменьшат цикл тестирования, но проблема заключается в том, что иногда тесты модулей также зависят от некоторой конфигурации XML, заставляющей вас использовать отражение. Таким образом, во время рефакторинга можно выполнять модульные тесты вместе с кодом.

Ответ 8

Как насчет тегов, методов, полей, к которым вы знаете, обращаются? IDE может предупредить вас, когда вы измените свои имена.

Ответ 9

Вы можете избежать написания API отражения с помощью dp4j.com, когда во время компиляции вы знаете, что ищете.

О сопоставлениях xml, это боль, я также испытал с платформой NetBeans и, тем более, с JPA2. Хорошей новостью является то, что аннотации захватывают, и это предлагает снова проверку времени компиляции. Я не уверен в Hibernate, но JPA и NetBeans (больше по состоянию на 7) предлагают эквиваленты аннотаций сопоставлений xml.

Я также разработал SqlWrapper, чтобы избежать использования строк с JDBC. Более сложным (и сложным) является API критериев JPA2.