Внедрение констант через пользовательскую аннотацию

В моем коде есть множество констант для различных настраиваемых свойств моей системы. Я перемещаю их все в центральный .properties файл. Мое текущее решение состоит в том, чтобы иметь один Properties.java, который статически загружает файл .properties и предоставляет различные методы получения, например:

public class Properties {
    private static final String FILE_NAME = "myfile.properties";
    private static final java.util.Properties props;

    static {
        InputStream in = Properties.class.getClassLoader().getResourceAsStream(
                FILE_NAME);
        props = new java.util.Properties();
        try {
            props.load(in);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static String getString(Class<?> cls, String key) {
        return props.getProperty(cls.getName() + '.' + key);
    }

    public static int getInteger(Class<?> cls, String key) {
        return Integer.parseInt(getString(cls, key));
    }

    public static double getDouble(Class<?> cls, String key) {
        return Double.parseDouble(getString(cls, key));
    }
}

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

private final static int MY_CONSTANT = Properties.getInteger(
    ThisClass.class, "MY_CONSTANT");

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

Я думаю примерно так:

@MyAnnotation
private static final int MY_CONSTANT;

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


person Ellis Michael    schedule 22.03.2015    source источник
comment
Как вы думаете, почему это множество кодов котельной плиты? не добавлял бы аннотацию к нему?   -  person SMA    schedule 22.03.2015
comment
Это действительно константы? Или больше похоже на элементы конфигурации? Если они конфигурационные, действительно ли нужно записывать их как константы? Потому что модификатор final потеряет свой смысл (я даже не уверен, что отражение может присвоить значение полю final). Если они только конфигурация, почему бы вам не использовать структуру конфигурации для облегчения вашей задачи (например, commons-configuration или configafe's config)? Если они константы, зачем их изменять при каждом запуске?   -  person Olivier Grégoire    schedule 22.03.2015
comment
Кроме того, вы не закрываете свой InputStream в своем блоке try-catch-finally. Вы должны попробовать и сделать это.   -  person Olivier Grégoire    schedule 22.03.2015
comment
Они являются константами, поскольку они постоянны на протяжении всего срока службы системы, но я хотел бы варьировать их для разных экспериментов, которые я проводил. Назначение final не должно быть проблемой, поскольку обработка аннотации выполняется во время компиляции. Закрытие InputStream - хороший момент (хотя и не совсем актуальный).   -  person Ellis Michael    schedule 22.03.2015
comment
Проверьте Константы и аннотации на предмет вычисленных значений при обработке аннотаций во время компиляции.   -  person Olivier Grégoire    schedule 22.03.2015
comment
Вы хотите автоматически заполнять значения из констант static final файла, используя только специальные аннотации и имена этих констант? В java это невозможно.   -  person Andremoniy    schedule 22.03.2015
comment
Судя по тому, что я видел, например, в Project Lombok, я действительно сомневаюсь, что это невозможно. Я бы даже был рад тому, что просто вставил бы соответствующий Properties.getX(ClassName.class, "FIELD_NAME")   -  person Ellis Michael    schedule 22.03.2015


Ответы (2)


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

Обработчик аннотаций, вероятно, ничего за вас не сделает. Хакерский процессор в стиле Ломбока может. Вы хотите сделать

@MyAnnotation
private static final int MY_CONSTANT;

работать как

private final static int MY_CONSTANT =
    Properties.getInteger(ThisClass.class, "MY_CONSTANT");

Исходное выражение не компилируется (из-за неинициализированной переменной final), но анализирует нормально, и Lombok может выполнять свою работу. Там уже что-то связанное:

  • @Value изменяет модификаторы на final private
  • @UtilityClass создает все поля static

На самом деле, вы могли написать просто

@MyAnnotation
int MY_CONSTANT;

и пусть ваша аннотация изменит также модификаторы. Я бы посмотрел на eclipse и javac обработчики для @UtilityClass, я думаю, все, что вам нужно, это сгенерировать инициализатор (что довольно сложно, потому что все это чертовски сложно).

Я не думаю, что сам Lombok реализует это в ближайшее время, поскольку

  • все static вещи не поддаются тестированию и в основном плохой стиль
  • и не все хотят этого в своем коде
  • это не так уж и много шаблонов
  • он также волшебным образом относится к классу Properties, но это можно решить с помощью конфигурации

но я полагаю, что взнос может быть принят.

person maaartinus    schedule 13.04.2015

Собственно не совсем понятно, зачем и что нужно архивировать.

Как я правильно понял, вы хотите использовать специальные аннотации для автоматического присвоения значений константам static final из некоторого properties файла. К сожалению, это невозможно без специальных хитростей. И аннотации тут ни при чем.

Причина в том, что final поля должны быть инициализированы, и это запрос компилятора. В java нет специальных аннотаций, которые предоставили бы такой синтаксический сахар, который вам нужен.

Но если вы настаиваете на этом, есть два пути:

  1. Экстремальный путь. Инициализировать все поля свойств со значением по умолчанию. Затем, используя этот хак в некотором разделе static init, инициализируйте это значение используя механизм reflection, и вы кодируете, считывая значения из properties.

  2. Менее экстремальный способ: отказать в запросе final модификаторов для полей свойств и использовать только reflection заполнить значения этих полей.

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

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

2) Заставьте ваш Properties класс быть инициализированным во всех возможных точках ввода вашего приложения. В статическом разделе этого класса вы загрузите свой файл свойств, а затем, используя метод (1) с отражением и загрузчиком классов, присвойте значения всем константам.

person Andremoniy    schedule 22.03.2015