Intercept JAX-RS web service response to add JSON field - json

I have a JAX-RS web service that returns a Response object as shown below (it is running in WebLogic 12.2.1). It will return a JSON response to the client. Is it possible to write an interceptor or filter, such that when the web service call is returned, it will add an extra field in the JSON response?
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("LogIn")
public Response logIn(#Context HttpServletRequest request, Parameters requestParameters) {...}
Thanks in advance.

If using Jersey, then you can try implementing ContainerResponseFilter.
On Over-riding filter(), it provides ContainerResponseContext object which gives you access to the response that is being sent using getEntity() method.
You can modify this object and set it back in the response.
public class ResponseInterceptor implements ContainerResponseFilter{
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
Object obj = responseContext.getEntity();
// Modify the Response obj as per need
responseContext.setEntity(obj);
}
}

Related

Is it possible to configure OAuth2 in Spring Boot to respond with JSON instead of HTML for InvalidTokenException?

My Spring Boot application uses OAuth2 for security and token management. I’m querying one of my REST endpoints with an invalid token to test its response using Postman. The endpoint is correctly responding with 401 InvalidTokenException but the response content is HTML when I would like it to respond with JSON. Can this be done via code?
Example response
<InvalidTokenException>
<error>invalid_token</error>
<error_description>Access token expired: … my token… </error_description>
</InvalidTokenException>
To elaborate on zfChaos's answer, which is a good lead but does not provide sufficient information for the response to be a JSON response:
You should also set the content type and character encoding.
Then, write your JSON response (in this example I used a simple String, of course it would be more convenient use a class and an ObjectMapper).
Here is a complete example:
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.oauth2Login(login -> login
.failureHandler((request, response, exception) -> {
response.setContentType("application/json");
response.setStatus(401);
response.setCharacterEncoding("UTF-8");
response.getWriter().write("{ \"msg\": \"foo\" }");
})
);
}
}
Add custom AuthenticationFailureHandler to your security configuration and then prepare response in your custom implementation:
http.oauth2Login()
.failureHandler(customFailureHandler)
Failure handler example:
public class CustomFailureHandler extends SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
response.sendError(401, "XML HERE");
}
}

restful web service response with json

I have restful web service which return list of users, i want to make response as json format but that produce the following exception:
SEVERE: Servlet.service() for servlet [RESTful] in context with path [/spring] threw exception
org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.json.JSONObject and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) )
my restful method:
#GET
#Path("all")
#Produces(MediaType.APPLICATION_JSON)
public Response getUsers(){
UserService service = new UserService();
List<UserBean> userBeans = service.getUsers();
JSONObject users = new JSONObject();
if(userBeans != null)
{
for(UserBean user : userBeans)
{
users.put("name",user.getUsername());
}
System.out.println(users);
return Response.status(200).entity(users).build();
}
return Response.status(201).entity("faild").build();
}
To produce JSON with Jersey, you don't need to use the org.json.JSONObject class.
Ensure you have a JSON provider configured (refer to this answer for more details) and change your resource method to be as following:
#GET
#Path("all")
#Produces(MediaType.APPLICATION_JSON)
public Response getUsers() {
UserService service = new UserService();
List<UserBean> users = service.getUsers();
return Response.ok(users).build();
}

How to send JSON in Spring?

I tried to find how I can write in Spring to POST JSON from REST client. For example, I wrote:
#RequestMapping(value = "/{userId}/add", method = RequestMethod.POST, headers = {"content-type=application/json"})
#ResponseBody
public Map<String, String> saveUser(#RequestBody User user, BindingResult result) {
Map<String, String> jsonResponse = new HashMap<String, String>();
if (result.hasErrors()) {
jsonResponse.put("Message", "Can't add the user");
jsonResponse.put("Code", "401");
return jsonResponse;
}
userService.addUser(user);
jsonResponse.put("Message", "Success add User");
jsonResponse.put("Code", "200");
return jsonResponse;
}
End tested it from Firefox REST client. But I saw 404 error. What am I doing wrong? Thanx for help.
First, if the URI of your request ended with "/user/2/add", it won't map to your method, which is mapped as "/{userId}/add". This will cause the HTTP 404 error you receive. Instead, your URI should end with "/2/add", if the "userId" is 2.
Second, annotating the User parameter with #RequestBody is not enough for the complex User type. You will need to convert your JSON request body into a User object. You can accomplish this with the MappingJacksonHttpMessageConverter. By declaring a bean of this type, you can use Jackson's annotations to control how the JSON is parsed into the User properties.

