Retrieving JSON Object Literal from HttpServletRequest - json

I am writing code that needs to extract an object literal posted to a servlet. I have studied the API for the HttpServletRequest object, but it is not clear to me how to get the JSON object out of the request since it is not posted from a form element on a web page.
Any insight is appreciated.
Thanks.

are you looking for this ?
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
StringBuilder sb = new StringBuilder();
BufferedReader reader = request.getReader();
try {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append('\n');
}
} finally {
reader.close();
}
System.out.println(sb.toString());
}

This is simple method to get request data from HttpServletRequest
using Java 8 Stream API:
String requestData = request.getReader().lines().collect(Collectors.joining());

make use of the jackson JSON processor
ObjectMapper mapper = new ObjectMapper();
Book book = mapper.readValue(request.getInputStream(),Book.class);

The easiest way is to populate your bean would be from a Reader object, this can be done in a single call:
BufferedReader reader = request.getReader();
Gson gson = new Gson();
MyBean myBean = gson.fromJson(reader, MyBean.class);

There is another way to do it, using org.apache.commons.io.IOUtils to extract the String from the request
String jsonString = IOUtils.toString(request.getInputStream());
Then you can do whatever you want, convert it to JSON or other object with Gson, etc.
JSONObject json = new JSONObject(jsonString);
MyObject myObject = new Gson().fromJson(jsonString, MyObject.class);

If you're trying to get data out of the request body, the code above works. But, I think you are having the same problem I was..
If the data in the body is in JSON form, and you want it as a Java object, you'll need to parse it yourself, or use a library like google-gson to handle it for you. You should look at the docs and examples at the project's website to know how to use it. It's fairly simple.

Converting the retreived data from the request object to json object is as below using google-gson
Gson gson = new Gson();
ABCClass c1 = gson.fromJson(data, ABCClass.class);
//ABC class is a class whose strcuture matches to the data variable retrieved

Related

Spring - Return Raw JSON without double serialization

I know there are other posts similar to this, but I haven't found any that help me find a solution for this particular case.
I am trying to return a HashMap<String, Object> from my Controller.
The Object part is a JSON string, but its being double serialized and not returned as a raw JSON string, thus not ending up with extra quotations and escape characters.
Controller function:
#RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public HashMap<String, Object> heartbeat(){
String streamInfo = service.getStreamInfo();
String streamCursorInfo = service.getStreamCursorInfo();
String topicInfo = service.getTopicInfo();
String greeting = "This is a sample app for using Spring Boot with MapR Streams.";
HashMap<String, Object> results = new HashMap();
results.put("greeting", greeting);
results.put("streamInfo", streamInfo);
results.put("streamCursorInfo", streamCursorInfo);
results.put("topicInfo", topicInfo);
return results;
}
Service function:
private String performCURL(String[] command){
StringBuilder stringBuilder = new StringBuilder();
try{
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process p = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while((line = reader.readLine()) != null){
stringBuilder.append(line);
}
}
catch(Exception e){
LOGGER.error(ExceptionUtils.getRootCauseMessage(e));
}
return stringBuilder.toString();
}
The cURL command I run already returns a raw JSON string. So im just trying to add it to the HashMap to be returned in the heartbeat response.
But every time I run this, my output looks like:
{
"greeting": "This is a sample app for using Spring Boot with MapR Streams.",
"streamCursorInfo": "{\"timestamp\":1538676344564,\"timeofday\":\"2018-10-04 02:05:44.564 GMT-0400 PM\",\"status\":\"OK\",\"total\":1,\"data\":[{\"consumergroup\":\"MapRDBConsumerGroup\",\"topic\":\"weightTags\",\"partitionid\":\"0\",\"produceroffset\":\"44707\",\"committedoffset\":\"10001\",\"producertimestamp\":\"2018-10-03T05:57:27.128-0400 PM\",\"consumertimestamp\":\"2018-09-21T12:35:51.654-0400 PM\",\"consumerlagmillis\":\"1056095474\"}]}",
...
}
If i return only the single string, such as streamInfo then it works fine and doesnt add the extra quotes and escape chars.
Can anyone explain what im missing or need to do to prevent this double serialization?
Instead of returning a HashMap, create an object like this:
public class HeartbeatResult {
private String greeting;
... //other fields here
#JsonRawValue
private String streamCursorInfo;
... //getters and setters here (or make the object immutable by having just a constructor and getters)
}
With #JsonRawValue Jackson will serialize the string as is. See https://www.baeldung.com/jackson-annotations for more info.
streamCursorInfo is a string, not an object => the serialization will escape the " character.
If you are able to return the object containing the data, it will work out of the box. If what you have is just a String, I suggest to serialize it to JsonNode and add it in your response
ObjectMapper objectMapper = new ObjectMapper();
JsonNode streamCursorInfo = objectMapper.readTree(service.getStreamInfo())
results.put("streamCursorInfo", streamCursorInfo);

How to set JSONArray in model attribute in spring modelandview controller?

