проверять во время компиляции, имеет ли строковый параметр, переданный методу, аннотацию @deprecated - PullRequest
4 голосов
/ 16 июня 2011

Я хотел бы проверить, являются ли строки, переданные методам, устаревшими или нет.Например:

public class MyRepo
    @Deprecated
    private static final String OLD_PATH = "old_path";
    private static final String NEW_PATH = "new_path";

    //...

    public load(Node node){
        migrateProperty(node, OLD_PATH , NEW_PATH );

        //load the properties
        loadProperty(node, NEW_PATH);
    }

    //I want to validate that the String oldPath has the @Deprecated annotation
    public void migrateProperty(Node node, String oldPath, String newPath) {
        if(node.hasProperty(oldPath)){
            Property property = node.getProperty(oldPath);
            node.setProperty(newPath, (Value) property);
            property.remove();
        }
    }

    //I want to validate that the String path does not have the @Deprecated annotation
    public void loadProperty(Node node, String path) {
        //load the property from the node
    }
}

Ближайшее, что я могу найти, это проверка комментариев к самим параметрам .

Ответы [ 7 ]

1 голос
/ 30 июня 2011

Ваша аннотация помечает поле OLD_PATH как устаревшее, а не строку "old_path".При вызове migrateProperty вы передаете строку, а не поле.Таким образом, метод не знает поле, из которого получено значение, и не может проверить его на наличие аннотаций.

С помощью аннотаций вы что-то заявляете об элементах Java, таких как классы, поля, переменные, методы.Вы не можете комментировать объекты, такие как строки.

Статья, на которую вы ссылаетесь, рассказывает о аннотировании формальных параметров.Опять же, это аннотированный параметр, а не аргумент (переданное значение).Если вы поместите @Something в параметр метода, этот параметр будет всегда аннотироваться независимо от значения, которое передается вызывающей стороне этому методу.

Что вы можете сделать, но я не уверен, что вы этого хотите- это следующее:

@Deprecated
private static final String OLD_PATH = "old_path";
private static final String NEW_PATH = "new_path";

public load(Node node){
    migrateProperty(node,
        getClass().getDeclaredField("OLD_PATH"),
        getClass().getDeclaredField("NEW_PATH") );
    // ...
}

//I want to validate that the String oldPath has the @Deprecated annotation
public void migrateProperty(Node node, Field<String> oldPath, Field<String> newPath) {
    if ( oldPath.getAnnotation(Deprecated.class) == null ) {
       // ... invalid
    }
    // ...
}

В этом случае вы действительно передаете поле, а не его значение.

0 голосов
/ 04 июля 2011

Это просто невозможно сделать во время компиляции.

Во-первых, аннотация @Depreciated может ссылаться на поле String, но ни в коем случае не присоединяет строковое значение.

Во-вторых, даже если вы как-то можете пометить строковое значение аннотацией, ничто в системе типов Java не позволяет вам объявить, что можно передавать только значения с определенной аннотацией - информация аннотации не обязательно будет даже доступна во время компиляции.

Обработка аннотации не будет работать из-за пункта 1. Все другие схемы будут работать только во время выполнения из-за пункта 2.

Для достижения проверки времени компиляции наиболее естественным было бы созданиеперечисление, которое содержит все допустимые значения вашей строки.

0 голосов
/ 23 июня 2011

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

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

public class MyRepo
    private enum Preferred {
        PATH("new_path"),
        OTHER_THING("bar");

        private String value;

        Preferred(String value) {
            this.value = value;
        }

        @Override
        public String toString() {
             return value;
        }
    }

    private enum Legacy {
        PATH("old_path"),
        OTHER_THING("foo");

        private String value;

        Legacy(String value) {
            this.value = value;
        }

        @Override
        public String toString() {
             return value;
        }
    }

    public load(Node node){
        migrateProperty(node, Legacy.PATH, Preferred.PATH);

        //load the properties
        loadProperty(node, Preferred.PATH);
    }

    public void migrateProperty(Node node, Legacy oldBusted, Preferred newHotness) {
        if (node.hasProperty(oldBusted)) {
            Property property = node.getProperty(oldBusted);
            node.setProperty(newHotness, (Value) property);
            property.remove();
        }
    }

    public void loadProperty(Node node, Preferred path) {
        //load the property from the node
    }
}

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


