Jersey 客户端请求中的多个返回类型

发布于 2024-08-17 01:29:28 字数 1074 浏览 2 评论 0原文

我按以下方式使用 Jersey Client API:-

User user = webRsrc.accept(MediaType.APPLICATION_XML).post(User.class, usr);

所以我期待 User 类的对象中的响应,该类是 JAXB 带注释的类。 然而,有时我也可能会收到错误 xml,为此我创建了一个 JAXB 类 ErrorResponse。

现在的问题是,如果我的请求返回 ErrorResponse 而不是 User 的对象,我该如何处理?

我尝试这样 -

ClientResponse response=null;
try {

        response = webRsrc.accept(MediaType.APPLICATION_XML).post(ClientResponse.class,usr);
        User usr = response.getEntity(User.class);    
    }catch(Exception exp)
    {
       ErrorResponse err = response.getEntity(ErrorResponse.class);    
    }

但是当我尝试在 catch 块中使用 getEntity() 时,它会抛出以下异常

[org.xml.sax.SAXParseException: Premature end of file.]
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.readFrom(AbstractRootElementProvider.java:107)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:532)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:491) .....

似乎在调用 getEntity() 一次后,输入流已耗尽。

I'm using Jersey Client API in the following way :-

User user = webRsrc.accept(MediaType.APPLICATION_XML).post(User.class, usr);

So I'm expecting the response in object of User class which is a JAXB annotated class.
However, at times I might also get an error xml and for that I've created a JAXB class ErrorResponse.

Now the problem is that if my request returns an object of ErrorResponse instead of User how can I handle that ?

I tried like this -

ClientResponse response=null;
try {

        response = webRsrc.accept(MediaType.APPLICATION_XML).post(ClientResponse.class,usr);
        User usr = response.getEntity(User.class);    
    }catch(Exception exp)
    {
       ErrorResponse err = response.getEntity(ErrorResponse.class);    
    }

But when I try to use getEntity() in catch block, it throws following exception

[org.xml.sax.SAXParseException: Premature end of file.]
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.readFrom(AbstractRootElementProvider.java:107)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:532)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:491) .....

Seems like after calling getEntity() once, the inputstream is exhausted.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浊酒尽余欢 2024-08-24 01:29:29

这种代码可用于管理响应中的错误消息或业务消息:

protected <T> T call(String uri, Class<T> c) throws  BusinessException {


    WebResource res = new Client().create().resource(url);
    ClientResponse cresp = res.get(ClientResponse.class);
    InputStream respIS = cresp.getEntityInputStream();


    try {
        // Managing business or error response
        JAXBContext jCtx = JAXBContext.newInstance(c, BeanError.class);
        Object entity = jCtx.createUnmarshaller().unmarshal(respIS);

        // If the response is an error, throw an exception
        if(entity instanceof  BeanError) {
            BeanError error = (BeanError) entity;
            throw new  BusinessException(error);

        // If this not an error, this is the business response
        } else {
            return (T) entity;
        }

    } catch (JAXBException e) {

        throw(new BusinessException(e));
    }



}

This kind of code could be used to manage Error message or business message in the response :

protected <T> T call(String uri, Class<T> c) throws  BusinessException {


    WebResource res = new Client().create().resource(url);
    ClientResponse cresp = res.get(ClientResponse.class);
    InputStream respIS = cresp.getEntityInputStream();


    try {
        // Managing business or error response
        JAXBContext jCtx = JAXBContext.newInstance(c, BeanError.class);
        Object entity = jCtx.createUnmarshaller().unmarshal(respIS);

        // If the response is an error, throw an exception
        if(entity instanceof  BeanError) {
            BeanError error = (BeanError) entity;
            throw new  BusinessException(error);

        // If this not an error, this is the business response
        } else {
            return (T) entity;
        }

    } catch (JAXBException e) {

        throw(new BusinessException(e));
    }



}
谷夏 2024-08-24 01:29:29

如果您无法更改服务器代码,可以使用ReaderInterceptor。这确实有一些限制,但您至少能够获取错误响应对象的内容。


我正在使用 JSON,但适用相同的原则:

public class MyException extends RuntimeException {

    private final ErrorResponse content;

    public MyException(ErrorResponse content) {
        this.content = content;
    }

    public ErrorResponse getContent() {
        return content;
    }
}

public class ErrorResultInterceptor implements ReaderInterceptor {

