使用 maven-assembly-plugin 创建 uber jar 时 Jersey 失败 [英] Jersey fails when creating uber jar with maven-assembly-plugin

查看:50
本文介绍了使用 maven-assembly-plugin 创建 uber jar 时 Jersey 失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have created a maven jersey starter webapp. Also I have embedded jetty server in my app using jetty plugin.

当我使用 mvn jetty:run 命令运行我的项目时,我的项目工作正常.

My project is working fine when I run my project using mvn jetty:run command.

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

But when I package my project using mvn clean package command and run the jar file which has name jar-with-dependencies the project throws this exception while returning a json response from a jersey resource.

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

这是我的 pom.xml 文件

Here is my pom.xml file

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

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>

我在默认包中创建了我的 Main Driver 类作为 App.java.这是我的 App.java 内容

I have created my Main Driver class as App.java in default package. Here is my App.java content

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 时被执行:

Here is my only jersey resource class which gets executed when I access my project url after starting the server :

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

After packaging and run the complete embedded project using command java -jar awesomeProject.jar

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

I get this output on the server prompt

我尝试了很多,但无法以解决此问题的方式打包我的嵌入式 Web 应用程序.我是 maven 和包装的新手.请帮助我犯错的地方.

I have tried a lot and unable to package my embedded webapp in such a way that this issue gets resolved. I am new to maven and packaging. Kindly Help where I am committing mistake.

推荐答案

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

If you look inside the MOXy jar, you will see a folder META-INF/services. In that folder, you will see a file named org.glassfish.jersey.internal.spi.AutoDiscoverable. The content of that file should be a single line

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

这个文件的作用是让 Jersey 发现 MoxyJsonAutoDiscoverable,它为 Jersey 注册 MOXy.这种服务加载器模式允许 Jersey 发现功能并注册它们,而无需我们自己注册它们.

What this file is for is to allow Jersey to discover the MoxyJsonAutoDiscoverable, which registers MOXy for Jersey. This service loader pattern allows Jersey to discover features and register them, without us having to register them ourselves.

这在创建 uber jar 时带来的问题是可能有多个 jars 具有相同的文件,因为不同的 jars 有不同的特性需要发现,但文件需要是那个确切的名称,因为这就是服务加载器模式的方式有效.

The problem this poses when creating an uber jar is that there may be multiple jars with the same file, as different jars have different features to discover, but the file needs to be that exact name as that is how the service loader pattern works.

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

So you have a bunch of jars with the same file, but when you create the uber jar, you cannot have multiple files with the same name. It's just not possible. So only one of the files gets put into the final jar. Which one.. who knows. But that means that if MOXy's files is not that one file then its feature will not be auto-discovered, and we need to register it ourselves. So the classes are packaged in the uber jar, but the main feature component is just not registered. You could just register it yourself

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

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

but what about all the other possible features that are possibly left out because their auto-discoverable file is not included?

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

For this reason, instead of the assembly plugin, you should use the maven-shade-plugin, which has transformers that allow us to concatenate the contents of service files into one file.

配置看起来像

<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开始.您可能需要检查一下以获取进一步的解释.

The ServicesResorceTransformaer is what concatenates the files. This particular configuration of the plugin was taking from the Dropwizard getting started. You may want to check that out for further explanation.

这篇关于使用 maven-assembly-plugin 创建 uber jar 时 Jersey 失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