Почему плагин Spring Boot Maven иногда портит переупаковку моего реакторного модуля?

Структура проекта

У меня есть проект реактора Maven в следующей структуре:

company-parent (другой проект для управления зависимостями и плагинами)

<parent>
  <groupId>org.apache</groupId>
  <artifactId>apache</artifactId>
  <version>21</version>
</parent>

<groupId>com.mycompany</groupId>
<artifactId>maven-mycompany-parent</artifactId>
<version>1</version>
<packaging>pom</packaging>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>2.1.6.RELEASE</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
...
  </dependencies>
</dependencyManagement>
<build>
  <pluginManagement>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <version>2.1.6.RELEASE</version>
    </plugin>
    ...
  </pluginManagement>
  ....
</build>

project-parent

<parent>
  <groupId>com.mycompany</groupId>
  <artifactId>maven-mycompany-parent</artifactId>
  <version>1</version>
</parent>

<groupId>com.mycompany</groupId>
<artifactId>project-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>

<modules>
  <module>project-api</module>
  <module>project-impl</module>
</modules>

project-api модуль, содержащий WSDL и сгенерированные POJO

<parent>
  <groupId>com.mycompany</groupId>
  <artifactId>project-parent</artifactId>
  <version>1.0-SNAPSHOT</version>
</parent>

<artifactId>project-api</artifactId>
<packaging>jar</packaging>

project-impl модуль, содержащий конкретную реализацию JAX-WS WSDL

<parent>
  <groupId>com.mycompany</groupId>
  <artifactId>project-parent</artifactId>
  <version>1.0-SNAPSHOT</version>
</parent>

<artifactId>project-impl</artifactId>
<packaging>war</packaging>
...
<dependencies>
  <dependency>
    <groupId>com.mycompany</groupId>
    <artifactId>project-api</artifactId>
    <version>${project.version}</version>
  </dependency>
...
</dependencies>
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <configuration>
        <webResources>
          <webResource>
            <directory>${project.basedir}/src/main/sql</directory>
            <targetPath>sql</targetPath>
          </webResource>
          <webResource>
            <directory>${project.basedir}</directory>
            <include>CHANGELOG.md</include>
            <filtering>true</filtering>
            <targetPath>.</targetPath>
          </webResource>
        </webResources>
        <archive>
          <manifest>
            <addClasspath>true</addClasspath>
            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>       
            <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
          </manifest>
        </archive>
      </configuration>
    </plugin>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <executions>
        <execution>
          <goals>
            <goal>build-info</goal>
            <goal>repackage</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
  ...
</build>

Проблема

Иногда переупакованный .war не может быть выполнен из-за того, что файл не найден и проблемы с загрузкой классов. Я понял, что когда проблема сохраняется, переупакованный WEB-INF/lib .war содержит много зависимостей .jar и один пустой каталог: WEB-INF/lib/project-api-1.0-SNAPSHOT.jar/.

Вот вывод unzip:

-bash-4.2$ unzip -l project-impl/target/project-impl.war | grep project-api
        0  07-17-2019 10:32   WEB-INF/lib/project-api-1.0-SNAPSHOT.jar/

И выполнение, конечно, терпит неудачу:

-bash-4.2$ java -jar project-impl/target/project-impl.war
...
[ERROR] 2019-07-17T11:24:55,711 org.spr.boo.SpringApplication Application run failed
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.mycompany.package.Application]; nested exception is java.io.FileNotFoundException: class path resource [com/mycompany/package/MyPortType.class] cannot be opened because it does not exist
        at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:181) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:315) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:232) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:705) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:531) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742) [spring-boot-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389) [spring-boot-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:311) [spring-boot-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213) [spring-boot-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202) [spring-boot-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
        at com.mycompany.package.Application.main(Application.java:18) [classes!/:3.0.0-SNAPSHOT]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_212]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_212]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_212]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_212]
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:47) [project-impl.war:3.0.0-SNAPSHOT]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:86) [project-impl.war:3.0.0-SNAPSHOT]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [project-impl.war:3.0.0-SNAPSHOT]
        at org.springframework.boot.loader.WarLauncher.main(WarLauncher.java:57) [project-impl.war:3.0.0-SNAPSHOT]
Caused by: java.io.FileNotFoundException: class path resource [com/mycompany/package/MyPortType.class] cannot be opened because it does not exist
        at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:180) ~[spring-core-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:51) ~[spring-core-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:103) ~[spring-core-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.createMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:86) ~[spring-boot-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
        at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.getMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:73) ~[spring-boot-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
        at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:81) ~[spring-core-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.asSourceClass(ConfigurationClassParser.java:682) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser$SourceClass.getInterfaces(ConfigurationClassParser.java:1008) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.processInterfaces(ConfigurationClassParser.java:375) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:323) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:242) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:191) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:295) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:242) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:199) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:167) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
        ... 21 more

