How do I get Jersey Test/Client to not fill in a default Accept header?

大兔子大兔子 提交于 2019-12-01 17:40:43

Not sure if this helps anyone else but we were seeing similar behavior calling a service in production with our client code. We are using Jersey 2.21.1.

Expanded the code from the original post and found the following to be true:

  • if Accept header is null then Jersey adds the default
  • if Accept header is an empty String then an empty Accept header is used
  • if Accept header has a value it is used

I'm not sure if there is a way to tell Jersey not to add the default value when a null is used.

public class JerseyAcceptHeaderTest extends JerseyTest {

    @Path("hello")
    public static class HelloResource {
        @GET
        public String getHello(@Context HttpHeaders httpHeaders) {
            String acceptHeader = httpHeaders.getHeaderString(HttpHeaders.ACCEPT);
            System.out.println("SERVER RECEIVED:" + acceptHeader);

            if (acceptHeader == null) {
                return "Null Accept Header";
            } else if (acceptHeader.equals("")) {
                return "No Accept Header";
            } else {
                return acceptHeader;
            }
        }
    }

    @Override
    protected Application configure() {
        return new ResourceConfig(HelloResource.class);
    }

    /**
     * this seems to be a bug in Jersey
     * it overrides a null Accept header
     */
    @Test
    public void test_accept_header_with_null() {
        final String acceptHeader = target("hello").request()
                .header(HttpHeaders.ACCEPT, null)
                .get(String.class);
        assertEquals("Null Accept Header", acceptHeader);
    }

    @Test
    public void test_accept_header_with_empty_string() {
        final String acceptHeader = target("hello").request()
                .header(HttpHeaders.ACCEPT, "")
                .get(String.class);
        assertEquals("No Accept Header", acceptHeader);
    }

    @Test
    public void test_accept_header_with_spaced_string() {
        final String acceptHeader = target("hello").request()
                .header(HttpHeaders.ACCEPT, "  ")
                .get(String.class);
        assertEquals("No Accept Header", acceptHeader);
    }

    @Test
    public void test_accept_header_with_value() {
        final String acceptHeader = target("hello").request()
                .header(HttpHeaders.ACCEPT, "application/json")
                .get(String.class);
        assertEquals("application/json", acceptHeader);
    }

}

I'm facing the same issue right now and after some research, I ended up finding the problem.

WebResourceFactory.invoke(final Object proxy, final Method method, final Object[] {
    ...
    Invocation.Builder builder = newTarget.request()
            .headers(headers) // this resets all headers so do this first
            .accept(accepts); // if @Produces is defined, propagate values into Accept header; empty array is NO-OP
    ...
}

The request builder is automatically adding into the existing headers the media types specified in the API (@Produce). Sadly I did not find a way to disable that behaviour. So I'll try to extend the WebResourceFactory class (which is final) used to create my client and overrided that method invoke to not call the accept on the request builder.

Be aware that I dont consider this as a solution but more as a workaround.

[EDIT] Since WebResourceFactory is final, I have duplicated it's content and removed the accept call on the request builder. A little bit ugly, I know and hope someone will find a better way.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!