jersey
jersey copied to clipboard
DeclarativeLinkingFeature does not work with StreamingOutput
This code throws an exception[1]
@GET
@Path("/reports/{id}")
@Produces(MediaType.APPLICATION_XML)
public Response retrieveReportXml(@NotNull @PathParam("id") UUID id) {
StreamingOutput result = outputStream -> {
this.reportXmlService.exportReport(id, outputStream);
outputStream.flush();
};
return Response.ok(result, MediaType.APPLICATION_XML_TYPE).build();
}
if the Response entity is changed so that the processLinks method short circuits
if (instance.getClass().getName().startsWith("java.lang")) {
return;
}
using a byte[] then the method will return properly.
@GET
@Path("/reports/{id}")
@Produces(MediaType.APPLICATION_XML)
public Response retrieveReportXml(@NotNull @PathParam("id") UUID id) {
byte[] result = null;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
this.reportXmlService.exportReport(id, outputStream);
result = outputStream.toByteArray();
}
return Response.ok(result, MediaType.APPLICATION_XML_TYPE).build();
}
[1]exception stack excerpt
java.lang.UnsupportedOperationException: null
at org.codehaus.plexus.context.ContextMapAdapter.entrySet(ContextMapAdapter.java:106)
at org.glassfish.jersey.linking.FieldProcessor.processLinks(FieldProcessor.java:169)
at org.glassfish.jersey.linking.FieldProcessor.processMember(FieldProcessor.java:198)
at org.glassfish.jersey.linking.FieldProcessor.processLinks(FieldProcessor.java:178)
[2] version
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-declarative-linking</artifactId>
</dependency>
Appears perhaps lambda? is what is causing the problem. Using an anonymous class works.
@GET
@Path("/reports/{id}")
@Produces(MediaType.APPLICATION_XML)
public Response retrieveReportXml(@NotNull @PathParam("id") UUID id)
throws IOException {
StreamingOutput result = new StreamingOutput() {
@Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
ReportResource.this.reportXmlService.exportReport(id, outputStream);
outputStream.flush();
}
};
return Response.ok(result, MediaType.APPLICATION_XML_TYPE).build();
}
Similar to #3310 it would be nice (and provides convenient workaround for this issue) to annotate the resource class method with @InjectLinkNoFollow and short circuit the ResponseLinkFilter.
public void filter(ContainerRequestContext request, ContainerResponseContext response) {
Object entity = response.getEntity();
if (entity != null
&& !this.uriInfo.getMatchedResources().isEmpty()
&& !Stream.of(response.getEntityAnnotations()).anyMatch(ann -> InjectNoFollow.class.equals(ann.getAnnotationType())) {