Процессор аннотаций Java для удаленного JAR

общий вопрос

у меня есть два проекта A и B; B имеет зависимость от A. Я хочу создать некоторый код в B с процессором аннотаций, основанный на аннотациях на объектах в A. Когда я запускаю компиляцию с правильной реализацией процессора, только аннотированные объекты из B берутся.

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

конкретном случае

мои проекты называются DB и WEB. Веб, очевидно, зависит от DB для его доступа JPA; это настроено в Maven. Из-за ряда архитектурных вариантов DB должен оставаться отдельным JAR. БД не использует Spring за исключением некоторых аннотаций, которые используются WEB; WEB использует Spring В MVC.

Я пытаюсь создать CrudRepository интерфейсы для всех моих объектов JPA с процессором аннотаций. The @Repository объекты должны идти в repo пакет в веб-проекте, поэтому их можно использовать с @Autowired где в моем веб-приложения. Аннотация я выполняю сканирование для @javax.persistence.Entity, но я также пробовал пользовательскую аннотацию с теми же результатами.

@SupportedAnnotationTypes("javax.persistence.Entity")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class RepositoryFactory extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element e : roundEnv.getElementsAnnotatedWith(Entity.class)) {
            if (e.getKind() != ElementKind.CLASS) {
                continue;
            }
            // TODO: implement logic to skip manually implemented Repos
            try {
                String name = e.getSimpleName().toString();
                TypeElement clazz = (TypeElement) e;

                JavaFileObject f = processingEnv.getFiler().
                        createSourceFile("blagae.web.repo." + name + "Repo");
                try (Writer w = f.openWriter()) {
                    PrintWriter pw = new PrintWriter(w);
                    pw.println("package blagae.web.repo;");
                    pw.println("import org.springframework.data.repository.CrudRepository;");
                    pw.printf("import %s;n", clazz.toString());
                    pw.println("import org.springframework.stereotype.Repository;");
                    pw.println("@Repository");
                    pw.printf("public interface %sRepo extends CrudRepository<%s, Long> {}n", name, name);
                    pw.flush();
                }
            } catch (IOException ex) {
                Logger.getLogger(RepositoryFactory.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return false;
    }
}

в идеале, я хотел бы, чтобы кто-то рассказал мне об аннотации, которая была бы так просто, как

@ComponentScan(basePackages = "blagae.db.*")

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

обновление

дополнительная информация: я использую Maven-processor-plugin, который я проверил, чтобы хорошо работать в веб-проекте для классов, которые определены здесь. Однако я специально хочу, чтобы классы доступа аннотировались в БД проекта зависимостей. Я изучил метод AbstractProcessor::getSupportedOptions но мне непонятно, что я мог бы там сделать.

конфигурация Maven:

<plugin>
    <groupId>org.bsc.maven</groupId>
    <artifactId>maven-processor-plugin</artifactId>
    <version>2.2.4</version>
    <configuration>
        <processors>
            <processor>blagae.utils.RepositoryFactory</processor>
        </processors>
    </configuration>
    <executions>
        <execution>
            <id>process</id>
            <goals>
                <goal>process</goal>
            </goals>
            <phase>generate-sources</phase>
        </execution>
    </executions>
</plugin>

предложение

еще одна случайная мысль, которую я должен был бы запустить JavaCompiler процесс для проекта DB в интернете, но как бы я ввел мой Processor ?

3 ответов


обработчик аннотаций работ на этапе компиляции вашего проекта (веб-в вашем случае) и компилятор компилирует этот проект. Зависимости текущего проекта уже скомпилированы, а компилятор (и, как результат, ваш обработчик аннотаций) не касается (или не имеет доступа) сторонних библиотек (БД).

вы можете попытаться извлечь обработчик аннотаций в отдельный проект / jar и использовать его в проектах WEB и DB. В этом случае обработчик аннотаций создаст CrudRepository на этапе компиляции конкретный проект. И все сгенерированные классы в проекте DB будут доступны в интернете.


лично я бы извлек обработчик аннотаций в отдельном модуле maven и добавил к нему зависимость от веб-модуля.

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

для того, чтобы процессор аннотаций работал, есть две вещи, которые вы должны предоставить:

поскольку вы упомянули, что в настоящее время классы не генерируются, я бы предположил, что вам не хватает мета-файла. Итак, откройте свой веб-проект и перейдите к . Внутри вы должны создать META-INF папка с вложенными services папка в нем. Затем в services создайте файл с именем javax.annotation.processing.Processor. В содержимом файла должно быть указано полное имя(имена) класса(ов) вашего процессора (ов) аннотаций. Если существует несколько процессоров аннотаций, полные имена классов должны быть на отдельных строках. Но поскольку у вас есть только один, у вас будет что-то вроде:

com.yourdomain.processor.RepositoryFactory

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

в конце концов, вы должны закончить с аналогичной структурой:

enter image description here

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

после этого, когда вы делаете mvn clean install все ваши модули будут очищены и построены. Однако, поскольку компилятор теперь будет знать о вашем процессоре аннотаций, он запустит его. Все сгенерированные источники будут расположены (по умолчанию) в


в вашем проекте A включите META-INF/beans.XML-файл, который будет содержать следующее:

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee <a href="http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"</a>
       version="1.1" bean-discovery-mode="all">
</beans>

и попробуйте. Вы должны использовать JavaEE 7 / CDI 1.1. См.Java EE 7 дескрипторы развертывания для получения дополнительной информации.

вы также можете обратиться на этот вопрос: как @Inject объект из другого модуля проекта, включенного в качестве jar