Когда я перезапускаю mvn install, есть вероятность ~80%, что регенерированный war будет восстановлен, поскольку файл project-api-1.0.jar присутствует в WEB-INF/lib, как и должно быть, нет пустого каталога.

-bash-4.2$ unzip -l project-impl/target/project-impl.war | grep project-api
  2740878  07-17-2019 11:49   WEB-INF/lib/project-api-1.0-SNAPSHOT.jar

Я проверил банку API в локальном репозитории после того, как неверный результат mvn install запустился на родительском реакторе, он zip -T непротиворечив. Нет сообщений об ошибках во время ошибочной генерации .war. Проверил множество форумов, проблемы с плагином Spring Boot Maven, не нашел ничего подходящего.

Кто-нибудь из вас сталкивался с этой проблемой? Любая помощь будет оценена по достоинству.

PS: полные pom.xml файлов, к сожалению, не могут уместиться в 30000 символов StackOverflow.

Обновление 1

Журнал отладки Maven показывает странную разницу в том, как maven-war-plugin обрабатывает API проекта jar и другие jar:

...
[DEBUG] Processing: project-api-1.0-SNAPSHOT.jar
[DEBUG] Processing: cxf-xjc-runtime-3.3.0.jar
[DEBUG]  + WEB-INF/lib/cxf-xjc-runtime-3.3.0.jar has been copied.
[DEBUG] Processing: jakarta.xml.bind-api-2.3.2.jar
[DEBUG]  + WEB-INF/lib/jakarta.xml.bind-api-2.3.2.jar has been copied.
...

Обновление 2

Я списал проблему на maven-war-plugin:3.2.2. Исходный файл war имеет эту проблему до переупаковки (см. >соответствующий пост).

-bash-4.2$ unzip -l project-impl.war.original | grep project-api
        0  07-18-2019 02:58   WEB-INF/lib/project-api-1.0-SNAPSHOT.jar/

Обновление 3

void org.apache.maven.plugins.war.packaging.ArtifactsPackagingTask.copyFile( String sourceId, final WarPackagingContext context, final File file, String targetFilename ) throws IOException

Проблема с упаковкой war заключается в том, что аргумент file указывает не на каталог project-api-1.0-SNAPSHOT.jar локального репозитория, а на каталог /absolute/path/project-parent/project-api/target/classes. Не уверен, почему аргумент неверен, хотя.


person David Lakatos    schedule 17.07.2019    source источник
comment
Вы проверили, существует ли класс com/mycompany/package/MyPortType.class в банке?   -  person sawyer    schedule 17.07.2019
comment
Да. Это существует. Единственная проблема, похоже, заключается в том, что не файл jar, а пустой каталог копируется в WEB-INF/lib, который по какой-то причине имеет имя jar.   -  person David Lakatos    schedule 17.07.2019
comment
Хорошо, поскольку я не вижу полной конфигурации сборки Maven, я прошу вас попробовать собрать проекты по отдельности, а не из родительского каталога. Дайте мне знать, если выполнение сборки ТОЛЬКО проекта, который имеет MyPortType.class, будет успешным или неудачным. Могли бы вы это сделать?   -  person sawyer    schedule 17.07.2019
comment
@sawyer Конечно. Сначала я строю project-api с mvn -DskipTests clean install, успешно. Затем я создаю project-impl с помощью той же команды, jar находится внутри war. Проблема возникает не всегда, к сожалению. Пожалуйста, взгляните на обновления, которые я опубликовал о maven-war-plugin. Спасибо.   -  person David Lakatos    schedule 18.07.2019
comment
Хорошо.. если я правильно понял, оба проекта скомпилированы правильно, верно? Итак, если сборки выполняются по отдельности, это означает, что проблема не в том, что вы думаете, а в уровне конфигурации Maven.   -  person sawyer    schedule 22.07.2019


Ответы (1)


Я так понял, к spring-boot-maven-plugin отношения не имеет. Проблема заключалась в том, что maven-site-plugin и maven-war-plugin запускались друг за другом. Первоначально я вызвал mvn clean site site:jar deploy из Jenkins, чтобы включить развертывание артефакта jar с классификатором сайта за один шаг. maven-site-plugin что-то делает с артефактами зависимостей Reactor (здесь project-api-0.1.0-SNAPSHOT.jar, поэтому maven-war-plugin по какой-то причине не может ссылаться на него. Пустой каталог будет храниться в каталоге WEB-INF/lib war вместо project-api-0.1.0-SNAPSHOT.jar/. Странно.

person David Lakatos    schedule 30.07.2019