【问题标题】:Jersey fails when creating uber jar with maven-assembly-plugin使用 maven-assembly-plugin 创建 uber jar 时 Jersey 失败
【发布时间】:2016-04-18 07:00:03
【问题描述】:

我创建了一个 maven jersey starter webapp。我还使用码头插件在我的应用程序中嵌入了码头服务器。

当我使用 mvn jetty:run 命令运行我的项目时,我的项目运行良好。

但是当我使用 mvn clean package 命令打包我的项目并运行名称为 jar-with-dependencies 的 jar 文件时,项目会在从球衣资源返回 json 响应时抛出此异常。

严重:找不到媒体 type=application/json、type=class com.nitish.freecharge.model.Count、genericType=class com.nitish.freecharge.model.Count 的 MessageBodyWriter。

这是我的 pom.xml 文件

http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.nitish.freecharge</groupId>
<artifactId>wordcount</artifactId>
<packaging>war</packaging>
<version>2.0</version>
<name>wordcount</name>

<build>
    <finalName>wordcount</finalName>
    <resources>
        <resource>
            <directory>src/main/java</directory>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
        <resource>
            <directory>src/main/webapp</directory>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <inherited>true</inherited>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-maven-plugin</artifactId>
            <version>9.3.0.v20150612</version>
            <configuration>
                <scanIntervalSeconds>5</scanIntervalSeconds>
                <webApp>
                    <contextPath>/wordcount</contextPath>
                </webApp>
                <httpConnector>
                    <!--host>localhost</host -->
                    <port>9999</port>
                </httpConnector>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <executions>
                <execution>
                    <id>package-jar</id>
                    <phase>package</phase>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <finalName>awesomeProject</finalName>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <appendAssemblyId>false</appendAssemblyId>
                <archive>
                    <manifest>
                        <mainClass>App</mainClass>
                    </manifest>
                </archive>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-moxy</artifactId>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>9.3.8.v20160314</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlet</artifactId>
        <version>9.3.8.v20160314</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.4</version>
    </dependency>
</dependencies>
<properties>
    <jersey.version>2.22.2</jersey.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

我在默认包中创建了我的主驱动程序类作为 App.java。这是我的 App.java 内容

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

