Access HttpServletRequest object from Jackson custom deserializer - json

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();

Related

how to map json object having unlimited property to pojo or in #RequestBody variable in controller

I have json object as below
{'key_1':'value_1','key_2':'value_2','key_3':'value_3',.....'key_N':'value_N',}
i tried to map this json with HashMap<String,String>, but it does not worked for me.
if any one have solution to map above json with proper datatype in #RequestBody in spirng controller would be appreciated.
Thanks
As per question, you can not hold many number of json values in the Map object or any other object because it will become heavy object and may cause memory leaks.
You can add required values to Map or any other object and send response to the client.
Note: it should not be a heavy object because it will impact in the real time environment while concurrency.
However you can use below snippet:
#RequestMapping(value = "/someUrl", method = RequestMethod.POST)
public #ResponseBody ResponseEntity<Object> someMethod(final HttpServletRequest req, final HttpSession session) {
ResponseEntity<Object> responseEntity;
Map<String,String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
map.put("key6", "value6");
map.put("key7", "value7");
map.put("key8", "value8");
map.put("key9", "value9");
responseEntity = new ResponseEntity<Object>(map, HttpStatus.OK);
return responseEntity;
}

Intercept JAX-RS web service response to add JSON field

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);
}
}

Spring boot / Jackson deserializes JSON of wrong type

I'm a litte bit lost, I have to admit. I wrote a Spring Boot (1.3M2) application that receives a JSON object which it needs to store in a database:
#RequestMapping(value = "/fav", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<String> setFavorite(#RequestBody List<Favorite> favorites) {
...
internally this method passes the JSON to another method which stores it line by line in a database:
jdbcTemplate.batchUpdate(INSERT_FAVORITE, new BatchPreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
Favorit fav = favorites.get(i);
ps.setString( ...
}
#Override
public int getBatchSize() {
int size = favorites.size();
return size;
}
When I POST a JSON to the controller which does not match the structure of my Favorite-object I only see null values in my database. Obviously Jackson tries its best to convert my JSON into a Java object but fails and sets all values of the object it finds no value for to null.
Then this list of sort of empty objects is written to the database.
I use curl to POST the values
curl -vX POST https://localhost/fav -d #incorrectype.json
This can't be the source of error because it works with a favorite.json. How can I have my controller / Jackson detect if I use a JSON that does not match ?
One solution is to use annotations from javax.validation, and instead of accepting a List in the controller signature, use a custom wrapper along the lines of this (getters/setters omitted):
public class FavoriteList {
#Valid
#NotNull
#Size(min = 1)
private List<Favorite> favorites;
}
then for the Favorite class add the validation as needed, e. g.:
public class Favorite {
#NotNull
private String id;
}
with these changes in place, modify the controller method signature along these lines:
public ResponseEntity<String> setFavorite(#Valid #RequestBody FavoriteList favoritesList) {
This way, input failing validation will throw exceptions before anything in the controller method is executed.

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.

Spring MVC get Jackson JSON as parameter

Hello In frist time I want apologize if my english isn't so good
I want send Multipart request to the server by Apache HttpClient. This request consist from several types of parts. One of these part is JSON. JSON is created by Jackson.
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost httppost = new HttpPost("http://xxx.xxx.xxx.xx:8080/synchronize");
HttpResponse response =null;
CProject project = new CProject();
project.setId(10L);
project.setName("name");
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(project);
MultipartEntity multipart = new MultipartEntity( HttpMultipartMode.BROWSER_COMPATIBLE);
multipart.addPart("project", new StringBody(json,"application/json",Charset.forName("UTF-8")) );
httppost.setEntity(multipart);
response = httpclient.execute(httppost);
Structure of CProject is very simple
public class CProject implements Serializable{
private Integer id;
private String name;
}
And I wand catch this request on server as parameter with anotations #RequestParam or #ModelAttribute but no with #RequestBody because this catch full request - and I need send multiply parameters(Multipart Entity).
Code on server
#RequestMapping (value = "/synchronize", method = RequestMethod.POST)
public #ResponseBody
List<Object> getRequest (#RequestParam CProject project, HttpServletResponse response)
{
return null;
}
Problem is that variable project is created but its atributes are null.
I try several tutorials on net what works with #RequestBody and send request on server and set full header as "application/json". And my application works if I change header of full request as JSON and send them on server, and catch this as #RequestBody on server this work. But I need send json as parameter.
Thanks for any ideas.