JAX-RS - Come restituire codice di stato JSON e HTTP insieme?


248

Sto scrivendo un'app Web REST (NetBeans 6.9, JAX-RS, TopLink Essentials) e sto cercando di restituire il codice di stato JSON e HTTP. Ho il codice pronto e funzionante che restituisce JSON quando il metodo HTTP GET viene chiamato dal client. Essenzialmente:

@Path("get/id")
@GET
@Produces("application/json")
public M_機械 getMachineToUpdate(@PathParam("id") String id) {

    // some code to return JSON ...

    return myJson;
}

Ma voglio anche restituire un codice di stato HTTP (500, 200, 204, ecc.) Insieme ai dati JSON.

Ho provato ad usare HttpServletResponse:

response.sendError("error message", 500);

Ma questo ha fatto pensare al browser che fosse un "vero" 500, quindi la pagina Web di output era una normale pagina di errore HTTP 500.

Voglio restituire un codice di stato HTTP in modo che il mio JavaScript lato client sia in grado di gestire un po 'di logica a seconda di esso (ad esempio, visualizzare il codice di errore e il messaggio su una pagina HTML). È possibile o non dovrebbero essere usati codici di stato HTTP per tale cosa?


2
Qual è la differenza tra 500 che vuoi (irreale? :)) e 500 reali?
rasoio,

@razor Qui 500 reale significa una pagina di errore HTML invece della risposta JSON
Nupur

il browser web non è stato progettato per funzionare con JSON, ma con pagine HTML, quindi se rispondi con 500 (e anche con qualche corpo di messaggio), il browser può mostrarti solo un messaggio di errore (dipende davvero dall'implementazione del browser), solo perché è utile per un utente normale.
rasoio,

Risposte:


347

Ecco un esempio:

@GET
@Path("retrieve/{uuid}")
public Response retrieveSomething(@PathParam("uuid") String uuid) {
    if(uuid == null || uuid.trim().length() == 0) {
        return Response.serverError().entity("UUID cannot be blank").build();
    }
    Entity entity = service.getById(uuid);
    if(entity == null) {
        return Response.status(Response.Status.NOT_FOUND).entity("Entity not found for UUID: " + uuid).build();
    }
    String json = //convert entity to json
    return Response.ok(json, MediaType.APPLICATION_JSON).build();
}

Dai un'occhiata alla classe Response .

Nota che devi sempre specificare un tipo di contenuto, specialmente se stai passando più tipi di contenuto, ma se ogni messaggio sarà rappresentato come JSON, puoi semplicemente annotare il metodo con @Produces("application/json")


12
Funziona, ma ciò che non mi piace del valore restituito dalla risposta è che secondo me inquina il tuo codice, specialmente per quanto riguarda qualsiasi client che cerca di usarlo. Se fornisci un'interfaccia che restituisce una risposta a una terza parte, non sa che tipo stai realmente restituendo. Spring lo rende più chiaro con un'annotazione, molto utile se si restituisce sempre un codice di stato (cioè HTTP 204)
Guido

19
Rendere quella classe generica (Response <T>) sarebbe un miglioramento interessante di jax-rs, per avere i vantaggi di entrambe le alternative.
Guido,

41
Non è necessario convertire l'entità in json in qualche modo. Puoi fare return Response.status(Response.Status.Forbidden).entity(myPOJO).build();Works come se lo avessi fatto return myPOJO;, ma con un'impostazione aggiuntiva del codice di stato HTTP.
Kratenko,

1
Penso che separare la logica di business in una classe di servizio separata funzioni bene. L'endpoint utilizza Response come tipo di ritorno ed i suoi metodi sono principalmente solo chiamate ai metodi di servizio più il percorso e le annotazioni dei parametri. Separa in modo pulito la logica dalla mappatura del tipo di url / content (dove la gomma colpisce la strada per così dire).
Stijn de Witt,

in realtà, si può semplicemente restituire l'oggetto che non si sposta sulla risposta.
sabato

191

Esistono diversi casi d'uso per l'impostazione dei codici di stato HTTP in un servizio Web REST e almeno uno non è stato sufficientemente documentato nelle risposte esistenti (ad esempio quando si utilizza la serializzazione JSON / XML auto-magica utilizzando JAXB e si desidera restituire un oggetto da serializzare, ma anche un codice di stato diverso dal 200 predefinito).

Vorrei quindi provare a elencare i diversi casi d'uso e le soluzioni per ognuno:

1. Codice errore (500, 404, ...)

Il caso d'uso più comune quando si desidera restituire un codice di stato diverso da 200 OKquando si verifica un errore.

Per esempio:

  • è richiesta un'entità ma non esiste (404)
  • la richiesta è semanticamente errata (400)
  • l'utente non è autorizzato (401)
  • c'è un problema con la connessione al database (500)
  • eccetera..

a) Generare un'eccezione