    private static final ObjectReader JSON = new ObjectMapper().readerFor(ErrorResponse.class);

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
    byte[] buffer = context.getInputStream().readAllBytes();
    context.setInputStream(new ByteArrayInputStream(buffer));
        try {
            return context.proceed();
        } catch (UnrecognizedPropertyException ex) {
            try {
                throw new MyException(JSON.readValue(buffer));
            } catch (IOException errorProcessingEx) {
                // Log errorProcessingEx using your preferred framework
                throw ex;
            }
        }
    }
}

然后将其用作调用的一部分:

client.register(ErrorResultInterceptor.class);
// Oher client setup
try {
    // Make the client call
    // Handle OK case
} catch (ResponseProcessingException ex) {
    if (ex.getCause() instanceof MyException) {
        ErrorResponse respone = ((MyException)ex.getCause()).getContent();
        // Handle error response
    } else {
        throw ex;
    }
}

限制是:

  • 必须缓冲响应,这可能会产生内存开销
  • 获取错误结果的客户端调用非常笨拙

If you can't change the server code, you can use a ReaderInterceptor. This does have some limitations but you will at least be able to get the contents of the error response object.


I'm using JSON but the same principles apply:

public class MyException extends RuntimeException {

    private final ErrorResponse content;

    public MyException(ErrorResponse content) {
        this.content = content;
    }

    public ErrorResponse getContent() {
        return content;
    }
}

public class ErrorResultInterceptor implements ReaderInterceptor {

    private static final ObjectReader JSON = new ObjectMapper().readerFor(ErrorResponse.class);

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
    byte[] buffer = context.getInputStream().readAllBytes();
    context.setInputStream(new ByteArrayInputStream(buffer));
        try {
            return context.proceed();
        } catch (UnrecognizedPropertyException ex) {
            try {
                throw new MyException(JSON.readValue(buffer));
            } catch (IOException errorProcessingEx) {
                // Log errorProcessingEx using your preferred framework
                throw ex;
            }
        }
    }
}

Then use this as part of the invocation:

client.register(ErrorResultInterceptor.class);
// Oher client setup
try {
    // Make the client call
    // Handle OK case
} catch (ResponseProcessingException ex) {
    if (ex.getCause() instanceof MyException) {
        ErrorResponse respone = ((MyException)ex.getCause()).getContent();
        // Handle error response
    } else {
        throw ex;
    }
}

Limitations are:

  • The response has to be buffered which could be a memory overhead
  • The client call to get hold of the error result is very clunky
提笔书几行 2024-08-24 01:29:28

我认为您错过了整个“REST 思维方式”中的一点。
简短的回答:是的,您只能调用 getEntity 一次。您需要检查返回的 HTTP 状态以了解您应该获取什么实体。

在服务器端:

  1. 设计 REST API 时,应始终使用适当的状态代码关于HTTP RFC
  2. 为此,请考虑使用 ExceptionMapper接口(这是一个带有“NotFoundException”的示例因此

,现在您的服务器返回带有 User 对象的“HTTP status OK - 200”,或者带有错误对象的错误状态。

在客户端:

您需要检查返回状态并根据 API 规范调整您的行为。
这是一个快速而肮脏的代码示例:

ClientResponse response=null;

response = webRsrc.accept(MediaType.APPLICATION_XML).post(ClientResponse.class,usr);

int status = response.getStatus();

if (Response.Status.OK.getStatusCode() == status) {

  // normal case, you receive your User object
  User usr = response.getEntity(User.class);

} else {

  ErrorResponse err = response.getEntity(ErrorResponse.class);
}

注意:根据返回的状态代码,此错误可能非常不同(因此需要非常不同的行为):

  • 客户端错误 40X:您的客户端请求错误
  • 服务器错误 500:发生意外错误服务器端

I think you missed a point in the whole "REST way of thinking".
Short answer: yes, you can only call getEntity once. You need to check the returned HTTP status to know what entity you should get.

On the server side:

  1. When designing a REST API, one should always use appropriate status codes regarding the HTTP RFC.
  2. For that matter, please consider using the ExceptionMapper interface (here's an example with a "NotFoundException"

So, now your server returns either "HTTP status OK - 200" with a User object, or an error status with an error object.

On the client side:

You need to check the return status and adapt your behavior according to the API spec.
here's a quick and dirty code sample:

ClientResponse response=null;

response = webRsrc.accept(MediaType.APPLICATION_XML).post(ClientResponse.class,usr);

int status = response.getStatus();

if (Response.Status.OK.getStatusCode() == status) {

  // normal case, you receive your User object
  User usr = response.getEntity(User.class);

} else {

  ErrorResponse err = response.getEntity(ErrorResponse.class);
}

NB: depending on the status code returned, this error could be very different (thus needing very different behavior):

  • client error 40X: your client request is wrong
  • server error 500: an unexpected error occured on the server side
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文