Если вы действительно хотите выполнить это с помощью аннотаций, то, похоже, - это способ.Java 6 имеет API обработки аннотаций, встроенные в javac, которые, по-видимому, фактически являются плагинами для компилятора.Они могут делать то, что вам нужно, плюс намного больше, но они кажутся довольно эзотерическими, по крайней мере, на первый взгляд.Это выглядит как хорошее вступление: http://today.java.net/pub/a/today/2008/04/10/source-code-analysis-using-java-6-compiler-apis.html

0 голосов
/ 23 июня 2011

Соответствует ли проверка файла ".class" вашему времени на компиляцию? FindBug позволяет выполнять много проверок файла .class. Вы можете написать собственный плагин для проверки полей, методов и аргументов (и многих других). Вот старый учебник

Если вам удастся написать один, мне будет очень интересно использовать этот код:)

0 голосов
/ 22 июня 2011

Я не знаю, какой именно ваш вариант использования здесь, но я не думаю, что вы можете делать то, что хотите, с @Deprecated. Когда вы помечаете что-то как устаревшее, вы помечаете поле, метод или класс НЕ значением. Все, к чему вы получаете доступ в loadProperty, это значение.

Итак, взяв ваш пример, я могу довольно легко позвонить

new MyRepo().loadProperty("old_path");

без ссылки на OLD_PATH или NEW_PATH вообще. Решение простое, вам нужно явно проверить в ваших методах соответствие. (добавлен метод isDeprecated). Вы можете оставить аннотацию @Deprecated, если хотите, в качестве указания.

public class MyRepo {
    @Deprecated
    private static final String OLD_PATH = "old_path";
    private static final String NEW_PATH = "new_path";

    private boolean isDeprecated(String path) {
        return OLD_PATH.equals("old_path");
    }

    //...

    public load(Node node){
        migrateProperty(node, OLD_PATH , NEW_PATH );

        //load the properties
        loadProperty(node, NEW_PATH);
    }

    //I want to validate that the String oldPath has the @Deprecated annotation
    public void migrateProperty(Node node, String oldPath, String newPath) {
        if (!isDeprecated(oldPath)) {
            throw new Exception(oldPath + " is not deprecated");
        }

        if(node.hasProperty(oldPath)){
            Property property = node.getProperty(oldPath);
            node.setProperty(newPath, (Value) property);
            property.remove();
        }
    }

    //I want to validate that the String path does not have the @Deprecated annotation
    public void loadProperty(Node node, String path) {
        if (isDeprecated(path)) {
            throw new Exception(path + " is deprecated, please use " + NEW_PATH);
        }

        //load the property from the node
    }
}

Если этот шаблон необходимо применить к нескольким классам, вы, конечно, можете сделать его более строгим.

0 голосов
/ 16 июня 2011

«Старая» (до Java 5, на основе JavaDoc) устаревшая аннотация хранится в скомпилированном файле класса, но, к сожалению, недоступна для отражения.

Если вместо этого вы можете использовать «реальную» аннотацию (@ java.lang.Deprecated), вы, конечно, можете использовать отражение, чтобы получить все объявленные поля вашего класса, проверьте, являются ли они статическими строками с @ Устаревшие аннотации и сравните их с переданным аргументом метода.

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

0 голосов
/ 16 июня 2011

Прежде всего, ваш маркер "@deprecated" - это просто тег JavaDoc, а не аннотация, поэтому он не имеет ничего общего с компилятором.

Если вы используете аннотацию @Deprecated, вы 'Вы получите предупреждение об устаревании для строк, в которых вы используете устаревшее поле:

@Deprecated
private static final String OLD_PATH = "old_path";
private static final String NEW_PATH = "new_path";

Вы также можете оставить тег JavaDoc @deprecated, но он будет полезен только в том случае, если вы предоставите какое-то объяснение.для этого.Конечно, тег javadoc должен быть внутри /** ... */.


Однако, если вы хотите во время выполнения внутри метода migrateProperty() проверить, что передаваемая строка получена из устаревшей переменной, это невозможно.То, что вы получаете с помощью вызова метода, является ссылкой на строку в куче.Амортизация относится только к полю, которое может быть проверено только перед вызовом метода, возможно.

...