Статьи

NbBundle на стероидах с использованием процессоров аннотаций

Платформа NetBeans имеет отличную поддержку i18n через Bundle.properties/NbBundle . В простейшей форме вы в основном создаете файл Bundle.properties со своими ключом / значениями и получаете к ним доступ в своем коде следующим образом:

NbBundle.getBundle(ClassInPackage.class).getString("yourKey");

Это прекрасно работает, но если «yourKey» не существует, вы получите исключение во время выполнения. Вы хотите перехватить эти ошибки во время компиляции или непосредственно при кодировании в вашей IDE. Некоторое время назад я столкнулся с модным LiveDB Ярослава
Тулаха , и мне не терпелось использовать этот блестящий подход в других ситуациях. Я считаю, что NbBundle — идеальный кандидат для улучшения с помощью
процессора аннотаций . Мое решение позволяет вам написать это вместо:

Bundle.yourKey;

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

Для начала, включите мою аннотацию StaticBundle.java и мой StaticBundleProcessor.java в вашем classpath (см. Ниже), предпочтительно в модуле «обертки», а не в модуле, где вы будете использовать аннотацию. (Это позволяет избежать некоторых ситуаций с курицей / яйцом).

В пакете у вас есть ваши Bundle.properties, создайте файл с именем package-info.java:

@StaticBundle
package com.yourcompany.yourpackage;

import no.tornado.netbeans.tools.StaticBundle;

Затем зарегистрируйте процессор аннотаций как сервис в META-INF / services / javax.annotation.processing.Processor:

no.tornado.netbeans.tools.StaticBundleProcessor

Теперь скомпилируйте ваш проект, и Bundle.class волшебным образом появится со статическими открытыми полями для всех ключей в ваших Bundle.properties. Это также работает без изменений в процессе сборки для maven проектов. Если вы используете IntelliJ, вам необходимо зарегистрировать процессор аннотаций, а также добавить папку сгенерированных источников в качестве папки-источника в вашем проекте, поскольку IntelliJ не использует папку назначения / вывода для помощи содержимому и т. Д.

Это аннотация StaticBundle.java:

package no.tornado.netbeans.tools;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.SOURCE)
public @interface StaticBundle {
}

Это StaticBundleProcessor.java:

package no.tornado.netbeans.tools;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import java.io.Writer;
import java.util.Properties;
import java.util.Set;

@SupportedAnnotationTypes("no.tornado.netbeans.tools.StaticBundle")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public final class StaticBundleProcessor extends AbstractProcessor {
    public boolean process(Set<!--? extends TypeElement--> annotations, RoundEnvironment roundEnv) {
        for (Element e : roundEnv.getElementsAnnotatedWith(StaticBundle.class)) {
            PackageElement pe = (PackageElement) e;
            String clsName = pe.getQualifiedName() + ".Bundle";
            try {
                Filer filer = processingEnv.getFiler();
                FileObject bundleFO = filer.getResource(StandardLocation.CLASS_OUTPUT, pe.getQualifiedName().toString(), "Bundle.properties");
                Properties bundleProps = new Properties();
                bundleProps.load(bundleFO.openInputStream());
                JavaFileObject src = filer.createSourceFile(clsName, pe);
                Writer w = src.openWriter();
                w.append("package ").append(pe.getQualifiedName().toString()).append(";\n\n");
                w.append("import org.openide.util.NbBundle;\n");
                w.append("import java.util.ResourceBundle;\n\n");
                w.append("public class Bundle {\n");
                w.append("\tprivate static final ResourceBundle bundle = NbBundle.getBundle(Bundle.class);\n\n");
                for (Object key : bundleProps.keySet())
                    w.append("\tpublic static final String ").append(String.valueOf(key)).append(" = bundle.getString(\"").append(String.valueOf(key)).append("\");\n");
                w.append("}");
                w.close();
            } catch (Exception ex) {
                throw new IllegalStateException(ex);
            }
        }
        return true;
    }
}

Сгенерированный Bundle.java будет выглядеть так:

package com.yourcompany.yourpackage;

import org.openide.util.NbBundle;
import java.util.ResourceBundle;

public class Bundle {
	private static final ResourceBundle bundle = NbBundle.getBundle(Bundle.class);

	public static final String myKey = bundle.getString("myKey");
}

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

От http://blog.syse.no/edvin/nbbundle-on-steroids-using-annotationprocessors/