In tal caso, penso che il modo più pulito per gestire il problema sia quello di generare un'eccezione. Questa eccezione verrà gestita da un ExceptionMapper, che tradurrà l'eccezione in una risposta con il codice di errore appropriato.

È possibile utilizzare il valore predefinito ExceptionMapperpreconfigurato con Jersey (e immagino che sia lo stesso con altre implementazioni) e lanciare una delle sottoclassi esistenti di javax.ws.rs.WebApplicationException. Si tratta di tipi di eccezione predefiniti che sono pre-mappati su diversi codici di errore, ad esempio:

  • BadRequestException (400)
  • InternalServerErrorException (500)
  • NotFoundException (404)

Ecc. Puoi trovare l'elenco qui: API

In alternativa, puoi definire le tue eccezioni e ExceptionMapperclassi personalizzate e aggiungere questi mappatori a Jersey in base @Providerall'annotazione ( fonte di questo esempio ):

public class MyApplicationException extends Exception implements Serializable
{
    private static final long serialVersionUID = 1L;
    public MyApplicationException() {
        super();
    }
    public MyApplicationException(String msg)   {
        super(msg);
    }
    public MyApplicationException(String msg, Exception e)  {
        super(msg, e);
    }
}

Fornitore:

    @Provider
    public class MyApplicationExceptionHandler implements ExceptionMapper<MyApplicationException> 
    {
        @Override
        public Response toResponse(MyApplicationException exception) 
        {
            return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();  
        }
    }

Nota: puoi anche scrivere ExceptionMapper per i tipi di eccezione esistenti che usi.

b) Utilizzare il builder Response

Un altro modo per impostare un codice di stato è utilizzare un Responsebuilder per creare una risposta con il codice previsto.

In tal caso, il tipo restituito dal metodo deve essere javax.ws.rs.core.Response. Questo è descritto in varie altre risposte come la risposta accettata da Hisdrewness e si presenta così:

@GET
@Path("myresource({id}")
public Response retrieveSomething(@PathParam("id") String id) {
    ...
    Entity entity = service.getById(uuid);
    if(entity == null) {
        return Response.status(Response.Status.NOT_FOUND).entity("Resource not found for ID: " + uuid).build();
    }
    ...
}

2. Successo, ma non 200

Un altro caso in cui si desidera impostare lo stato di ritorno è quando l'operazione ha avuto esito positivo, ma si desidera restituire un codice di successo diverso da 200, insieme al contenuto che si restituisce nel corpo.

Un caso di utilizzo frequente è quando si crea una nuova entità ( POSTrichiesta) e si desidera restituire informazioni su questa nuova entità o sull'entità stessa, insieme a un 201 Createdcodice di stato.

Un approccio consiste nell'utilizzare l'oggetto response proprio come descritto sopra e impostare tu stesso il corpo della richiesta. Tuttavia, perdendo la possibilità di utilizzare la serializzazione automatica in XML o JSON fornita da JAXB.

Questo è il metodo originale che restituisce un oggetto entità che verrà serializzato su JSON da JAXB:

@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user){
    User newuser = ... do something like DB insert ...
    return newuser;
}

Ciò restituirà una rappresentazione JSON dell'utente appena creato, ma lo stato di ritorno sarà 200, non 201.

