For several day I trying to figure out what this error means. I getting the error when i try to download file from web service.
The full error is:
java.lang.RuntimeException: org.codehaus.jackson.JsonParseException: Unexpected character ('%' (code 37)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: java.io.StringReader@39494c1; line: 1, column: 2]".
The class that do the job of Serialization and Deserialization from web service:
public class WSClass{
public String authenticationToken;
public enum HTTPMethod {
GET, PUT, POST, DELETE
}
// Constructor.
public WSClass() {
}
/**
* Calls a REST endpoint in the specified URL and returns
* the return value. Optionally deserializes it from JSON.
*
* @param <T> The type of the return value
* @param //strUrl URL relative to the applet root
* @param method HTTP Method used in the request
* @param body Body serialized for the JSON
* @param output The type of the return value
* @return The REST response as an instance of type T
*/
public <T> T doMethod(String strUrl, HTTPMethod method, Object body,
Class<T> output) throws IOException {
return doMethod(strUrl, method, body, output, null);
}
/**
* Calls a REST endpoint in the specified URL and returns
* the return value. Optionally deserializes it from JSON.
*
* @param <T> The type of the return value
* @param //strUrl URL relative to the applet root
* @param method HTTP Method used in the request
* @param body Body serialized for the JSON
* @param output The type of the return value
* @param headers Key-Value list of additional headers.
* @return The REST response as an instance of type T
*/
@SuppressWarnings("unchecked")
public <T> T doMethod(String strUrl, HTTPMethod method, Object body,
Class<T> output, Map<String, String> headers) throws IOException {
// Strip the first '/' away if it exists.
if (strUrl.startsWith("/")) {
strUrl = strUrl.substring(1);
}
// Calculate the real url based on method. IIS supports only the
// GET and POST in default mode so we'll use the _method parameter
// that MFWS understands.
if (method != HTTPMethod.GET && method != HTTPMethod.POST) {
String methodParam;
if (strUrl.contains("?")) {
methodParam = "&_method=";
} else {
methodParam = "?_method=";
}
strUrl += methodParam + method.name();
method = HTTPMethod.POST;
}
// Initialize JSON (de)serializer.
ObjectMapper om = new ObjectMapper();
om.configure(org.codehaus.jackson.map.SerializationConfig.Feature.CAN_OVERRIDE_ACCESS_MODIFIERS, false);
om.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.CAN_OVERRIDE_ACCESS_MODIFIERS, false);
om.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// Get URL to REST interface.
URL u = new URL(strUrl);
// Perform the request.
HttpURLConnection conn = null;
OutputStream os = null;
InputStream is = null;
BufferedReader in = null;
try {
// Open connection.
conn = (HttpURLConnection) u.openConnection();
// Prevent the use of cache.
// The applet does not seem to respect the cache control flags it receives from the server.
// For example it won't necessarily make a new request to the server even if the requested
// resources has expired. See issue: #9234.
conn.setUseCaches(false);
// Set the request properties.
conn.setRequestMethod(method.name());
if (body != null)
conn.setDoOutput(true);
if (!output.equals(void.class))
conn.setDoInput(true);
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("X-Authentication", authenticationToken);
if (headers != null) {
for (Map.Entry<String, String> header : headers.entrySet()) {
System.out.println("Setting header " + header.getKey());
conn.setRequestProperty(header.getKey(), header.getValue());
}
}
// If there is a body, serialize it to the output stream.
if (body != null) {
os = conn.getOutputStream();
om.writeValue(os, body);
} else if (method != HTTPMethod.GET) {
// No body available.
conn.setRequestProperty("Content-Length", "0");
}
// Check if the caller wanted the connection as the return value.
if (output.equals(HttpURLConnection.class)) {
// Change ownership so we don't disconnect the connection in
// finalize block.
HttpURLConnection connDetached = conn;
conn = null;
return (T) connDetached;
}
// Write the output if we had output.
if (os != null) {
os.flush();
os.close();
}
os = null;
// Get response to input stream.
conn.connect();
is = conn.getInputStream();
int contentLength = conn.getContentLength();
if (output.equals(InputStream.class)) {
// If the output type is input stream, just return it
// as it is.
InputStream isReturn = is;
is = null; // Change ownership.
return (T) isReturn;
}
else {
// Deserialize from JSON object.
String response = readStringFromStream(is, contentLength);
// Read the return value from the response.
if (output.equals(void.class) || response.length() == 0)
return null;
else
return om.readValue(response, output);
} // end-if (output.equals(InputStream.class))
} catch (IOException e3) {
throw new RuntimeException(e3);
} finally {
// Close streams.
closeStream(os);
closeStream(is);
closeStream(in);
if (conn != null)
conn.disconnect();
}
}
/**
* Reads an UTF-8 encoded string from the specified stream.
*
* @param is
* @param totalLengthInBytes
* @return
* @throws IOException
*/
private String readStringFromStream(InputStream is, int totalLengthInBytes) throws IOException {
// Return empty string if the requested number of bytes is zero.
if (totalLengthInBytes == 0)
return "";
// It seems that Opera 10 may pass -1 as the total length if the actual Content-Length header
// indicates zero body length.
// Because -1 indicates unspecified content length we attempt to read as much as possible in this case.
if (totalLengthInBytes == -1)
totalLengthInBytes = Integer.MAX_VALUE;
// Read the data from the stream as bytes and pipe it through piped stream
// that converts the byte stream to UTF-8 char stream.
PipedOutputStream poutput = null;
PipedInputStream pinput = null;
StringBuilder result = new StringBuilder();
try {
// Start reading the stream.
boolean continueRead = true;
poutput = new PipedOutputStream();
pinput = new PipedInputStream(poutput);
InputStreamReader r = new InputStreamReader(pinput, "UTF-8");
int bytesReadTotal = 0;
int byteBufferSize = 500; // Buffer size used in the conversion.
CharBuffer cb = CharBuffer.allocate(byteBufferSize);
byte[] buffer = new byte[byteBufferSize];
while (continueRead) {
// Read correct number of bytes from the input stream and write the to the output buffer.
int readByteCount = Math.min(buffer.length, totalLengthInBytes - bytesReadTotal);
int bytesRead = is.read(buffer, 0, readByteCount);
// Convert the bytes to a string.
if (bytesRead > 0) {
// Write to the piped stream.
poutput.write(buffer, 0, bytesRead);
// Read the bytes as string.
cb.clear();
r.read(cb);
int charactersRead = cb.position();
// Collect the string read to the buffer.
cb.rewind();
String currentBatch = cb.subSequence(0, charactersRead).toString();
result.append(currentBatch);
} // end if
// Stop reading if EOF was encountered.
if (bytesRead == -1)
continueRead = false;
else
bytesReadTotal += bytesRead;
// Stop reading the stream after we have read all the available bytes.
if (bytesReadTotal == totalLengthInBytes)
continueRead = false;
} // end while
} finally {
// Close the middleware streams.
closeStream(poutput);
closeStream(pinput);
}
// Return the result.
return result.toString();
}
/**
* Closes the specified stream
*
* @param stream
*/
private static void closeStream(Closeable stream) {
// Try closing only if the stream was specified.
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// Ignore error.
e.printStackTrace();
}
}
}
}
The line the I used to download the file is:
try {
FileOutputStream outputStream = new FileOutputStream(file);
outputStream = WSClass.doMethod(Url, WSClass.HTTPMethod.GET, null,
FileOutputStream.class);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally {
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
}
Someone knows what the problem?
UPDATE: I success to download the file.
I change the function doMethod with @Ganesh Karewad suggested and added another way to write to fileoutputstream.
public <T> T doMethod(String strUrl, HTTPMethod method, Object body,
Class<T> output, File file) throws IOException {
return doMethod(strUrl, method, body, output, null, file);
}
/**
* Calls a REST endpoint in the specified URL and returns
* the return value. Optionally deserializes it from JSON.
*
* @param <T> The type of the return value
* @param //strUrl URL relative to the applet root
* @param method HTTP Method used in the request
* @param body Body serialized for the JSON
* @param output The type of the return value
* @param headers Key-Value list of additional headers.
* @return The REST response as an instance of type T
*/
@SuppressWarnings("unchecked")
public <T> T doMethod(String strUrl, HTTPMethod method, Object body,
Class<T> output, Map<String, String> headers, File file) throws IOException {
// Strip the first '/' away if it exists.
if (strUrl.startsWith("/")) {
strUrl = strUrl.substring(1);
}
// Calculate the real url based on method. IIS supports only the
// GET and POST in default mode so we'll use the _method parameter
// that MFWS understands.
if (method != HTTPMethod.GET && method != HTTPMethod.POST) {
String methodParam;
if (strUrl.contains("?")) {
methodParam = "&_method=";
} else {
methodParam = "?_method=";
}
strUrl += methodParam + method.name();
method = HTTPMethod.POST;
}
// Initialize JSON (de)serializer.
ObjectMapper om = new ObjectMapper();
om.configure(org.codehaus.jackson.map.SerializationConfig.Feature.CAN_OVERRIDE_ACCESS_MODIFIERS, false);
om.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.CAN_OVERRIDE_ACCESS_MODIFIERS, false);
om.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// Get URL to REST interface.
URL u = new URL(strUrl);
// Perform the request.
HttpURLConnection conn = null;
OutputStream os = null;
InputStream is = null;
BufferedReader in = null;
try {
// Open connection.
conn = (HttpURLConnection) u.openConnection();
// Prevent the use of cache.
// The applet does not seem to respect the cache control flags it receives from the server.
// For example it won't necessarily make a new request to the server even if the requested
// resources has expired. See issue: #9234.
conn.setUseCaches(false);
// Set the request properties.
conn.setRequestMethod(method.name());
if (body != null)
conn.setDoOutput(true);
if (!output.equals(void.class))
conn.setDoInput(true);
if(file != null)
{
conn.setRequestProperty("Accept", "application/octet-stream");
}
else
{
conn.setRequestProperty("Accept", "application/json");
}
conn.setRequestProperty("X-Authentication", authenticationToken);
if (headers != null) {
for (Map.Entry<String, String> header : headers.entrySet()) {
System.out.println("Setting header " + header.getKey());
conn.setRequestProperty(header.getKey(), header.getValue());
}
}
// If there is a body, serialize it to the output stream.
if (body != null) {
os = conn.getOutputStream();
om.writeValue(os, body);
} else if (method != HTTPMethod.GET) {
// No body available.
conn.setRequestProperty("Content-Length", "0");
}
// Check if the caller wanted the connection as the return value.
if (output.equals(HttpURLConnection.class)) {
// Change ownership so we don't disconnect the connection in
// finalize block.
HttpURLConnection connDetached = conn;
conn = null;
return (T) connDetached;
}
// Write the output if we had output.
if (os != null) {
os.flush();
os.close();
}
os = null;
// Get response to input stream.
conn.connect();
is = conn.getInputStream();
String response = null;
int contentLength = conn.getContentLength();
if (output.equals(InputStream.class)) {
// If the output type is input stream, just return it
// as it is.
InputStream isReturn = is;
is = null; // Change ownership.
return (T) isReturn;
}
else {
if(file != null)
{
FileOutputStream fileOut = new FileOutputStream(file);
IOUtils.copy(is, fileOut);
return om.readValue("true", output);
}
else
{
// Deserialize from JSON object.
response = readStringFromStream(is, contentLength);
}
// Read the return value from the response.
if (output.equals(void.class) || response.length() == 0)
return null;
else
return om.readValue(response, output);
} // end-if (output.equals(InputStream.class))
} catch (IOException e3) {
throw new RuntimeException(e3);
} finally {
// Close streams.
closeStream(os);
closeStream(is);
closeStream(in);
if (conn != null)
conn.disconnect();
}
}
If i need file: I set to connection as "conn.setRequestProperty("Accept", "application/octet-stream");" and read the input to fileoutputstream.
Thanks,
Tal
you are trying to download file as a json by setting value as
conn.setRequestProperty("Accept", "application/json");
so java is trying to read response as a json and thats why its throwing error now if you dont' know what type of file you will get in response use
conn.setRequestProperty("Accept", "application/octet-stream");
if you know file like its a png file then use
conn.setRequestProperty("Accept", "image/png");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With