JSON Exceptionorg.json.JSONException: Unterminated string at character - json

Im unable to get complete JSON string, it doesn't show last three character if the string. Here is JSON String
{"status":"success","data":"Screenshot_2016-07-24-13-06-4120160726082711.pn
JSON request
StringRequest stringRequest = new StringRequest(Request.Method.POST,
url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
Utils.psLog("Server RESPONSE >> " + response);
JSONObject obj = new JSONObject(response);
}
catch {
}
Error log
07-26 13:57:11.556 8632-8632/com.directory D/TEAMPS: Server RESPONSE >>
{"status":"success","data":"Screenshot_2016-07-24-13-06-4120160726082711.pn
07-26 13:57:11.557 8632-8632/com.directory D/TEAMPS: JSON Exceptionorg.json.JSONException: Unterminated string at character 78 of
{"status":"success","data":"Screenshot_2016-07-24-13-06-4120160726082711.pn

You are getting that error because the JSON Object appears to be incomplete (according do your code snippet).
If the string composing the JSON is incomplete, it will cause a JSON Parsing Exception
{"status":"success","data":"Screenshot_2016-07-24-13-06-4120160726082711.pn
Should instead be :
{"status":"success","data":"Screenshot_2016-07-24-13-06-4120160726082711.png"}

Related

How to properly send Mono<ResponseEntity> as JSON in Netty Reactor HTTP Server response

I am trying to figure out how to properly send response with ResponseEntity as JSON from Netty Reactor HTTP Server.
My current implementation reacts on request from WebClient and should send back response with some ResponseEntity status (let's assume just HTTP OK).
Unfortunately I'm still getting InvalidDefinitionException on the client side saying that it not possible to construct instance due to no default constructor.
I know what it means but for example Spring Webflux can have return type of rest endpoint Mono as well and no issues on client side will appear.
So is it somehow possible to properly serialize entity as JSON on server side and deserialize it at the client side?
This is my client
import org.springframework.web.reactive.function.client.WebClient;
public Mono<ResponseEntity> postRequest(final Object body, final String uri) {
return webClient.post()
.uri(uri)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(body))
.exchange()
.flatMap(clientResponse -> clientResponse.toEntity(ResponseEntity.class));
}
This is my Server
public void runWithPost(final String endpointPath, final ServerCallback callback) {
server = HttpServer.create()
.host(this.host)
.port(this.port)
.route(routes ->
routes.post(endpointPath, (request, response) ->
response.addHeader(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.sendString(Mono.just(getJSON(callback.handleCallback())))))
.wiretap(true)
.bindNow();
System.out.println("Starting server...");
}
private String getJSON(final ResponseEntity responseEntity) {
String json = StringUtils.EMPTY;
try {
json = objectMapper.writeValueAsString(responseEntity);
System.out.println("Serialized JSON: " + json);
} catch (final JsonProcessingException ex) {
System.err.println("JSON serializer error: " + ex.getMessage());
}
return json;
}
This is callback
public interface ServerCallback {
ResponseEntity handleCallback();
}
and usage
reactiveRestServer.runWithPost("/transaction", () -> ResponseEntity.ok().build());
Unfortunately on the client side I do not get HTTP status OK but deserialization exception:
2020-04-28 16:09:35.345 ERROR 15136 --- [ctor-http-nio-2] c.a.t.t.inbound.ArpMessageServiceImpl : Type definition error: [simple type, class org.springframework.http.ResponseEntity]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.http.ResponseEntity` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 2]
2020-04-28 16:09:35.349 WARN 15136 --- [ctor-http-nio-2] io.netty.util.ReferenceCountUtil : Failed to release a message: DefaultLastHttpContent(data: PooledSlicedByteBuf(freed), decoderResult: success)
io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
at io.netty.util.internal.ReferenceCountUpdater.toLiveRealRefCnt(ReferenceCountUpdater.java:74) ~[netty-common-4.1.45.Final.jar:4.1.45.Final]
What I am missing?
So I finally resolved that issue. For those who would be solving similar issue here is the answer.
The problem is that Spring Webflux converts ResponseEntity into DefaultFullHttpResponse, so that DefaultFullHttpResponse contains headers, status and also body. I resolved that issue by doing exactly the same approach.
public void runWithPost(final String endpointPath, final ServerCallback callback) {
if (server == null || server.isDisposed()) {
server = HttpServer.create()
.host(this.host)
.port(this.port)
.route(routes ->
routes.post(endpointPath, (request, response) -> processResponse(response, callback)))
.wiretap(true)
.bindNow();
logger.info("Starting server...");
} else {
logger.info("Couldn't start server because one is already running!");
}
}
and conversion is here
private NettyOutbound processResponse(final HttpServerResponse response, final ServerCallback callback) {
final ResponseEntity responseEntity = callback.handleCallback();
// set status
response.status(responseEntity.getStatusCodeValue());
// set headers
final HttpHeaders entityHeaders = responseEntity.getHeaders();
if (!entityHeaders.isEmpty()) {
entityHeaders.entrySet().stream()
.forEach(entry -> response.addHeader(entry.getKey(), buildValue(entry.getValue())));
}
if (responseEntity.hasBody()) {
try {
final Object body = responseEntity.getBody();
if (body instanceof String) {
return response.sendString(Mono.just((String) body));
} else {
return response.send(Mono.just(Unpooled.wrappedBuffer(getBytesFromObject(body))));
}
} catch (final IOException ex) {
response.status(HttpResponseStatus.INTERNAL_SERVER_ERROR);
return response.sendString(Mono.just(ex.getMessage()));
}
}
// set body
return response.send(Mono.empty());
}
Usage is as follows:
mockReactiveRestServer.runWithPost("/transaction", () -> ResponseEntity.ok().build());

Return a string (for success or exception details) with PostJsonAsync - .NET Core REST API

I want my REST API to return a string with the exception details to the client. My client-side code is:
public async Task CreateUnit(UnitEntity unit)
{
try
{
var response = await _http.PostJsonAsync<HttpResponseMessage>("api/units", unit);
}
catch(Exception e)
{
//todo want to display error from the service and carry on
//throw;
}
}
And the code for the service / API is:
[HttpPost]
public HttpResponseMessage CreateUnit(UnitEntity unit)
{
try
{
Dal.CreateUnit(unit);
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.Created;
response.Content = new StringContent($"The unit {unit.UnitName} was created successfully");
return response;
}
catch(Exception e)
{
//todo send error message in Http response if possible
//throw;
return new HttpResponseMessage() {StatusCode = HttpStatusCode.NotAcceptable, Content = new StringContent(e.Message)};
}
}
I've tried just returning a string and it basically says that the JSON serialiser can't deserialise it (because it's already a raw string and not JSON). The code above throws an exception:
Deserialization of reference types without parameterless constructor is not supported. Type 'System.Net.Http.HttpContent'

how to parse JSON file using rest API and spring boot

I'm new to this, and I want to read JSON file imported with rest api and parse it with spring boot.
I worked with CSV file with his method :
#RequestMapping(value = "/import", method = RequestMethod.POST)
public String handleFileUpload(#RequestParam("file") MultipartFile multipartFile) throws IOException {
String name = multipartFile.getOriginalFilename();
System.out.println("File name: "+name);
byte[] bytes = multipartFile.getBytes();
System.out.println("File uploaded content:\n" + new String(bytes));
return "file uploaded";
}
Now i want to parse a JSON File :
[
{
"name":"John",
"city":"Berlin",
"cars":[
"audi",
"bmw"
],
"job":"Teacher"
},
{
"name":"Mark",
"city":"Oslo",
"cars":[
"VW",
"Toyata"
],
"job":"Doctor"
}
]
I have try it to parse this file with java and it works for me but I dont know how to get it with rest api
This method to parse te file JSON and it works
public static void main(String[] args) throws FileNotFoundException,
IOException, ParseException {
JSONParser parser = new JSONParser();
JSONArray jsonArray = (JSONArray) parser.parse(new FileReader(
"D:/PFE 2018/testjsonfile.json"));
for (Object o : jsonArray) {
JSONObject person = (JSONObject) o;
String strName = (String) person.get("name");
System.out.println("Name::::" + strName);
String strCity = (String) person.get("city");
System.out.println("City::::" + strCity);
JSONArray arrays = (JSONArray) person.get("cars");
for (Object object : arrays) {
System.out.println("cars::::" + object);
}
String strJob = (String) person.get("job");
System.out.println("Job::::" + strJob);
System.out.println();
}
}
now how to reuse this methode with rest api
It depends what you want to do with your JSON (it's not entirely clear in your question).
In general, good practice with Spring Boot is to use Jackson either:
binding your JSON with a POJO if you expect your JSON to have a known format or
mapping your JSON in a tree.
Examples for the described behaviours can be found in this article for instance.

java restful web services retrieving post data

I am getting a JSON object POST request from android volley.I am trying to read the json using the following code.
#POST
#Path("/driver/insertTripLog")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_PLAIN)
public String insertTripLog(InputStream incomingData) throws Exception
{
StringBuilder sb = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new InputStreamReader(incomingData));
String line = null;
while ((line = in.readLine()) != null) {
sb.append(line);
}
} catch (Exception e) {
System.out.println("Error Parsing: - ");
}
String data=sb.toString();
System.out.println("Data Received: " +data );
return data;
}
The output i am getting json object but the special characters are encoded with %XX format.
Sample Output:
json=%5B%7B%22name%22%3A%22value%22%7D%5D
how to read properly post json data sent from volley.
Use the URLDecoder class to handle the percent encoded content which you are seeing:
String data = sb.toString();
data = java.net.URLDecoder.decode(data, "UTF-8");
Output:
json=[{"name":"value"}]

org.codehaus.jackson.JsonParseException: Invalid UTF-8 middle byte 0xdf

I'm using the jackson framework for marshaling and unmarshalling data between JSON and Java. Everything works well, as long the input doesn't contain any characters like:
ö
ä
ü
Ö
Ä
Ü
ß
For input data I tried:
String jsonData = "{\"id\":1,\"street\":\"Straße\",\"number\":\"1c\",\"zipCode\":1111,\"city\":\"MyCity\"}";
as well as:
String jsonData = "{\"id\":1,\"street\":\"Stra\u00DFe\",\"number\":\"1c\",\"zipCode\":1111,\"city\":\"MyCity\"}";
and all the time I get the same exception.
The mapping from json data to java entity object is done via:
/*
* Convert stream to data entity
*/
ObjectMapper m = new ObjectMapper();
T entity = (T) m.readValue(stringToStream(jsonData), readableClass);
I also perform a json data validation which works like expected, also with the above chars.
How should such data be handled?
UPDATE
These are the important parts of the MessageBodyReader class
#Override
public T readFrom(Class<T> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
final String jsonData = getStringFromInputStream(entityStream);
System.out.println(jsonData);
InputStream isSchema = new FileInputStream(jsonSchemaFile);
String jsonSchema = getStringFromInputStream(isSchema);
/*
* Perform JSON data validation against schema
*/
validateJsonData(jsonSchema, jsonData);
/*
* Convert stream to data entity
*/
ObjectMapper m = new ObjectMapper();
T entity = (T) m.readValue(stringToStream(jsonData), readableClass);
return entity;
}
/**
* Validate the given JSON data against the given JSON schema
*
* #param jsonSchema
* as String
* #param jsonData
* as String
* #throws MessageBodyReaderValidationException
* in case of an error during validation process
*/
private void validateJsonData(final String jsonSchema, final String jsonData)
throws MessageBodyReaderValidationException {
try {
final JsonNode d = JsonLoader.fromString(jsonData);
final JsonNode s = JsonLoader.fromString(jsonSchema);
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
JsonValidator v = factory.getValidator();
ProcessingReport report = v.validate(s, d);
System.out.println(report);
if (!report.toString().contains("success")) {
throw new MessageBodyReaderValidationException(
report.toString());
}
} catch (IOException e) {
throw new MessageBodyReaderValidationException(
"Failed to validate json data", e);
} catch (ProcessingException e) {
throw new MessageBodyReaderValidationException(
"Failed to validate json data", e);
}
}
/**
* Taken from <a href=
* "http://www.mkyong.com/java/how-to-convert-inputstream-to-string-in-java/"
* >www.mkyong.com</a>
*
* #param is
* {#link InputStream}
* #return Stream content as String
*/
private String getStringFromInputStream(InputStream is) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try {
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
private InputStream stringToStream(final String str) {
return new ByteArrayInputStream(str.getBytes());
}
JSON specification states, that only valid encodings are UTF-8, UTF-16 and UTF-32. No other encodings (like Latin-1) can be used. Your stringToStream implementation is not setting the encoding explicitly, so system default is used. That is how you got non-utf stream. On the next step Jakson is trying to parse the stream using one of UTF encodings (it has detection algorithm built in) and fails. Try setting an explicit encoding:
new ByteArrayInputStream(str.getBytes("UTF-8"));
You already got an answer, but one obvious question here is this: why are you converting from a String to a stream? That is unnecessary and wasteful thing to do -- so just pass the String as-is. This will also remove the problem; Strings do not have encoding per se (that is: there is just a single in-memory representation and no conversions are needed).