Ora il problema è se voglio usare il Responsebuilder per impostare il codice di ritorno, devo restituire un Responseoggetto nel mio metodo. Come posso ancora restituire l' Useroggetto da serializzare?

a) Impostare il codice sulla risposta servlet

Un approccio per risolvere questo problema è ottenere un oggetto richiesta servlet e impostare manualmente il codice di risposta, come dimostrato nella risposta di Garett Wilson:

@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user, @Context final HttpServletResponse response){

    User newUser = ...

    //set HTTP code to "201 Created"
    response.setStatus(HttpServletResponse.SC_CREATED);
    try {
        response.flushBuffer();
    }catch(Exception e){}

    return newUser;
}

Il metodo restituisce comunque un oggetto entità e il codice di stato sarà 201.

Nota che per farlo funzionare, ho dovuto svuotare la risposta. Questa è una spiacevole rinascita del codice API Servlet di basso livello nella nostra bella risorsa JAX_RS, e molto peggio, fa sì che le intestazioni non siano modificabili dopo questo perché erano già state inviate sul filo.

b) Utilizzare l'oggetto risposta con l'entità

La soluzione migliore, in tal caso, è utilizzare l'oggetto Response e impostare l'entità da serializzare su questo oggetto response. Sarebbe bello rendere generico l'oggetto Response per indicare il tipo di entità payload in quel caso, ma non è attualmente il caso.

@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addUser(User user){

    User newUser = ...

    return Response.created(hateoas.buildLinkUri(newUser, "entity")).entity(restResponse).build();
}

In tal caso, utilizziamo il metodo creato della classe Builder Response per impostare il codice di stato su 201. Passiamo l'oggetto entità (utente) alla risposta tramite il metodo entity ().

Il risultato è che il codice HTTP è 401 come volevamo, e il corpo della risposta è esattamente lo stesso JSON che avevamo prima quando abbiamo appena restituito l'oggetto Utente. Aggiunge anche un'intestazione di posizione.

La classe Response ha un numero di metodo builder per diversi stati (stati?) Come:

Response.accepted () Response.ok () Response.noContent () Response.notAcceptable ()

NB: l'oggetto hateoas è una classe di supporto che ho sviluppato per aiutare a generare risorse URI. Dovrai inventare il tuo meccanismo qui;)

Questo è tutto.

Spero che questa lunga risposta aiuti qualcuno :)


Mi chiedo se esiste un modo chiaro per restituire l'oggetto dati stesso invece della risposta. La flushè davvero sporca.
AlikElzin-Kilaka

1
Solo una mia piccola pipì: 401 non significa che l'utente non è autorizzato. Significa che il client non è autorizzato, perché il server non sa chi sei. Se a un utente registrato / altrimenti riconosciuto non è consentito eseguire una determinata azione, il codice di risposta corretto è 403 proibito.
Demonblack,

69

La risposta di Hisdrewness funzionerà, ma modifica l'intero approccio per consentire a un provider come Jackson + JAXB di convertire automaticamente l'oggetto restituito in un formato di output come JSON. Ispirato da un post Apache CXF (che utilizza una classe specifica CXF) ho trovato un modo per impostare il codice di risposta che dovrebbe funzionare in qualsiasi implementazione JAX-RS: iniettare un contesto HttpServletResponse e impostare manualmente il codice di risposta. Ad esempio, ecco come impostare il codice di risposta su CREATEDquando appropriato.

@Path("/foos/{fooId}")
@PUT
@Consumes("application/json")
@Produces("application/json")
public Foo setFoo(@PathParam("fooID") final String fooID, final Foo foo, @Context final HttpServletResponse response)
{
  //TODO store foo in persistent storage
  if(itemDidNotExistBefore) //return 201 only if new object; TODO app-specific logic
  {
    response.setStatus(Response.Status.CREATED.getStatusCode());
  }
  return foo;  //TODO get latest foo from storage if needed
}