I want to add JSONArray in spring's model attribute and return from ModelAndView Controller. Not able to do like below. Request for help. Thanking you!
#RequestMapping(value = "/sample.htm", method = RequestMethod.GET)
public ModelAndView seatRequest( ModelMap model,
HttpServletRequest request,HttpServletResponse response, HttpSession session) throws JSONException, JsonProcessingException {
JSONArray jsonArray = new JSONArray();
JSONObject jsonObject = new JSONObject();
jsonObject.put("0", "val0");
jsonObject.put("1", "val1");
jsonObject.put("2", "val2");
jsonArray.put(jsonObject);
model.addAttribute("jsonData",jsonArray.toString());
return new ModelAndView("sample");
What is your intention? Currently JsonArray is added in String form.You can access this jsonArray as a String in your view. But I think you don't want to do that. If you want to access it as object just add as model.addAttribute("jsonData",jsonArray) and then you can access it as object in your views.
Also, In your json Object, Key value is Numric "0","1" so on. make it alphanumeric i.e "key1", "key2" etc. and values "val1","val2" etc. Because name of identifiers cannot start with numbers.

Tomcat servlet acting strange with json object

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("application/json");
PrintWriter out = response.getWriter();
Gson gson = new Gson();
LocationTypes locTypes = new LocationTypes();
String json = gson.toJson(locTypes);
out.print(json);
out.flush();
}
If i take the above code, and System.out.println(json), it looks like this :
{"locationTypes":["Hospital","Church","Restaurant","Bar","Other"]}
What i get in the browser, when pointing to the url for the servlet, i get this:
{"calls":{"threadLocalHashCode":-2084311414},"typeTokenCache":{"com.google.gson.InstanceCreator\u003c?\u003e":{},"int":{},"java.lang.String":{},"java.lang.String[]":{},"java.util.Map\u003ccom.google.gson.reflect.TypeToken\u003c?\u003e, com.google.gson.TypeAdapter\u003c?\u003e\u003e":{},"java.util.List\u003ccom.google.gson.TypeAdapterFactory\u003e":{},"java.lang.ThreadLocal\u003cjava.util.Map\u003ccom.google.gson.reflect.TypeToken\u003c?\u003e, com.google.gson.Gson$FutureTypeAdapter\u003c?\u003e\u003e\u003e":{},"com.google.gson.TypeAdapterFactory":{},"com.google.gson.JsonDeserializationContext":{},"com.google.gson.reflect.TypeToken\u003c?\u003e":{},"java.util.Map\u003cjava.lang.reflect.Type, com.google.gson.InstanceCreator\u003c?\u003e\u003e":{},"com.google.gson.Gson":{},"boolean":{},"java.lang.reflect.Type":{},"data.LocationTypes":{},"java.lang.Class\u003c? super ?\u003e":{},"java.lang.Integer":{},"com.google.gson.internal.ConstructorConstructor":{},"com.google.gson.TypeAdapter\u003c?\u003e":{},"com.google.gson.JsonSerializationContext":{}},"factories":[null,null,{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]},null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,{"constructorConstructor":{"instanceCreators":{}}},{"constructorConstructor":{"instanceCreators":{}},"complexMapKeySerialization":false},{"constructorConstructor":{"instanceCreators":{}},"fieldNamingPolicy":"IDENTITY","excluder":{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]}}],"constructorConstructor":{"instanceCreators":{}},"serializeNulls":false,"htmlSafe":true,"generateNonExecutableJson":false,"prettyPrinting":false}
Update
I have reproduced your error.
Unfortunately, you are passing the gson object to be converted to JSON.
Your problem is the result of a typo/mistake.
I ran the following code:
public static void main (String args[])
{
Gson gson = new Gson();
String json = gson.toJson(gson);
System.out.println(json);
}
And received the following:
{"calls":{"threadLocalHashCode":1253254570},"typeTokenCache":{"com.google.gson.Gson":{},"com.google.gson.reflect.TypeToken\u003c?\u003e":{},"com.google.gson.internal.ConstructorConstructor":{},"com.google.gson.InstanceCreator\u003c?\u003e":{},"java.lang.reflect.Type":{},"boolean":{},"int":{},"com.google.gson.JsonDeserializationContext":{},"com.google.gson.JsonSerializationContext":{},"java.lang.ThreadLocal\u003cjava.util.Map\u003ccom.google.gson.reflect.TypeToken\u003c?\u003e, com.google.gson.Gson$FutureTypeAdapter\u003c?\u003e\u003e\u003e":{},"java.util.List\u003ccom.google.gson.TypeAdapterFactory\u003e":{},"java.util.Map\u003cjava.lang.reflect.Type, com.google.gson.InstanceCreator\u003c?\u003e\u003e":{},"com.google.gson.TypeAdapter\u003c?\u003e":{},"java.lang.Integer":{},"com.google.gson.TypeAdapterFactory":{},"java.lang.Class\u003c? super ?\u003e":{},"java.util.Map\u003ccom.google.gson.reflect.TypeToken\u003c?\u003e, com.google.gson.TypeAdapter\u003c?\u003e\u003e":{}},"factories":[null,null,{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]},null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,{"constructorConstructor":{"instanceCreators":{}}},{"constructorConstructor":{"instanceCreators":{}},"complexMapKeySerialization":false},{"constructorConstructor":{"instanceCreators":{}},"fieldNamingPolicy":"IDENTITY","excluder":{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]}}],"constructorConstructor":{"instanceCreators":{}},"serializeNulls":false,"htmlSafe":true,"generateNonExecutableJson":false,"prettyPrinting":false}
Kudos to Pragmateek for also checking the GSON SVN repo.
Original Answer
It's really quite impossible that System.out.println(json); would give you a different result than
out.print(json);
out.flush();
json is a String and dispays the same in any stream.
Have you checked that you don't have a typo somewhere?
I would suggest you copy and paste the code exactly as is within your project.
In the browser, you are getting a JSON version of an object that has serialized all the object's values/fields to JSON.
Many of the keys within your generated JSON are actual fields of the object your trying to serialize to JSON as Pragmateek has said.
It could almost be suspected that your are passing your GSON object to be converted to JSON....
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("application/json");
PrintWriter out = response.getWriter();
Gson gson = new Gson();
LocationTypes locTypes = new LocationTypes();
String json = gson.toJson(locTypes);
response.setContentType("application/json");
out.print(json);
out.flush();
}
try setting content-type as above
Is this the original code?
Are you sure there isn't a typo like:
out.print(gson);
Because the strange JSON really looks like a serialized GSON library object...

