Java 意外字符(';%';(代码37)):应为有效值(数字、字符串、数组、对象、';true';、';false';或';null';)

Java 意外字符(';%';(代码37)):应为有效值(数字、字符串、数组、对象、';true';、';false';或';null';),java,android,web-services,Java,Android,Web Services,我花了几天的时间试图弄明白这个错误的含义。 我尝试从web服务下载文件时遇到错误 完全错误是: 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: j

我花了几天的时间试图弄明白这个错误的含义。 我尝试从web服务下载文件时遇到错误

完全错误是:

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]".
从web服务执行序列化和反序列化操作的类:

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();
        }
    }
 }
}
有人知道问题出在哪里

更新:我下载文件成功

我用@Ganesh Karewad建议的方法更改了函数doMethod,并添加了另一种写入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();
    }
}
public T doMethod(字符串结构、HTTPMethod方法、对象体、,
类输出,文件)引发IOException{
返回doMethod(strUrl,method,body,output,null,file);
}
/**
*调用指定URL中的REST端点并返回
*返回值。可选地从JSON反序列化它。
*
*@param返回值的类型
*@param//strUrl相对于小程序根的URL
*@param method请求中使用的HTTP方法
*@param body已为JSON序列化
*@param输出返回值的类型
*@param headers附加头的键值列表。
*@将REST响应作为类型T的实例返回
*/
@抑制警告(“未选中”)
公共T方法(字符串结构、HTTPMethod方法、对象体、,
类输出、映射头、文件)引发IOException{
//如果第一个“/”存在,请将其去掉。
if(strUrl.startsWith(“/”){
strUrl=strUrl.子串(1);
}
//基于方法计算实际url。IIS仅支持
//在默认模式下获取和发布,因此我们将使用_方法参数
//MFWS理解这一点。
if(method!=HTTPMethod.GET&&method!=HTTPMethod.POST){
字符串方法参数;
if(结构包含(“?”){
methodParam=“&_method=”;
}否则{
methodParam=“?_method=”;
}
strUrl+=methodParam+method.name();
方法=HTTPMethod.POST;
}
//初始化JSON(反)序列化程序。
ObjectMapper om=新的ObjectMapper();
configure(org.codehaus.jackson.map.SerializationConfig.Feature.CAN\u OVERRIDE\u ACCESS\u MODIFIERS,false);
configure(org.codehaus.jackson.map.DeserializationConfig.Feature.CAN\u OVERRIDE\u ACCESS\u MODIFIERS,false);
configure(org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL\u ON\u UNKNOWN\u属性,false);
//获取REST接口的URL。
URL u=新的URL(strUrl);
//执行请求。
HttpURLConnection conn=null;
OutputStream os=null;
InputStream=null;
BufferedReader in=null;
试一试{
//打开连接。
conn=(HttpURLConnection)u.openConnection();
//防止使用缓存。
//小程序似乎不遵守从服务器接收的缓存控制标志。
//例如,它不一定会向服务器发出新请求,即使请求
//资源已过期。请参阅问题:#9234。
conn.SETUSECHACHES(假);
//设置请求属性。
conn.setRequestMethod(method.name());
if(body!=null)
连接设置输出(真);
如果(!output.equals(void.class))
conn.setDoInput(真);
如果(文件!=null)
{
conn.setRequestProperty(“接受”、“应用程序/八位字节流”);
}
其他的
{
conn.setRequestProperty(“接受”、“应用程序/json”);
}
conn.setRequestProperty(“X-Authentication”,authenticationToken);
如果(标题!=null){
for(Map.Entry头:headers.entrySet()){
System.out.println(“设置头”+头.getKey());
conn.setRequestProperty(header.getKey(),header.getValue());
}
}
//如果有正文,则将其序列化到输出流。
if(body!=null){
os=conn.getOutputStream();
om.writeValue(操作系统,主体);
}else if(method!=HTTPMethod.GET){
//没有人。
conn.setRequestProperty(“内容长度”,“0”);
}
//检查调用方是否希望连接作为返回值。
if(output.equals(HttpURLConnection.class)){
//更改所有权,这样我们就不会断开中的连接
//最后定稿。
HttpURLConnection=conn;
conn=null;
返回(T)值;
}
//如果我们有输出,就写输出。
如果(os!=null){
os.flush();
os.close();
}
os=null;
//获取对输入流的响应。
连接();
is=conn.getInputStream();
字符串响应=null;
int contentLength=conn.getContentLength();
if(output.equals(InputStream.class)){
//如果输出类型是输入流,只需返回它
//事实就是这样。
InputStream isReturn=is;
is=null;//更改所有权。
返回(T)isReturn;
}
否则{
如果(文件!=null)
{
FileOutputStream fileOut=新的FileOutputStream(文件);
IOUtils.copy(is,fileOut);
返回om.readValue(“真”,输出);
}
其他的
{
//从JSON对象反序列化。
response=readStringFromStream(是,contentLength);
}
//从响应中读取返回值。
if(output.equals(void.class)| response.length()==0)
返回null;
其他的
返回om.readValue(响应、输出);
}//如果(output.equals(InputStream.class))结束
}捕获(IOE3异常){
抛出新的运行时异常
    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();
    }
}
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Accept", "application/octet-stream");
conn.setRequestProperty("Accept", "image/png");