Miglioramento: dopo aver trovato un'altra risposta correlata , ho imparato che si può iniettare HttpServletResponsecome variabile membro, anche per la classe di servizio singleton (almeno in RESTEasy) !! Questo è un approccio molto migliore rispetto all'inquinamento dell'API con dettagli di implementazione. Sarebbe così:

@Context  //injected response proxy supporting multiple threads
private HttpServletResponse response;

@Path("/foos/{fooId}")
@PUT
@Consumes("application/json")
@Produces("application/json")
public Foo setFoo(@PathParam("fooID") final String fooID, final Foo foo)
{
  //TODO store foo in persistent storage
  if(itemDidNotExistBefore) //return 201 only if new object; TODO app-specific logic
  {
    response.setStatus(Response.Status.CREATED.getStatusCode());
  }
  return foo;  //TODO get latest foo from storage if needed
}

Puoi effettivamente combinare gli approcci: annota il metodo con @Producese non specificare il tipo di supporto nel finale Response.ok, e otterrai correttamente l'oggetto di ritorno serializzato JAXB nel tipo di supporto appropriato per soddisfare la richiesta. (Ho appena provato questo con un singolo metodo che potrebbe restituire XML o JSON: il metodo stesso non deve nemmeno menzionarlo, tranne nell'annotazione @Produces.)
Royston Shufflebotham,

Hai ragione Garret. Il mio esempio è stato più un esempio dell'enfasi di fornire un tipo di contenuto. I nostri approcci sono simili, ma l'idea di utilizzare a MessageBodyWritere Providerconsente la negoziazione implicita dei contenuti, anche se sembra che nel tuo esempio manchi del codice. Ecco un'altra risposta che ho fornito che illustra questo: stackoverflow.com/questions/5161466/...
hisdrewness

8
Non riesco a sovrascrivere il codice di stato response.setStatus(). L'unico modo per inviare ad esempio una risposta 404 non trovata è impostare il codice di stato della risposta response.setStatus(404)e quindi chiudere il flusso di output in response.getOutputStream().close()modo che JAX-RS non possa ripristinare il mio stato.
Rob Juurlink il

2
Sono stato in grado di utilizzare questo approccio per impostare un codice 201, ma ho dovuto aggiungere un blocco try-catch response.flushBuffer()per evitare che il framework prevalesse sul mio codice di risposta. Non molto pulito
Pierre Henry,

1
@RobJuurlink, se si desidera specificamente restituire un 404 Not Found, potrebbe essere più semplice da usare throw new NotFoundException().
Garret Wilson,

34

Se ti piace mantenere pulito il tuo livello di risorse dagli Responseoggetti, ti consiglio di utilizzare @NameBindinge associare le implementazioni di ContainerResponseFilter.

Ecco la carne dell'annotazione:

package my.webservice.annotations.status;

import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
  int CREATED = 201;
  int value();
}

Ecco la carne del filtro:

package my.webservice.interceptors.status;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

@Provider
public class StatusFilter implements ContainerResponseFilter {

  @Override
  public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
    if (containerResponseContext.getStatus() == 200) {
      for (Annotation annotation : containerResponseContext.getEntityAnnotations()) {
        if(annotation instanceof Status){
          containerResponseContext.setStatus(((Status) annotation).value());
          break;
        }
      }
    }
  }
}

E quindi l'implementazione sulla tua risorsa diventa semplicemente:

package my.webservice.resources;

import my.webservice.annotations.status.StatusCreated;
import javax.ws.rs.*;

@Path("/my-resource-path")
public class MyResource{
  @POST
  @Status(Status.CREATED)
  public boolean create(){
    return true;
  }
}

Mantiene l'API pulita, bella risposta. Sarebbe possibile parametrizzare la tua annotazione come @Status (code = 205) e fare in modo che l'interceptor sostituisca il codice con qualunque cosa tu specifichi? Penso che in sostanza ti darebbe un'annotazione per sovrascrivere i codici ogni volta che è necessario.
user2800708

@ user2800708, l'ho già fatto per il mio codice locale, ho aggiornato la risposta come mi hai suggerito.
Nthalk,