public class App {
    public static void main(String []gg){

        Server server = new Server(9999);

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
        context.setContextPath("/");
        server.setHandler(context);

        ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/wordcount/*");
        jerseyServlet.setInitOrder(1);
        jerseyServlet.setInitParameter("jersey.config.server.provider.packages","com.nitish.freecharge.resources");
        try {
            System.out.println("Starting the server..");
            server.start();
            System.out.println("Server started");
            server.join();
        } catch(Exception e) {
            System.out.println("Exception in starting the server ");
            e.printStackTrace();
        }
    }
}

这是我在启动服务器后访问我的项目 url 时执行的唯一球衣资源类:

package com.nitish.freecharge.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import com.nitish.freecharge.dao.FileDAO;
import com.nitish.freecharge.model.Count;

/**
 * Root resource (exposed at "count" path) which handles HTTP GET method and returns the count value;
 */
@Path("/count")
public class CountResource {

    private FileDAO fileDAO=new FileDAO();

    /**
     * Method handling HTTP GET requests. The returned object will be sent
     * to the client as "application/json" media type.
     *
     * @return String that will be returned as a application/json response.
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @QueryParam("query")
    public Response getWordCount(@QueryParam("query")String query) {
        Error error=null;
        Count count=null;
        try{   
            if(query!=null){
                query=query.trim();
                if(query.length()>0 && query.matches("^[A-Za-z]+$")){
                    long c=fileDAO.getCount(query.toLowerCase());
                    count=new Count(c);
                }else{
                    error=new Error("Some Error Occured.Please Try Again With a new word!");
                }
            }else{
                error=new Error("Some Error Occured.Please Try Again!");
            }
        }catch(Exception e){
            error=new Error(e.getMessage());
            return Response.status(Status.INTERNAL_SERVER_ERROR).entity(error).build();
        }
        if(count!=null){
            return Response.status(Status.OK).entity(count).build();
        }else{
            return Response.status(Status.BAD_REQUEST).entity(error).build();
        }
    }
}

打包后使用命令运行完整的嵌入式项目 java -jar awesomeProject.jar

我在服务器提示符下得到这个输出

我已经尝试了很多,但无法以解决此问题的方式打包我的嵌入式 web 应用程序。我是 Maven 和包装的新手。请在我犯错的地方提供帮助。

【问题讨论】:

    标签: maven jersey jersey-2.0 embedded-jetty jar-with-dependencies


    【解决方案1】:

    如果您查看 MOXy jar 内部,您将看到一个文件夹 META-INF/services。在该文件夹中,您将看到一个名为 org.glassfish.jersey.internal.spi.AutoDiscoverable 的文件。该文件的内容应该是一行

    org.glassfish.jersey.moxy.json.internal.MoxyJsonAutoDiscoverable
    

    这个文件的目的是让 Jersey 发现 MoxyJsonAutoDiscoverable,它为 Jersey 注册 MOXy。这种服务加载器模式允许 Jersey 发现特性并注册它们,而无需我们自己注册。

    这在创建 uber jar 时带来的问题是,可能有多个 jar 具有相同的文件,因为不同的 jar 有不同的功能要发现,但文件必须是准确的名称,因为这就是服务加载器模式的方式有效。

    所以你有一堆具有相同文件的 jar,但是当你创建 uber jar 时,你不能有多个同名的文件。这是不可能的。所以只有一个文件被放入最终的 jar 中。哪一个。。谁知道呢。但这意味着如果 MOXy 的文件不是那个文件,那么它的功能将不会被自动发现,我们需要自己注册它。所以类被打包在 uber jar 中,但主要功能组件没有注册。自己注册就可以了

    jerseyServlet.setInitParameter("jersey.config.server.provider.classnames",
                                   "org.glassfish.jersey.moxy.json.MoxyJsonFeature");
    

    但是由于不包括自动发现文件而可能被遗漏的所有其他可能的功能呢?

    因此,您应该使用maven-shade-plugin,而不是程序集插件,它具有转换器,可以让我们将服务文件的内容连接到一个文件中。

    配置看起来像

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.3</version>
        <configuration>
            <createDependencyReducedPom>true</createDependencyReducedPom>
            <filters>
                <filter>
                    <artifact>*:*</artifact>
                    <excludes>
                        <exclude>META-INF/*.SF</exclude>
                        <exclude>META-INF/*.DSA</exclude>
                        <exclude>META-INF/*.RSA</exclude>
                    </excludes>
                </filter>
            </filters>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
                <configuration>
                    <transformers>
                        <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                            <mainClass>com.example.YourApp</mainClass>
                        </transformer>
                    </transformers>
                </configuration>
            </execution>
        </executions>
    </plugin>
    

    ServicesResorceTransformaer 用于连接文件。这个插件的特殊配置来自Dropwizard getting started。您可能需要检查一下以获得进一步的解释。

    【讨论】:

    • 非常感谢。 jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", "org.glassfish.jersey.moxy.json.MoxyJsonFeature");解决了这个问题。但是当使用 maven-shade-plugin 时,最终输出是 awesomeProject.war 文件,但我需要一个 jar 文件。如何使用mave-shade-plugin获取带有主类的可执行jar文件?
    • 查看 pom.xml 文件中的 &lt;packaging&gt;。它应该是jar 而不是war。我知道您需要war 才能使用jetty-maven-plugin,但是要获取jar,您需要记住将其更改为jar。
    • @user2327445 你应该将此答案标记为正确...它也对我有帮助,所以我也投了赞成票
    • 我不知道如何将答案标记为正确。你能帮忙吗
    猜你喜欢
    • 2016-12-30
    • 2017-07-07
    • 1970-01-01
    • 2014-10-10
    • 2017-08-29
    • 2013-07-07
    相关资源
    最近更新 更多