Сгенерируйте код, реализующий JSR 308 instanceof @MyAnotations runtime check.

JSR 308 предлагает добавлять аннотации типов в Java. После его ратификации программисты смогут добавлять аннотации везде, где в настоящее время разрешен тип Java. Это включает в себя не только декорации методов / полей / локальных / параметров, но также вызовы конструкторов, приведение типов и, что самое любопытное, проверки instanceof. Checker Framework использует JSR 308 для реализации квалификаторов типов, таких как @NonNull для типов объектов или @Regex для строк.

Теперь все, что делает Checkers, - это статический анализ вашего кода. Это все проверки во время компиляции. Хорошо. Но я хочу иметь механизм, который может выполнять проверки во время выполнения. Вы можете заявить:

@Regex String p1 = "[a-z]+";
@Regex String p1 = "[a-z)+";    // compile time error from annotation processor

Еще я могу написать:

if (x instanceof @Regex String) ...

но это ничем не отличается от x instanceof String, проверка во время выполнения не выполняется. Мне нужен процессор аннотаций времени компиляции или манипулятор байт-кода времени выполнения, который позволяет мне запускать произвольный код при проверках instanceof и возвращать логическое значение. Возможно ли это с Java?


person Saintali    schedule 24.09.2012    source источник


Ответы (2)


Да, ты можешь. Но это нетривиально и не поддерживается доступным API процессоров аннотаций. Доступный API обработчика аннотаций ограничен созданием новых классов и не может изменять существующие байт-коды (даже в JDK 8). Вы можете преобразовать в определенные классы компилятора на уровне процессора аннотаций, что дает гораздо больше возможностей. Но вам придется использовать внутренний API компилятора и переписывать его для каждого доступного компилятора (JDT и JavaC). Вы можете взглянуть на проект Lombok (http://projectlombok.org/), который делает очень похожую вещь. К сожалению, Lombok еще не совместим с аннотациями нового типа JDK8.

person grashalm    schedule 01.10.2012
comment
Вы имеете в виду, что Ломбок изменяет написанный код? Как это соотносится с манипуляциями с байт-кодом во время выполнения? Поддержание кода для каждого компилятора может быть потенциально дорогостоящим. - person Saintali; 01.10.2012

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

Как реализовать тест во время выполнения, зависит от того, вычисляет ли система типов свойства самих данных или свойства происхождения (источник данных). Вот текст из раздела «Тесты времени выполнения и уточнение типа» руководство по Checker Framework:

Некоторые системы типов поддерживают тест во время выполнения, который Checker Framework может использовать для уточнения типов в рамках условного оператора, такого как if, после оператора assert и т. Д.

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

1) Для свойств данных ваш самый простой вариант - избежать тестов instanceof и вместо этого использовать тесты, которые поставляются с Checker Framework, например _ 1_.

Например, вместо

  if (x instanceof @Regex String) ...

записывать

  if (RegexUtil.isRegex(x)) ...

и все готово.

Если вы действительно хотите использовать instanceof вместо isRegex, вам нужно будет взломать компилятор, чтобы преобразовать каждое вхождение x instanceof @Regex String в исходном коде в RegexUtil.isRegex(x). Вы также можете сделать это путем перезаписи байтового кода.

2) Для свойств о происхождении требуется гораздо больше усилий по реализации. Вам нужно будет добавить бит происхождения к представлению каждого элемента данных в вашей программе (включая как объекты, так и примитивы) и изменить каждую операцию (в вашей собственной программе и в библиотеках) так, чтобы, помимо работы с данными, она также соответствующим образом сохраняет бит происхождения. Инструмент, который уже делает это, и вы, возможно, сможете использовать его, это DynComp, который распространяется как часть детектора инвариантов Daikon.

person mernst    schedule 30.09.2014