The request sent by the client was syntactically incorrect ().+Spring , RESTClient

I am working with Spring MVC using JSON objects. while I am tring to send JSON Object from RESTClient, I am getting
HTTP Status 400 - The request sent by the client was syntactically incorrect ().
This is my controller
ObjectMapper mapper=new ObjectMapper();
#RequestMapping(value = "/addTask", method = RequestMethod.GET)
public ModelAndView addTask(#RequestParam("json") String json) throws JsonParseException, JsonMappingException, IOException
{
System.out.println("Json object from REST : "+json);
Task task=(Task) mapper.readValue(json, Task);
service.addService(task);
return new ModelAndView("Result");
}
My request URL : http://localhost:8080/Prime/addTask
My Json Object :
{"taskName":"nothing","taskId":1234,"taskDesc":"nothing doing"}
Also i tried specifying "Content-Type: application/json" in RESTClient but still am getting the same error
I ran into a similar situation using a JSON string in the request body recently, and using a very similar Spring setup as yours. In my case I wasn't specifying a String parameter and deserialising it myself though, I was letting Spring do that:
#RequestMapping(value = "/myService/{id}", method = RequestMethod.POST)
#ResponseBody
public void myService(#PathVariable(value = "id") Long id, #RequestBody MyJsonValueObject request) {
..
}
I was getting an HTTP error 400 "The request sent by the client was syntactically incorrect" response. Until I realised that there wasn't a default constructor on the #RequestBody MyJsonValueObject so there were problems deserialising it. That problem presented in this way though.
So if you are using POST and objects, and getting errors like this, make sure you have a default constructor! Add some JUnit to be sure you can deserialise that object.
Note: I'm not saying this is the only reason you get this error. The original case used just String (which does have a default constructor !) so it's a little different. But in both cases it appears the request URI appears to have been mapped to the right method, and something has gone wrong trying to extract parameters from the HTTP request.
Try this
Change
#RequestParam("json") String json
To
#RequestBody Task task
If you are not interested in POST method you can try this
change your Controller method from
#RequestMapping(value = "/addTask", method = RequestMethod.GET)
public ModelAndView addTask(#RequestParam("json") String json)
to
#RequestMapping(value = "/addTask/{taskName}/{taskId}/{taskDesc}", method = RequestMethod.GET)
public ModelAndView addTask(#RequestParam("taskName") String taskName,
#RequestParam("taskId") String taskId,#RequestParam("taskDesc") String taskDesc)
and change your URL to
http://localhost:8080/Prime/addTask/mytask/233/testDesc
My problem was due to the incorrect mapping of the #RequestBody object.
My Request Body looks like this
{data: ["1","2","3"]}
I had the following code in my controller
#RequestMapping(value = "/mentee", method = RequestMethod.POST)
public #ResponseBody boolean updateData(#RequestBody List<Integer> objDTO, HttpSession session) {
...
}
This give me HTTP 400 because Spring doesn't know how to bind my Json data to a List.
I changed the RequestBody object to the following
#RequestMapping(value = "/mentee", method = RequestMethod.POST)
public #ResponseBody boolean updateData(#RequestBody ObjectiveDto objDTO, HttpSession session) {
...
}
and defined ObjectiveDto as followed
#ToString
public class ObjectiveDto {
#Getter #Setter
private List<Integer> data;
}
This resolved the HTTP 400 error.

Access HttpServletRequest object from Jackson custom deserializer

I am trying to send an object via an ajax POST using JSON payload; this object has references to other objects stored in a database, handled by Hibernate; I need to access this database to resolve other objects references and store them in the new object obtained deserializing JSON payload of request.
Now, I have to access HttpServletRequest attribute in order to get a saved hibernate session to use to access to database. Is it possible?
The controller that handle the request is the following:
#RequestMapping(value = "/newproduct", method = RequestMethod.POST)
public #ResponseBody
Integer newProduct(HttpServletRequest request, #RequestBody Product product)
{
//Controller code here
}
The deserializer where I have to be able to get request attribute "hibernate_session" is a custom deserializer, registered to Jackson and is the following:
public class ProductDeserializer extends JsonDeserializer<Product>
{
#Override
public Product deserialize(JsonParser jpar, DeserializationContext arg1)
throws IOException, JsonProcessingException
{
Product newProduct = new Product();
// I want to get request attribute or open a new hibernate session here
return newProduct;
}
}
If necessary I'll post more code if needed.
Thanks
You may try following approach
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();