Jersey InputStream 在过滤器中被修改。无法弄清楚如何访问 Jersey Resource 中修改后的 inputStream
Jersey InputStream is modified in filter. Unable to figure out how to access modified inputStream in Jersey Resource
如 How to use Jersey interceptors to get request body 中所述,我正在修改 ContainerRequestFilter 中的 EntityInputStream。
public filter(ContainerRequest request){
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = request.getEntityInputStream();
try{
Readerwriter.writeTo(in, out);
byte[] requestEntity = out.toByteArray();
// DO SOMETHING WITH BYTES HERE
request.setEntityInputStream(new ByteArrayInputStream(requestEntity));
}/// error handling code here
}
但是,后来我不知道如何访问修改后的 InputStream。我可以在资源中获取 ServletContext,但我不知道如何获取我在过滤器中实际修改的对象,即 ContainerRequest。
我可以做这样的事情吗?当我尝试这个时,Jersey 无法启动:
@Post
@Path("/test")
public Response test(@Context ContainerRequest cr){
// blah blah
return....
}
球衣错误:
缺少方法 public javax.ws.rs.core.Response example.TestController.test(com.sun.jersey.spi.container.ContainerRequest) 的依赖项,注释为 POST 资源,class example.TestController, 未被识别为有效的资源方法。
我卡在旧版本的球衣 1.8 上,所以我不确定这是否是问题的一部分。
您需要做的就是在您的资源方法中接受一个 InputStream
作为实体主体。如果你想要 ByteArrayInputStream
就投它。
@POST
public Response post(InputStream in) {
ByteArrayInputStream bin = (ByteArrayInputStream)in;
}
如果您还不知道,Jersey 如何将请求流(对于请求主体)转换为 Java 类型(例如 JSON 到 POJO)是通过 MessageBodyReader
s. You can read more about them at JAX-RS Entity Providers .
Jersey 已经提供了一些标准 readers 用于易于转换的类型,例如 String。大多数内容类型都可以转换为字符串。同样,它有一个 reader 来处理 InputStream
。这可能是最简单的转换,因为请求已经作为 InputStream
传入,所以 reader 实际上需要做的就是 return 原始流,这就是得到的传递给我们的方法。
如果我们看一下实现 InputStreamProvider
, we can see that that's what actually happens. The original stream is simply returned。由于过滤器发生在 reader 之前,因此 reader 只是 return 我们设置的流。
这是一个使用 Jersey Test Framework
的完整示例
public class StreamFilterTest extends JerseyTest {
public static class InputStreamFilter implements ContainerRequestFilter {
@Override
public ContainerRequest filter(ContainerRequest request) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = request.getEntityInputStream();
ReaderWriter.writeTo(in, out);
byte[] requestBytes = out.toByteArray();
byte[] worldBytes = " World".getBytes(StandardCharsets.UTF_8);
byte[] newBytes = new byte[requestBytes.length + worldBytes.length];
System.arraycopy(requestBytes, 0, newBytes, 0, requestBytes.length);
System.arraycopy(worldBytes, 0, newBytes, requestBytes.length, worldBytes.length);
request.setEntityInputStream(new ByteArrayInputStream(newBytes));
} catch (IOException ex) {
Logger.getLogger(InputStreamFilter.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
return request;
}
}
@Path("stream")
public static class StreamResource {
@POST
public String post(InputStream in) throws Exception {
ByteArrayInputStream bin = (ByteArrayInputStream) in;
StringWriter writer = new StringWriter();
ReaderWriter.writeTo(new InputStreamReader(bin), writer);
return writer.toString();
}
}
public static class AppConfig extends DefaultResourceConfig {
public AppConfig() {
super(StreamResource.class);
getContainerRequestFilters().add(new InputStreamFilter());
}
}
@Override
public WebAppDescriptor configure() {
return new WebAppDescriptor.Builder()
.initParam(WebComponent.RESOURCE_CONFIG_CLASS,
AppConfig.class.getName())
.build();
}
@Test
public void should_return_hello_world() {
String response = resource().path("stream").post(String.class, "Hello");
assertEquals("Hello World", response);
}
}
这是测试依赖
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>1.17.1</version>
<scope>test</scope>
</dependency>
如 How to use Jersey interceptors to get request body 中所述,我正在修改 ContainerRequestFilter 中的 EntityInputStream。
public filter(ContainerRequest request){
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = request.getEntityInputStream();
try{
Readerwriter.writeTo(in, out);
byte[] requestEntity = out.toByteArray();
// DO SOMETHING WITH BYTES HERE
request.setEntityInputStream(new ByteArrayInputStream(requestEntity));
}/// error handling code here
}
但是,后来我不知道如何访问修改后的 InputStream。我可以在资源中获取 ServletContext,但我不知道如何获取我在过滤器中实际修改的对象,即 ContainerRequest。
我可以做这样的事情吗?当我尝试这个时,Jersey 无法启动:
@Post
@Path("/test")
public Response test(@Context ContainerRequest cr){
// blah blah
return....
}
球衣错误:
缺少方法 public javax.ws.rs.core.Response example.TestController.test(com.sun.jersey.spi.container.ContainerRequest) 的依赖项,注释为 POST 资源,class example.TestController, 未被识别为有效的资源方法。
我卡在旧版本的球衣 1.8 上,所以我不确定这是否是问题的一部分。
您需要做的就是在您的资源方法中接受一个 InputStream
作为实体主体。如果你想要 ByteArrayInputStream
就投它。
@POST
public Response post(InputStream in) {
ByteArrayInputStream bin = (ByteArrayInputStream)in;
}
如果您还不知道,Jersey 如何将请求流(对于请求主体)转换为 Java 类型(例如 JSON 到 POJO)是通过 MessageBodyReader
s. You can read more about them at JAX-RS Entity Providers .
Jersey 已经提供了一些标准 readers 用于易于转换的类型,例如 String。大多数内容类型都可以转换为字符串。同样,它有一个 reader 来处理 InputStream
。这可能是最简单的转换,因为请求已经作为 InputStream
传入,所以 reader 实际上需要做的就是 return 原始流,这就是得到的传递给我们的方法。
如果我们看一下实现 InputStreamProvider
, we can see that that's what actually happens. The original stream is simply returned。由于过滤器发生在 reader 之前,因此 reader 只是 return 我们设置的流。
这是一个使用 Jersey Test Framework
的完整示例public class StreamFilterTest extends JerseyTest {
public static class InputStreamFilter implements ContainerRequestFilter {
@Override
public ContainerRequest filter(ContainerRequest request) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = request.getEntityInputStream();
ReaderWriter.writeTo(in, out);
byte[] requestBytes = out.toByteArray();
byte[] worldBytes = " World".getBytes(StandardCharsets.UTF_8);
byte[] newBytes = new byte[requestBytes.length + worldBytes.length];
System.arraycopy(requestBytes, 0, newBytes, 0, requestBytes.length);
System.arraycopy(worldBytes, 0, newBytes, requestBytes.length, worldBytes.length);
request.setEntityInputStream(new ByteArrayInputStream(newBytes));
} catch (IOException ex) {
Logger.getLogger(InputStreamFilter.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
return request;
}
}
@Path("stream")
public static class StreamResource {
@POST
public String post(InputStream in) throws Exception {
ByteArrayInputStream bin = (ByteArrayInputStream) in;
StringWriter writer = new StringWriter();
ReaderWriter.writeTo(new InputStreamReader(bin), writer);
return writer.toString();
}
}
public static class AppConfig extends DefaultResourceConfig {
public AppConfig() {
super(StreamResource.class);
getContainerRequestFilters().add(new InputStreamFilter());
}
}
@Override
public WebAppDescriptor configure() {
return new WebAppDescriptor.Builder()
.initParam(WebComponent.RESOURCE_CONFIG_CLASS,
AppConfig.class.getName())
.build();
}
@Test
public void should_return_hello_world() {
String response = resource().path("stream").post(String.class, "Hello");
assertEquals("Hello World", response);
}
}
这是测试依赖
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>1.17.1</version>
<scope>test</scope>
</dependency>