Bene grazie. Con questo e alcuni altri trucchi sono praticamente ora in grado di ripulire le API REST nel mio codice, in modo che sia conforme a una semplice interfaccia Java senza menzione di REST in essa; è solo un altro meccanismo RMI.
user2800708

6
Invece di eseguire il looping per le annotazioni in StatusFilter, è possibile annotare il filtro con @ Status oltre a @ Provider. Quindi il filtro verrà chiamato solo su risorse annotate con @ Status. Questo è lo scopo di @ NameBinding
trevorismo il

1
Buon callout @trevorism. C'è un effetto collaterale non altrettanto piacevole StatusFiltercon l' annotazione @Status: o devi fornire un valore predefinito per il valuecampo dell'annotazione o dichiararne uno quando annoti la classe (es:) @Status(200). Questo ovviamente non è l'ideale.
Phil,

6

Nel caso in cui si desideri modificare il codice di stato a causa di un'eccezione, con JAX-RS 2.0 è possibile implementare un ExceptionMapper come questo. Questo gestisce questo tipo di eccezione per l'intera app.

@Provider
public class UnauthorizedExceptionMapper implements ExceptionMapper<EJBAccessException> {

    @Override
    public Response toResponse(EJBAccessException exception) {
        return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
    }

}

6

Se il tuo WS-RS deve generare un errore, perché non usare semplicemente WebApplicationException?

@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("{id}")
public MyEntity getFoo(@PathParam("id") long id,  @QueryParam("lang")long idLanguage) {

if (idLanguage== 0){
    // No URL parameter idLanguage was sent
    ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
    builder.entity("Missing idLanguage parameter on request");
    Response response = builder.build();
    throw new WebApplicationException(response);
    }
... //other stuff to return my entity
return myEntity;
}

4
A mio avviso, WebApplicationExceptions non è adatto per errori lato client perché generano tracce di grandi stack. Gli errori del client non devono generare tracce dello stack lato server e inquinare la registrazione con esso.
Rob Juurlink il

5

JAX-RS ha il supporto per codici HTTP standard / personalizzati. Vedi ResponseBuilder e ResponseStatus, ad esempio:

http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/Response.ResponseBuilder.html#status%28javax.ws.rs.core.Response.Status%29

Tieni presente che le informazioni JSON riguardano maggiormente i dati associati alla risorsa / applicazione. I codici HTTP riguardano maggiormente lo stato dell'operazione CRUD richiesta. (almeno così dovrebbe essere nei sistemi REST-ful)


il collegamento è interrotto
Umpa

5

Ho trovato molto utile creare anche un messaggio json con codice ripetuto, come questo:

@POST
@Consumes("application/json")
@Produces("application/json")
public Response authUser(JsonObject authData) {
    String email = authData.getString("email");
    String password = authData.getString("password");
    JSONObject json = new JSONObject();
    if (email.equalsIgnoreCase(user.getEmail()) && password.equalsIgnoreCase(user.getPassword())) {
        json.put("status", "success");
        json.put("code", Response.Status.OK.getStatusCode());
        json.put("message", "User " + authData.getString("email") + " authenticated.");
        return Response.ok(json.toString()).build();
    } else {
        json.put("status", "error");
        json.put("code", Response.Status.NOT_FOUND.getStatusCode());
        json.put("message", "User " + authData.getString("email") + " not found.");
        return Response.status(Response.Status.NOT_FOUND).entity(json.toString()).build();
    }
}

4

Guarda l'esempio qui, illustra meglio il problema e come è risolto nell'ultima versione (2.3.1) di Jersey.

https://jersey.java.net/documentation/latest/representations.html#d0e3586

Fondamentalmente implica la definizione di un'eccezione personalizzata e il mantenimento del tipo restituito come entità. Quando si verifica un errore, viene generata l'eccezione, altrimenti si restituisce il POJO.


Vorrei aggiungere che l'esempio di interesse è quello in cui definiscono la propria classe di eccezioni e la costruiscono Response. Cerca la CustomNotFoundExceptionlezione e magari copiarla nel tuo post.
JBert

