且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Maven:已部署javax.servlet规范

更新时间:2023-12-04 14:45:43

首先,我要感谢gouki和Stephen C.的帮助.但是他们提出的解决方案对我不起作用.我感谢他们,但我不能接受他们的回答,因为它不能解决该问题,因此会产生误导.我赞成Stephen C.的回答,因为他为我指出了正确的文档,这对于解决问题至关重要.

通过阅读WAR插件文档,尤其是war:war mojo部分,我找到了一个有关如何创建Skinny WAR的示例,该示例可以解决问题.因此,这是在工作配置下面,要添加到构建部分:

<build>
    <finalName>private</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.1.1</version>
            <configuration>
                <packagingExcludes>WEB-INF/lib/geronimo-servlet_3.0_spec-1.0.jar</packagingExcludes>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

归档部分可能并不是真正需要的,但是我将在部署WAR时找到答案.起作用的部分是PackagingExcludes标记,该标记可以包含用逗号分隔的标记列表,以便在包装之前从WAR中排除.

I've a web application configured with Maven which uses a library, also configured with Maven and when I package geronimo-servlet_3.0_spec-1.0.jar is included in WEB-INF/lib and I don't understand why.

I check the library with mvn dependency:tree

$ mvn dependency:tree | grep geronimo
[INFO] +- org.apache.geronimo.specs:geronimo-servlet_3.0_spec:jar:1.0:provided

I check my web app:

$ mvn dependency:tree | grep geronimo
$

However when I run mvn:package the file gets included in WEB-INF/lib.

When I run mvn tomcat:run I can see:

INFO: validateJarFile(/home/stivlo/workspace/private/src/main/webapp/WEB-INF/lib/geronimo-servlet_3.0_spec-1.0.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class

Why and how to avoid? Thank you.

UPDATE 1: as requested I add the pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.obliquid</groupId>
    <artifactId>test-webapp</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>private webapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <repositories>
        <!-- For Jakarta ORO -->
        <repository>
            <id>mvnsearch</id>
            <name>Maven Search</name>
            <url>http://www.mvnsearch.org/maven2/</url>
        </repository>
    </repositories>

    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.obliquid.helpers</groupId>
            <artifactId>obliquid-helpers</artifactId>
            <version>0.9-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <finalName>private</finalName>
    </build>

</project>

UPDATE 2: I followed the advice of Stephen C and modified the build section as follows:

<build>
    <finalName>private</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war</artifactId>
            <version>2.1</version>
            <configuration>
                <overlays>
                    <overlay>
                        <groupId>org.obliquid</groupId>
                        <artifactId>test-webapp</artifactId>
                        <excludes>
                            <exclude>WEB-INF/lib/geronimo-servlet_3.0_spec-1.0.jar</exclude>
                        </excludes>
                    </overlay>
                </overlays>
            </configuration>
        </plugin>
    </plugins>
</build>

However geronimo*.jar still gets included. I guess I've made a mistake in this configuration.

UPDATE 3: Stephen C. says that I should use

the groupId the artifactId of the WAR file that contains the JAR file(s) that you are trying to exclude.

I didn't know that WAR files could have a groupId and artifactId, in fact in my pom.xml I don't see any. My project builds a WAR file and has a groupId and an artifactId and those were the ones I tested above without success.

The dependency causing the problem is the following (is a JAR, not a WAR):

<dependency>
    <groupId>org.obliquid.helpers</groupId>
    <artifactId>obliquid-helpers</artifactId>
    <version>0.9-SNAPSHOT</version>
    <scope>compile</scope>
</dependency>

If I try to use the groupId and artifactId listed in this dependency I've the following error:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.1.1:war (default-war) on project test-webapp: overlay [ id org.obliquid.helpers:obliquid-helpers] is not a dependency of the project. -> [Help 1]

If I try to use the groupId and artifactId of the JAR included by org.obliquid.helpers:

<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-servlet_3.0_spec</artifactId>)

I have the same error.

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.1.1:war (default-war) on project test-webapp: overlay [ id org.apache.geronimo.specs:geronimo-servlet_3.0_spec] is not a dependency of the project. -> [Help 1]

Reading the War plugin documentation, I found a section about creating skinny WARs. So I tried the following:

<build>
    <finalName>private</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.1.1</version>
            <configuration>
                <packagingExcludes>WEB-INF/lib/geronimo-servlet_3.0_spec-1.0.jar</packagingExcludes>
            </configuration>
        </plugin>
    </plugins>
</build>

Still without any success, geronimo-servlet_3.0_spec-1.0.jar is still there!

<groupId>org.obliquid.helpers</groupId>
<artifactId>obliquid-helpers</artifactId>

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.1.1:war (default-war) on project test-webapp: overlay [ id org.obliquid.helpers:obliquid-helpers] is not a dependency of the project. -> [Help 1]

<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-servlet_3.0_spec</artifactId>

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.1.1:war (default-war) on project test-webapp: overlay [ id org.apache.geronimo.specs:geronimo-servlet_3.0_spec] is not a dependency of the project. -> [Help 1]

UPDATE 4: I discovered that the target/private.war file is not a zip of target/private/ directory, but the exclusions are done at packaging time and not by deleting files in target/private/ -- This means, I've to re-test all the things I did before.

  • Suggestion of gouki: doesn't work, the JAR is still there also in the WAR file.
  • Suggestion of Stephen C., maybe mis-understood: actually I just noticed that the pom.xml is always invalid whatever groupId/artifactId I put of the three possibilities explained above. So they didn't work for me.
  • What I found in the documentation (packagingExcludes), works.

Now, if I had to choose one of he answers I would choose Stephen C., because he helped me pointing at the documentation of the WAR plugin (I was reading in the wrong places). However I'd accept an answer that doesn't work, at least in the way I tried (probably wrong). So I'm not going to accept any answer, and add a new answer myself with the final working configuration.

UPDATE 5: I post the relevant part of the pom.xml of obliquid-helpers, that mentions geronimo-servlet_3.0_spec. I've marked it optional and with scope provided, still it gets included by a web-app, unless I mark it as "packagingExclude" in the maven-war-plugin configuration.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.obliquid.helpers</groupId>
  <artifactId>obliquid-helpers</artifactId>
  <version>0.9-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>obliquid-helpers</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <repositories>
    [...]
  </repositories>

  <dependencies>
    [...]

    <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-servlet_3.0_spec</artifactId>
      <version>1.0</version>
      <scope>provided</scope>
      <optional>true</optional>
    </dependency>

  </dependencies>

</project>

First I want to thank gouki and Stephen C. for helping me. However their proposed solution didn't work for me. I'm grateful to them, but I can't accept their answer, because it would be misleading since it didn't work for this problem. I've upvoted Stephen C. answer, because he pointed me to the right documentation, which was essential to solve the problem.

Reading the WAR plugin documentation, especially the war:war mojo section, I've found an example on how to create Skinny WARs, which did the trick. So here is below the working configuration, to be added to the build section:

<build>
    <finalName>private</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.1.1</version>
            <configuration>
                <packagingExcludes>WEB-INF/lib/geronimo-servlet_3.0_spec-1.0.jar</packagingExcludes>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

The archive part is probably not really needed, but I will find out when I deploy the WAR. The part that does the trick is the packagingExcludes tag, that can contain a comma separated list of tokens to exclude from the WAR before packaging.