Jersey fallisce quando si crea un jar uber con maven-assembly-plugin

Ho creato una webapp starter maven jersey. Inoltre ho incorporato il server jetty nella mia app usando il plugin jetty.

Il mio progetto funziona correttamente quando eseguo il mio progetto usando mvn jetty: comando di esecuzione.

Ma quando impacchetta il mio progetto usando il comando mvn clean package ed eseguo il file jar che ha il nome jar-with-dependencies, il progetto lancia questa eccezione mentre restituisce una risposta json da una risorsa jersey.

SEVERE: MessageBodyWriter non trovato per il tipo di supporto = application / json, type = class com.nitish.freecharge.model.Count, genericType = class com.nitish.freecharge.model.Count.

Ecco il mio file pom.xml

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

4.0.0 com.nitish.freecharge wordcount war 2.0 wordcount  wordcount   src/main/java   src/main/resources   src/main/webapp     org.apache.maven.plugins maven-compiler-plugin 2.5.1 true  1.7 1.7    org.eclipse.jetty jetty-maven-plugin 9.3.0.v20150612  5  /wordcount    9999     org.apache.maven.plugins maven-jar-plugin 2.4   package-jar package  jar      org.apache.maven.plugins maven-assembly-plugin 2.6  awesomeProject  jar-with-dependencies  false   App      package  single          org.glassfish.jersey jersey-bom ${jersey.version} pom import      org.glassfish.jersey.core jersey-server   org.glassfish.jersey.containers jersey-container-servlet-core   org.glassfish.jersey.media jersey-media-moxy   org.eclipse.jetty jetty-server 9.3.8.v20160314   org.eclipse.jetty jetty-servlet 9.3.8.v20160314   junit junit 4.4    2.22.2 UTF-8  

Ho creato la mia class Main Driver come App.java nel pacchetto predefinito. Ecco il mio contenuto 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(); } } } 

Ecco la mia unica class di risorsa jersey che viene eseguita quando accedo all’URL del mio progetto dopo aver avviato il 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(); } } } 

Dopo aver imballato ed eseguito il progetto embedded completo usando il comando java -jar awesomeProject.jar

Ottengo questo output sul prompt del server

inserisci la descrizione dell'immagine qui

Ho provato molto e non sono riuscito a confezionare la mia webapp incorporata in modo tale da risolvere questo problema. Sono nuovo di Maven e Packaging. Gentilmente aiuto dove sto commettendo un errore.

Se guardi all’interno del barattolo MOXy, vedrai una cartella META-INF/services . In quella cartella, vedrai un file chiamato org.glassfish.jersey.internal.spi.AutoDiscoverable . Il contenuto di quel file dovrebbe essere una singola riga

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

A cosa serve questo file è consentire a Jersey di scoprire MoxyJsonAutoDiscoverable , che registra MOXy per Jersey. Questo modello di caricatore di servizi consente a Jersey di scoprire le funzionalità e registrarle, senza che noi dobbiamo registrarle da soli.

Il problema che si pone quando si crea un jar uber è che potrebbero esserci più jar con lo stesso file, poiché i diversi jar hanno caratteristiche diverse da scoprire, ma il file deve essere il nome esatto poiché è così che funziona il modello del caricatore di servizi.

Quindi hai un sacco di barattoli con lo stesso file, ma quando crei il jar uber, non puoi avere più file con lo stesso nome. Non è ansible. Quindi solo uno dei file viene inserito nel jar finale. Quale … chi lo sa. Ma questo significa che se i file di MOXy non sono quel file, allora la sua funzione non verrà scoperta automaticamente, e dobbiamo registrarla noi stessi. Quindi le classi sono confezionate nel jar uber, ma il componente principale non è registrato. Potresti semplicemente registrarlo da solo

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

ma che dire di tutte le altre possibili funzionalità che sono probabilmente escluse perché il loro file auto-rilevabile non è incluso?

Per questo motivo, invece del plugin assembly, dovresti usare il maven-shade-plugin , che ha trasformatori che ci permettono di concatenare i contenuti dei file di servizio in un unico file.

La configurazione sembrerebbe qualcosa di simile

  org.apache.maven.plugins maven-shade-plugin 2.3  true   *:*  META-INF/*.SF META-INF/*.DSA META-INF/*.RSA       package  shade      com.example.YourApp       

Il ServicesResorceTransformaer è ciò che concatena i file. Questa particolare configurazione del plugin stava prendendo avvio da Dropwizard . Si consiglia di verificarlo per ulteriori spiegazioni.