Restlet reuse InputStream

帅比萌擦擦* 提交于 2019-12-11 03:36:01

问题


Consider the next code.

Filter:

public class InputFilter extends Filter {

  @Override
  protected int beforeHandle(Request request, Response response) {

    int result = CONTINUE;
    InputStream inputStream = request.getEntity().getStream();
    StringWriter writer = new StringWriter();
    IOUtils.copy(inputStream, writer, "UTF-8");

    String theString = writer.toString();
    JsonRepresentation jRep = new JsonRepresentation(theString);

    String token = jRep.getJsonObject().getString("token");
    .
    .
    .
    return result;
  }
}

Resource:

public class inputResource extends GsServerResource {

  @Post
  public JsonRepresentation getInput(JsonRepresentation jRep) {
    String token = jRep.getJsonObject().getString("token");
    .
    .
    .
  }
}

jRep is NULL.

I use the stream once in the filter and it is closed for later use due to the fact that it is not transient.

My current fix:

in the filter (after retrieving the Stream):

request.getAttributes().putIfAbsent("token", token);

in the resource:

String token = (String) getRequest().getAttributes().get("token");

Is there any other solution than putting the data in to the context in the filter and later retrieving it in the resource?


回答1:


In fact, you can set again within the filter the entity for the request based on a StringRepresentation based on the entity text you extracted from the request, as described below:

// Get entity text
Representation repr = request.getEntity();
String content = repr.getText();

// Use entity text
InputStream inputStream = request.getEntity().getStream();
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, "UTF-8");

String theString = writer.toString();
JsonRepresentation jRep = new JsonRepresentation(theString);

String token = jRep.getJsonObject().getString("token");

// Set again the entity for the request
StringRepresentation sRepr = new StringRepresentation(
                           content, repr.getMediaType());
request.setEntity(sRepr);

Using this approach, you can read again the request entity within the resource behind the filter.

Hope it helps you, Thierry




回答2:


There is a simpler approach to write the filter:

    Filter filter = new Filter(getContext()) {
        @Override
        protected int beforeHandle(Request request, Response response) {
            try {
                JsonRepresentation jrep = new JsonRepresentation(request.getEntity());
                JSONObject jo = jrep.getJsonObject();
                String token = jo.getString("token");
                System.out.println(token);
                request.setEntity(new JsonRepresentation(jo));
            } catch (JSONException | IOException e) {
                throw new ResourceException(Status.SERVER_ERROR_INTERNAL);
            }

            return super.beforeHandle(request, response);
        }
    };

And actually, it would even be easier if the JsonRepresentation class persists the parsed object. I've entered an issue for this topic (https://github.com/restlet/restlet-framework-java/issues/1067). In that case, we could simply write:

    Filter filter = new Filter(getContext()) {
        @Override
        protected int beforeHandle(Request request, Response response) {
            try {
                JsonRepresentation jrep = new JsonRepresentation(request.getEntity());
                String token = jrep.getJsonObject().getString("token");
                System.out.println(token);
                request.setEntity(jrep);
            } catch (JSONException | IOException e) {
                throw new ResourceException(Status.SERVER_ERROR_INTERNAL);
            }

            return super.beforeHandle(request, response);
        }
    };


来源:https://stackoverflow.com/questions/30012863/restlet-reuse-inputstream

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!