3

I've a CXF RESTful service which returns both XML and Json format. I need to add a custom http header in the RESTful service. Here's a sample code snippet.


    @GET
    @Path("/test")
    @Produces("application/xml")
    public Response test(
            @QueryParam("p") String var
    {
        TestRequest req = new TestRequest();
        req.setVar(var);
        TestResponse res = p.getData(req);
        return Response.ok(res).header("Result", res.getResult()).build();
    }

The above code shows the XML response which sets the custom http header "Result". I'm able to see the new http header in the response header. So far so good.

Now, here's the Json version which internally calls the testService() method to get the result, then use google Gson API to send the result back. This has been working well, till I decided to return the new header. Here's the code snippet.


    @GET
    @Path("/test/jsonp")
    public String testJSONP(
            @QueryParam("p") String var,
            @QueryParam("cb") String callBack
    {
        Response resp = test(var);
        XStream xs = new XStream(new JsonHierarchicalStreamDriver());
        xs.setMode(XStream.NO_REFERENCES);
        xs.alias("TestResponse", TestResponse.class);
        StringBuilder sb = new StringBuilder();
        sb.append(callBack);
        sb.append("(");
        GsonBuilder gb = new GsonBuilder();
        gb.registerTypeAdapter(XMLGregorianCalendar.class, new XMLGregorianCalenderSerializer());
        gb.setPrettyPrinting();
        Gson gson = gb.create();
        sb.append(gson.toJson(resp));
        sb.append(")");
        return sb.toString();
    }

I'm not able to see the http header in Json response.

Any feedback will be highly appreciated.

-Thanks

UPDATE

I added the following code in Json method for my testing.


    @GET
    @Path("/test/jsonp")
    public String testJSONP(
            @QueryParam("p") String var,
            @QueryParam("cb") String callBack
    {
        Response resp = test(var);
        XStream xs = new XStream(new JsonHierarchicalStreamDriver());
        xs.setMode(XStream.NO_REFERENCES);
        xs.alias("TestResponse", TestResponse.class);
        StringBuilder sb = new StringBuilder();
        sb.append(callBack);
        sb.append("(");
        GsonBuilder gb = new GsonBuilder();
        gb.registerTypeAdapter(XMLGregorianCalendar.class, new XMLGregorianCalenderSerializer());
        gb.setPrettyPrinting();
        Gson gson = gb.create();
        sb.append(gson.toJson(resp));
        sb.append(")");
        return Response.ok(sb.toString(), MediaType.APPLICATION_JSON).header("Result", "50").build();
    }

This sets the header value correctly,but the issue is the Json response format seems to have changed. Since this is an existing service, I'm not allowed to do that. Here's the existing response format


null({
  "status": "Completed",
  "totalResult": "252",
  "bin": [
    {
      "type": "source",
      "value": "documentation",
      "ndocs": "243"
    },
    {
      "type": "source",
      "value": "wikihelp",
      "ndocs": "6"
    },    
  "entries": {
    "item": [
      {
        "url": "http://test.com/test.htm",
        "title": "\u003cspan class\u003d\"vivbold qt0\"\u003eXREF\u003c/span\u003e",
        "snippet": "     Test data.",
        "source": "documentation",
        "type": "html",
        "shortDescription": "Starts the TEST command.",
        "category": [
          "User"
        ],
        "publishDate": "2012-02-05T12:00:00-0500",
        "lastUpdateDate": "2012-03-14T12:00:00-0400",
        "topicId": "GUID-7DD70C3C-B8AD-40F1-8A69-5D1EECEAB013"
      }
    ]
  }
})

Here's the response after adding this change


null({
  "status": 200,
  "entity": {
    "status": "Completed",
    "totalResult": "252",
    "bin": [
      {
        "type": "source",
        "value": "documentation",
        "ndocs": "243"
      },
      {
        "type": "source",
        "value": "wikihelp",
        "ndocs": "6"
      }
    ],
    "entries": {
      "item": [
        {
          "url": "http://test.com/test.htm",
          "title": "\u003cspan class\u003d\"vivbold qt0\"\u003eXREF\u003c/span\u003e",
          "snippet": " Test data.",
          "source": "documentation",
          "type": "html",
          "shortDescription": "Starts the TEST command.",
          "category": [
            "User"
          ],
          "publishDate": "2012-02-05T12:00:00-0800",
          "lastUpdateDate": "2012-03-14T12:00:00-0700",
          "topicId": "GUID-7DD70C3C-B8AD-40F1-8A69-5D1EECEAB013"
        }
      ]
    }
  },
  "metadata": {
    "Result": {

    }
  }
})

1 Answer 1

3

You need to change signature of your method, to return an instance of Response class, instead of a String, and then built the response manually.

From the CXF wiki page:

@Path("/example")
public ExampleResource {
    @GET
    public Response getSomething() {
        return Response.ok(/* some entity */).header("CustomHeader", "CustomValue").build();
    }
}

Update

You can also inject HttpServletResponse into your handler using @Context annotation like this:

@Path("/example")
public class Welcome {

    @GET
    public String getSomething(
            @QueryParam("p1") String param1, 
            @QueryParam("p2") String param2, 
            @Context HttpServletResponse response) {

        response.addHeader("CustomHeader", "CustomValue");

        return "my awesome response";
    }
}

Note, that there is a CXF-1498 bug in versions prior to 2.1 that causes HttpServletResponse not being injected, so you need a newer CXF version.

Sign up to request clarification or add additional context in comments.

5 Comments

@npe..Thanks for your response....I did try that using the following code in the Jsonp method .... return Response.ok(sb.toString(), MediaType.APPLICATION_JSON).header("Result", "200").build(); This does set the header without changing the signature, but for some reason, this changes the response format. Since this is an existing service, I'm not allowed to do that.
I've updated the answer with another solution, please check it out.
@npe...thanks a ton, I was not aware that HTTPResponse objects can be passed as a context. It worked great.
+1 The HttpServletResponse as a parameter doesn't seem to work with CXF version 2.7. It throws "2 counts of IllegalAnnotationExceptions". It does work as a field however. Is this answer still valid?
This - especially the updateCustomer method definition - states that the example is still valid. Perhaps it's a bug in 2.7?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.