How does play.libs.Json.fromJson handled a List<T> in Java?

I'd like to use the Json library that comes with the play 2.1 framework.
But I'm stuck with deserializing a json object back into a java List.
With gson, you can write s.th. like
Type type = new TypeToken<List<XYZ>>(){}.getType();
List<XYZ> xyzList = gson.fromJson(jsonXyz, type);
Is there a way to do the same with play.libs.Json.fromJson ?
Any help appreciated.
Edit (17.12.2013):
I did the following to work around the problem. I guess there is a better way, but I didn't found it.
List<MyObject> response = new ArrayList<MyObject>();
Promise<WS.Response> result = WS.url(Configuration.getRestPrefix() + "myObjects").get();
WS.Response res = result.get();
JsonNode json = res.asJson();
if (json != null) {
for (JsonNode jsonNode : json) {
if (jsonNode.isArray()) {
for (JsonNode jsonNodeInner : jsonNode) {
MyObject mobj = Json.fromJson(jsonNodeInner, MyObject.class);
response.add(bst);
}
} else {
MyObject mobj = Json.fromJson(jsonNode, MyObject.class);
response.add(bst);
}
}
}
return response;
The Json library for Play Java is really just a thin wrapper over the Jackson JSON library (http://jackson.codehaus.org/). The Jackson way to deserialize a list of custom objects is mentioned here.
For your case, once you parse the json from the response body, you would do something like this, assuming MyObject is a plain POJO:
JsonNode json = res.asJson();
try{
List<MyObject> objects = new ObjectMapper().readValue(json, new TypeReference<List<MyObject>>(){});
}catch(Exception e){
//handle exception
}
I'm assuming you were asking about Play Java based on your edit, Play Scala's JSON library is also based on Jackson but has more features and syntactic sugar to accommodate functional programming patterns.
You can use the following code:
List<YourClass> returnedRoles = new ObjectMapper().readValue(jsonString
,TypeFactory.defaultInstance().constructCollectionType(List.class,
YourClass.class));

How to let jackson generate json string using single quote or no quotes?

For example, I want to generate a json string for ng-style:
<th ng-style="{width:247}" data-field="code">Code</th>
But with jackson, the result is:
<th ng-style="{"width":247}" data-field="code">Code</th>
It's not easy to read.
So I want jackson to generate the json string with single quote or no quotes. Is it possible to do this?
If you have control over the ObjectMapper instance, then configure it to handle and generate JSON the way you want:
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
JsonGenerator.Feature.QUOTE_FIELD_NAMES
is deprecated, you can use this instead:
mapper.configure(JsonWriteFeature.QUOTE_FIELD_NAMES.mappedFeature(), false);
mapper.configure(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES.mappedFeature(), true);
Note that JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES is not deprecated (as of now), the corresponding JsonReadFeature is mentioned here just for completeness.
The simplest and the best option is to use regular expression and update the string value.
The sample code is as listed below.
partNumberList=partNumberList.replaceAll(":", ":\"").replaceAll("}", "\"}");
The complete code is as shown below
public static void main(String[] args) throws JsonParseException, JsonMappingException,
IOException {
TestJack obj = new TestJack();
//var jsonString ='{"it":"Stati Uniti d'America"}';
// jsonString =jsonString.replace("'", "\\\\u0027")
ObjectMapper mapper = new ObjectMapper();
String partNumberList = "[{productId:AS101R}, {productId:09902007}, {productId:09902002}, {productId:09902005}]";
partNumberList = partNumberList.replaceAll(":", ":\"").replaceAll("}", "\"}");
System.out.println(partNumberList);
mapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
List<ProductDto> jsonToPersonList = null;
jsonToPersonList = mapper.readValue(partNumberList, new TypeReference<List<ProductDto>>() {
});
System.out.println(jsonToPersonList);
}