简体   繁体   中英

Jersey server JSON response throwing MalformedChunkCodingException: Chunked stream ended unexpectedly

I have a basic java webserver for persisting payment history of users. I am trying to write a method to return a list of payments by querying a database, but for some reason the client keeps throwing an exception.

Here is my resource method for the server:

@RolesAllowed({"authenticated","administrator","superadministrator"})
@Path("getPaymentHistory/{userId}")
@GET
public Response getPaymentHistory(@Context SecurityContext sc, @PathParam("userId") String userId){
    PaymentListResponse response = paymentService.getUserPaymentHistory(userId);
    logger.debug("payment service found " +response.getPayments().size()+ " payments for user: " + userId);
    return Response.ok().entity(response).build();
}

This produces the following log :

DEBUG cbspresource.PaymentResource - payment service found 3 payments for user: c832f8c2-f5ff-4e5c-a1b9-7e5a3f26a359

Therefore the list is definitely populated with the 3 payments the user has made previously. I added the list to an XML root element as I thought it may be the cause of the exception:

@XmlRootElement
public class PaymentListResponse {

    private List<Payment> payments = new ArrayList<Payment>();

    public PaymentListResponse(){}

    //getter & setter .. 
}

Here is my client code:

    DefaultHttpClient httpClient = new DefaultHttpClient();
    String responseString = null;
    HttpResponse response;
    try {
        response = httpClient.execute(data);
        HttpEntity entity = response.getEntity();
        responseString = EntityUtils.toString(entity, "UTF-8");
    } catch (HttpException | IOException e) {
        e.printStackTrace();
    }
    return responseString;

This produces the following log:

 org.apache.http.MalformedChunkCodingException: Chunked stream ended unexpectedly at org.apache.http.impl.io.ChunkedInputStream.getChunkSize(ChunkedInputStream.java:222) at org.apache.http.impl.io.ChunkedInputStream.nextChunk(ChunkedInputStream.java:183) at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:155) at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:159) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.Reader.read(Reader.java:140) at org.apache.http.util.EntityUtils.toString(EntityUtils.java:135) 

I cant figure out why my JSON is causing errors, I have responses from the same Resource being sent back without errors. this happens only when i try to send a populated list. If the list is empty the response from the server is

{"payments":[]}


Update

I used the following code as suggested in the answers:

return Response.ok().entity(response.toArray()).build();

Class annotations are as follows:

@Produces({MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_JSON})

with the same exception being thrown. For clarity, I have used this type of response before in another part of the server. The response from that is also a JSON list and is handled by the same client code.

Here is another method which works:

@RolesAllowed({"administrator","superadministrator"})
@Path("get_all")
@GET
public Response getAccounts(@Context SecurityContext sc) {
    ExternalUser userMakingRequest = (ExternalUser)sc.getUserPrincipal();
    List<Account> accounts = accountService.getAllAccounts(userMakingRequest);
    return Response.ok().entity(accounts).build();
}

This exception is thrown whenever there is a problem in the header with the HTTP request. If I had to guess, your specific problem may be due to the fact that you are sending a list, so the header doesn't end properly. Try to call the toArray() method of the list to convert it into an array before sending it.

I realised that the Object I was returning, Payment, contained a linked JPA object. So my response contained the whole DB object, with all relationships. The client was still receiving data while I attempted to extract the String, therefore the exception was thrown. I used a different method to extract the String from HttpEntity, here it is:

public static String sendGetReqForList(HttpGet get){
    DefaultHttpClient httpClient = new DefaultHttpClient();
    StringBuilder  result = new StringBuilder();
    HttpResponse response = null;
    try {
         response = httpClient.execute(get);
    } catch (Exception e) {   
        e.printStackTrace();
    }
    InputStream input = null;
    try {
        input = new BufferedInputStream(response.getEntity().getContent());
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    byte data[] = new byte[40000];
    int currentByteReadCount = 0;
    /** read response from input stream */
    try {
        while ((currentByteReadCount = input.read(data)) != -1) {
            String readData = new String(data, 0, currentByteReadCount);
            result.append(readData);
            if (readData.indexOf("}~{") >= 0) {
                System.out.println("got json obj from data");
            }
        }   
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        input.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    /** transform response into JSONArray */
    return result.toString();
}

This allowed me to see the full string.

Also duplicate of this issue: used some code from there link to stackoverflow question

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM