Процессор аннотаций 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 и добавил к нему зависимость от веб-модуля.
однако это не имеет большого значения для успешного запуска процессора аннотаций.
для того, чтобы процессор аннотаций работал, есть две вещи, которые вы должны предоставить:
- класс, который расширяет
javax.annotation.processing.AbstractProcessor
класса. - a специальные файл, вложенный в
META-INF/services
проекта.
поскольку вы упомянули, что в настоящее время классы не генерируются, я бы предположил, что вам не хватает мета-файла. Итак, откройте свой веб-проект и перейдите к . Внутри вы должны создать META-INF
папка с вложенными services
папка в нем. Затем в services
создайте файл с именем javax.annotation.processing.Processor
. В содержимом файла должно быть указано полное имя(имена) класса(ов) вашего процессора (ов) аннотаций. Если существует несколько процессоров аннотаций, полные имена классов должны быть на отдельных строках. Но поскольку у вас есть только один, у вас будет что-то вроде:
com.yourdomain.processor.RepositoryFactory
обратите внимание, что вам придется изменить эту строку с фактическим полностью кваллифицированным именем класса вашего процессора аннотаций.
в конце концов, вы должны закончить с аналогичной структурой:
этот мета-файл важен, потому что в противном случае компилятор не осведомлены о пользовательских процессорах аннотаций. Имея его, он будет использовать все зарегистрированные обработчики.
после этого, когда вы делаете 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