1

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
2
  • Is the 501/503 mismatch a typo? I'm having the same problem, trying to map a runtime exception from a third-party library to a sensible status code - no luck yet :( Commented May 12, 2014 at 14:32
  • Yes, it's a typo. Either one would be fine .. just not 500, or what I'm seeing, just nothing - a totally empty response. Commented May 12, 2014 at 14:33

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.