Uso questo approccio per errori e mi piace. Ma non è applicabile ai codici di successo (diversi da 200) come "201 creato".
Pierre Henry,

3

Non sto usando JAX-RS, ma ho uno scenario simile in cui utilizzo:

response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());

Lo fa per me usando Spring MVC ma c'è un modo semplice per scoprirlo!
Cappellini

1

Inoltre, tieni presente che, per impostazione predefinita, Jersey sostituirà il corpo della risposta in caso di un codice http 400 o più.

Per ottenere l'entità specificata come corpo della risposta, prova ad aggiungere il seguente init-param a Jersey nel tuo file di configurazione web.xml:

    <init-param>
        <!-- used to overwrite default 4xx state pages -->
        <param-name>jersey.config.server.response.setStatusOverSendError</param-name>
        <param-value>true</param-value>
    </init-param>

0

Il seguente codice ha funzionato per me. Iniettare messageContext tramite setter annotato e impostare il codice di stato nel mio metodo "aggiungi".

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import org.apache.cxf.jaxrs.ext.MessageContext;

public class FlightReservationService {

    MessageContext messageContext;

    private final Map<Long, FlightReservation> flightReservations = new HashMap<>();

    @Context
    public void setMessageContext(MessageContext messageContext) {
        this.messageContext = messageContext;
    }

    @Override
    public Collection<FlightReservation> list() {
        return flightReservations.values();
    }

    @Path("/{id}")
    @Produces("application/json")
    @GET
    public FlightReservation get(Long id) {
        return flightReservations.get(id);
    }

    @Path("/")
    @Consumes("application/json")
    @Produces("application/json")
    @POST
    public void add(FlightReservation booking) {
        messageContext.getHttpServletResponse().setStatus(Response.Status.CREATED.getStatusCode());
        flightReservations.put(booking.getId(), booking);
    }

    @Path("/")
    @Consumes("application/json")
    @PUT
    public void update(FlightReservation booking) {
        flightReservations.remove(booking.getId());
        flightReservations.put(booking.getId(), booking);
    }

    @Path("/{id}")
    @DELETE
    public void remove(Long id) {
        flightReservations.remove(id);
    }
}

0

Espandendo la risposta di Nthalk con Microprofile OpenAPI puoi allineare il codice di ritorno con la tua documentazione usando l' annotazione @APIResponse .

Ciò consente di etichettare un metodo JAX-RS come

@GET
@APIResponse(responseCode = "204")
public Resource getResource(ResourceRequest request) 

È possibile analizzare questa annotazione standardizzata con un ContainerResponseFilter

@Provider
public class StatusFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
        if (responseContext.getStatus() == 200) {
            for (final var annotation : responseContext.getEntityAnnotations()) {
                if (annotation instanceof APIResponse response) {
                    final var rawCode = response.responseCode();
                    final var statusCode = Integer.parseInt(rawCode);

                    responseContext.setStatus(statusCode);
                }
            }
        }
    }

}

Un avvertimento si verifica quando si inseriscono più annotazioni sul metodo come

@APIResponse(responseCode = "201", description = "first use case")
@APIResponse(responseCode = "204", description = "because you can")
public Resource getResource(ResourceRequest request) 

-1

Sto usando la maglia 2.0 con lettori e scrittori di messaggi. Avevo il mio metodo return tipo come un'entità specifica che era anche usata nell'implementazione del writer del corpo del messaggio e stavo restituendo lo stesso pojo, uno SkuListDTO. @GET @Consumes ({"application / xml", "application / json"}) @Produces ({"application / xml", "application / json"}) @Path ("/ skuResync")

public SkuResultListDTO getSkuData()
    ....
return SkuResultListDTO;

tutto ciò che ho cambiato è stato questo, ho lasciato l'implementazione dello scrittore da sola e funzionava ancora.

public Response getSkuData()
...
return Response.status(Response.Status.FORBIDDEN).entity(dfCoreResultListDTO).build();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.