使用 maven-assembly-plugin 创建 uber jar 时 Jersey 失败
Jersey fails when creating uber jar with maven-assembly-plugin
我创建了一个 maven jersey starter webapp。我还使用 jetty 插件在我的应用程序中嵌入了 jetty 服务器。
当我 运行 我的项目使用 mvn jetty:run 命令时,我的项目工作正常。
但是当我使用 mvn clean package 命令和 运行 名称为 jar-with-dependencies 的 jar 文件打包我的项目时,该项目在从球衣返回 json 响应时抛出此异常资源。
严重:找不到媒体类型=application/json、类型=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>
我已经在默认包中创建了主驱动 class 作为 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();
}
}
}
这是我唯一的球衣资源 class,当我启动服务器后访问我的项目 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-罐子awesomeProject.jar
我在服务器提示符上得到了这个输出
我已经尝试了很多,但无法以解决此问题的方式打包我的嵌入式 Web 应用程序。我是 Maven 和包装的新手。请帮助我犯错的地方。
如果您查看 MOXy 罐子内部,您会看到一个文件夹 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。您可能需要检查一下以获得进一步的解释。
我创建了一个 maven jersey starter webapp。我还使用 jetty 插件在我的应用程序中嵌入了 jetty 服务器。
当我 运行 我的项目使用 mvn jetty:run 命令时,我的项目工作正常。
但是当我使用 mvn clean package 命令和 运行 名称为 jar-with-dependencies 的 jar 文件打包我的项目时,该项目在从球衣返回 json 响应时抛出此异常资源。
严重:找不到媒体类型=application/json、类型=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>
我已经在默认包中创建了主驱动 class 作为 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();
}
}
}
这是我唯一的球衣资源 class,当我启动服务器后访问我的项目 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-罐子awesomeProject.jar
我在服务器提示符上得到了这个输出
我已经尝试了很多,但无法以解决此问题的方式打包我的嵌入式 Web 应用程序。我是 Maven 和包装的新手。请帮助我犯错的地方。
如果您查看 MOXy 罐子内部,您会看到一个文件夹 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。您可能需要检查一下以获得进一步的解释。