Reputation: 13682
I'm having difficulty throwing a WebApplicationException
from my StreamingOutput
implementation. I would expect the code below to return a 501, but curl is reporting curl: (52) Empty reply from server
. I can see the 503 in the trace of the call, but Jersey is just replying with an empty body. Does anybody know what gives?
public final class MyStreamingOutput implements StreamingOutput {
@Override
public void write(final OutputStream outputStream)
throws IOException {
try {
dataProvider = new DataProvider(); // throws SQLException
} catch (final SQLException e) {
throw new WebApplicationException(503);
}
}
}
This is the trace I'm seeing:
java.sql.SQLException: Invalid object name 'no_such_table'.
at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:368) ~[jtds-1.2.4.jar:1.2.4]
...
16:05:22.148 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - MBW_WRITE_TO WriteTo by [org.glassfish.jersey.message.internal.StreamingOutputProvider @1d45d135] [642.98 ms]
16:05:22.148 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - WI_AFTER [org.glassfish.jersey.filter.LoggingFilter @77edc290 #-2147483648] AFTER context.proceed() [ 0.00 ms]
16:05:22.148 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - WI_AFTER [org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor @2a0fded2 #3000] AFTER context.proceed() [ 0.01 ms]
16:05:22.148 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - WI_AFTER [org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor @26c087be #10] AFTER context.proceed() [ 0.01 ms]
16:05:22.148 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - WI_SUMMARY WriteTo summary: 3 interceptors [644.44 ms]
16:05:22.148 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - FINISHED Response status: 200/SUCCESSFUL|OK [ ---- ms]
16:05:22.153 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - EXCEPTION_MAPPING Exception mapper [com.locustec.eim.query.rest.RuntimeExceptionMapper @3a8978c7] maps [javax.ws.rs.WebApplicationException @563625d0 <501/SERVER_ERROR|Not Implemented|-no-entity->] ('Carp') to <501/SERVER_ERROR|Not Implemented> [ 0.02 ms]
16:05:22.153 [http-8080-1] INFO o.g.jersey.filter.LoggingFilter - 8 * LoggingFilter - Response received on thread http-8080-1
8 < 503
16:05:22.154 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - RESPONSE_FILTER Filter by [org.glassfish.jersey.filter.LoggingFilter @5271b383 #-2147483648] [ 0.13 ms]
16:05:22.154 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - RESPONSE_FILTER_SUMMARY Response summary: 1 filters [ 0.93 ms]
16:05:22.155 [http-8080-1] DEBUG org.glassfish.jersey.tracing.general - FINISHED Response status: 501/SERVER_ERROR|Not Implemented [ ---- ms]
16:05:22.160 [http-8080-1] TRACE o.g.j.process.internal.RequestScope - [DEBUG] Released scope instance Instance{id=021c24a2-c224-4c22-8f18-e5f7f93b0295, referenceCounter=0, store size=0} on thread http-8080-1
Upvotes: 1
Views: 1673
Reputation: 1574
Jersey is beginning the HTTP response, thus sending a 200 OK, and only after that starts calling your StreamingOutput.write
implementation. So, when your exception is raised, it's already too late to send a different HTTP code.
The best way I found to deal with this kind of issue is trying to do as much as possible outside of the StreamingOutput
, or in the constructor of the implementation (these versions will send 500, you can catch the SQLException
if you want something else):
@GET
public StreamingOutput getDataWithAnonymousClass() throws SQLException {
final DataProvider dataProvider = new DataProvider();
return new StreamingOutput() {
@Override
public void write(OutputStream output) {
dataProvider.writeData(output);
}
}
}
public final class MyStreamingOutput implements StreamingOutput {
private final DataProvider dataProvider;
public MyStreamingOutput() throws SQLException {
this.dataProvider = new DataProvider();
}
@Override
public void write(OutputStream output) {
dataProvider.writeData(output);
}
}
@GET
public StreamingOutput getDataWithExcInConstructor() throws SQLException {
return new MyStreamingOutput();
}
That way, the exception is thrown before the HTTP response has been started, and you can have a different status.
Upvotes: 1