Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit 1c57258

Browse files
author
Adam Lindenthal
committed
JERSEY-2500 - InternalServerErrorException is not caugth by ExceptionMapper<WebApplicationException>
Change-Id: I8175c803f912bad95d0ea40c9ce42e748fca9c4f
1 parent f139549 commit 1c57258

File tree

5 files changed

+154
-18
lines changed

5 files changed

+154
-18
lines changed

core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import java.util.logging.Logger;
5959

6060
import javax.ws.rs.HttpMethod;
61+
import javax.ws.rs.InternalServerErrorException;
6162
import javax.ws.rs.NotFoundException;
6263
import javax.ws.rs.ServiceUnavailableException;
6364
import javax.ws.rs.WebApplicationException;
@@ -82,6 +83,7 @@
8283
import org.glassfish.jersey.internal.util.collection.Refs;
8384
import org.glassfish.jersey.internal.util.collection.Value;
8485
import org.glassfish.jersey.message.internal.HeaderValueException;
86+
import org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException;
8587
import org.glassfish.jersey.message.internal.OutboundJaxrsResponse;
8688
import org.glassfish.jersey.message.internal.OutboundMessageContext;
8789
import org.glassfish.jersey.message.internal.TracingLogger;
@@ -498,6 +500,12 @@ private Response mapException(final Throwable originalThrowable) throws Throwabl
498500
if (throwable instanceof MappableException) {
499501
inMappable = true;
500502
} else if (inMappable || throwable instanceof WebApplicationException) {
503+
// in case ServerProperties.PROCESSING_RESPONSE_ERRORS_ENABLED is true, allow
504+
// wrapped MessageBodyProviderNotFoundException to propagate
505+
if (runtime.processResponseErrors && throwable instanceof InternalServerErrorException
506+
&& throwable.getCause() instanceof MessageBodyProviderNotFoundException) {
507+
throw throwable;
508+
}
501509
Response waeResponse = null;
502510

503511
if (throwable instanceof WebApplicationException) {

core-server/src/main/java/org/glassfish/jersey/server/internal/MappableExceptionWrapperInterceptor.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
33
*
4-
* Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
4+
* Copyright (c) 2013-2014 Oracle and/or its affiliates. All rights reserved.
55
*
66
* The contents of this file are subject to the terms of either the GNU
77
* General Public License Version 2 only ("GPL") or the Common Development
@@ -41,6 +41,7 @@
4141

4242
import java.io.IOException;
4343

44+
import javax.ws.rs.InternalServerErrorException;
4445
import javax.ws.rs.WebApplicationException;
4546
import javax.ws.rs.ext.ReaderInterceptor;
4647
import javax.ws.rs.ext.ReaderInterceptorContext;
@@ -89,7 +90,7 @@ public void aroundWriteTo(WriterInterceptorContext context) throws IOException,
8990
} catch (WebApplicationException wae) {
9091
throw wae;
9192
} catch (MessageBodyProviderNotFoundException nfe) {
92-
throw nfe;
93+
throw new InternalServerErrorException(nfe);
9394
} catch (MappableException mappable) {
9495
throw mappable;
9596
} catch (Exception e) {

core-server/src/test/java/org/glassfish/jersey/server/ApplicationHandlerTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import java.util.concurrent.ExecutionException;
5353

5454
import javax.ws.rs.GET;
55+
import javax.ws.rs.InternalServerErrorException;
5556
import javax.ws.rs.POST;
5657
import javax.ws.rs.Path;
5758
import javax.ws.rs.Produces;
@@ -516,7 +517,8 @@ public static class MyResponseErrorMapper implements ResponseErrorMapper {
516517

517518
@Override
518519
public Response toResponse(final Throwable exception) {
519-
if (exception instanceof MessageBodyProviderNotFoundException || exception instanceof WebApplicationException) {
520+
if ((exception instanceof InternalServerErrorException && exception.getCause() instanceof
521+
MessageBodyProviderNotFoundException) || (exception instanceof WebApplicationException)) {
520522
return Response.ok().entity("bar").build();
521523
} else if (exception instanceof MappableException || exception instanceof RuntimeException) {
522524
return Response.ok().entity(new ResponseErrorEntity("bar")).type("foo/bar").build();

tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/ExceptionMapperTest.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import javax.ws.rs.ClientErrorException;
5353
import javax.ws.rs.Consumes;
5454
import javax.ws.rs.GET;
55+
import javax.ws.rs.InternalServerErrorException;
5556
import javax.ws.rs.NameBinding;
5657
import javax.ws.rs.POST;
5758
import javax.ws.rs.Path;
@@ -130,15 +131,13 @@ public void testReaderThrowsException() {
130131
assertEquals("reader-exception-mapper", entity);
131132
}
132133

133-
134134
@Test
135135
public void testWriterThrowsExceptionBeforeFirstBytesAreWritten() {
136136
Response res = target().path("test/before").request("test/test").get();
137137
assertEquals(200, res.getStatus());
138138
assertEquals("exception-before-first-bytes-exception-mapper", res.readEntity(String.class));
139139
}
140140

141-
142141
@Test
143142
public void testWriterThrowsExceptionAfterFirstBytesAreWritten() throws IOException {
144143
Response res = target().path("test/after").request("test/test").get();
@@ -152,7 +151,6 @@ public void testWriterThrowsExceptionAfterFirstBytesAreWritten() throws IOExcept
152151
}
153152
}
154153

155-
156154
@Test
157155
public void testPreventMultipleExceptionMapping() {
158156
Response res = target().path("test/exception").request("test/test").get();
@@ -170,7 +168,6 @@ public Response exceptionBeforeFirstBytesAreWritten() {
170168
return Response.status(200).header("writer-exception", "before-first-byte").entity("ok").build();
171169
}
172170

173-
174171
@GET
175172
@Path("after")
176173
@Produces("test/test")
@@ -279,7 +276,6 @@ public void writeTo(String s, Class<?> type, Type genericType, Annotation[] anno
279276
}
280277
}
281278

282-
283279
@Consumes("test/test")
284280
public static class MyMessageBodyReader implements MessageBodyReader<String> {
285281

@@ -545,25 +541,25 @@ public static class UnknownType {
545541

546542
}
547543

548-
public static class ProviderNotFoundExceptionMapper implements ExceptionMapper<MessageBodyProviderNotFoundException>{
549-
550-
544+
public static class ProviderNotFoundExceptionMapper implements ExceptionMapper<InternalServerErrorException>{
551545
@Override
552-
public Response toResponse(MessageBodyProviderNotFoundException exception) {
553-
return Response.ok("mapped-by-ProviderNotFoundExceptionMapper").build();
546+
public Response toResponse(InternalServerErrorException exception) {
547+
if (exception.getCause() instanceof MessageBodyProviderNotFoundException) {
548+
return Response.ok("mapped-by-ProviderNotFoundExceptionMapper").build();
549+
}
550+
return Response.serverError().entity("Unexpected root cause of InternalServerError").build();
554551
}
555552
}
556553

557554
/**
558-
* This test tests that {@link MessageBodyProviderNotFoundException} cannot be mapped by
559-
* an {@link ExceptionMapper}. Spec defines that exception mappers should process
560-
* exceptions thrown from user resources and providers. So, we currently limit exception
561-
* mappers only to these exceptions.
555+
* Tests that {@link MessageBodyProviderNotFoundException} wrapped into {@link javax.ws.rs.InternalServerErrorException}
556+
* is correctly mapped using an {@link ExceptionMapper}.
562557
*/
563558
@Test
564559
public void testNotFoundResource() {
565560
final Response response = target().path("not-found").request().get();
566-
assertEquals(500, response.getStatus());
561+
assertEquals(200, response.getStatus());
562+
assertEquals("mapped-by-ProviderNotFoundExceptionMapper", response.readEntity(String.class));
567563
}
568564

569565

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
5+
*
6+
* The contents of this file are subject to the terms of either the GNU
7+
* General Public License Version 2 only ("GPL") or the Common Development
8+
* and Distribution License("CDDL") (collectively, the "License"). You
9+
* may not use this file except in compliance with the License. You can
10+
* obtain a copy of the License at
11+
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
12+
* or packager/legal/LICENSE.txt. See the License for the specific
13+
* language governing permissions and limitations under the License.
14+
*
15+
* When distributing the software, include this License Header Notice in each
16+
* file and include the License file at packager/legal/LICENSE.txt.
17+
*
18+
* GPL Classpath Exception:
19+
* Oracle designates this particular file as subject to the "Classpath"
20+
* exception as provided by Oracle in the GPL Version 2 section of the License
21+
* file that accompanied this code.
22+
*
23+
* Modifications:
24+
* If applicable, add the following below the License Header, with the fields
25+
* enclosed by brackets [] replaced by your own identifying information:
26+
* "Portions Copyright [year] [name of copyright owner]"
27+
*
28+
* Contributor(s):
29+
* If you wish your version of this file to be governed by only the CDDL or
30+
* only the GPL Version 2, indicate your decision by adding "[Contributor]
31+
* elects to include this software in this distribution under the [CDDL or GPL
32+
* Version 2] license." If you don't indicate a single choice of license, a
33+
* recipient has the option to distribute your version of this file under
34+
* either the CDDL, the GPL Version 2 or to extend the choice of license to
35+
* its licensees as provided above. However, if you add GPL Version 2 code
36+
* and therefore, elected the GPL Version 2 license, then the option applies
37+
* only if the new code is made subject to such option by the copyright
38+
* holder.
39+
*/
40+
package org.glassfish.jersey.tests.e2e.server;
41+
42+
import org.glassfish.jersey.server.ResourceConfig;
43+
import org.glassfish.jersey.test.JerseyTest;
44+
import org.junit.Test;
45+
46+
import javax.ws.rs.Consumes;
47+
import javax.ws.rs.GET;
48+
import javax.ws.rs.POST;
49+
import javax.ws.rs.Path;
50+
import javax.ws.rs.Produces;
51+
import javax.ws.rs.WebApplicationException;
52+
import javax.ws.rs.client.Entity;
53+
import javax.ws.rs.core.Application;
54+
import javax.ws.rs.core.MediaType;
55+
import javax.ws.rs.core.Response;
56+
import javax.ws.rs.ext.ExceptionMapper;
57+
import javax.ws.rs.ext.Provider;
58+
59+
import java.util.logging.Logger;
60+
61+
import static org.junit.Assert.assertEquals;
62+
63+
/**
64+
* JERSEY-2500 reproducer test.
65+
*
66+
* Tests, that correct exceptions are thrown in case no MessageBodyProvider was matched on server.
67+
*
68+
* - InternalServerErrorException for MBW (JSR339, chapter 4.2.2, step 7)
69+
* - NotSupportedException for MBR (JSR339, chapter 4.2.1, step 6)
70+
*
71+
* @author Adam Lindenthal (adam.lindenthal at oracle.com)
72+
*/
73+
public class MessageBodyProvidersExceptionsTest extends JerseyTest {
74+
75+
private static final Logger LOGGER = Logger.getLogger(MessageBodyProvidersExceptionsTest.class.getName());
76+
77+
@Override
78+
protected Application configure() {
79+
return new ResourceConfig(
80+
Resource.class,
81+
WebAppExceptionMapper.class
82+
);
83+
}
84+
85+
@Path("resource")
86+
public static class Resource {
87+
@GET
88+
@Path("write")
89+
@Produces(MediaType.TEXT_PLAIN)
90+
public Resource failOnWrite() {
91+
return this;
92+
}
93+
94+
@POST
95+
@Path("read")
96+
@Consumes("foo/bar")
97+
@Produces(MediaType.TEXT_PLAIN)
98+
public String failOnRead() {
99+
return "this-should-never-be-returned";
100+
}
101+
}
102+
103+
@Provider
104+
public static class WebAppExceptionMapper implements ExceptionMapper<WebApplicationException> {
105+
@Override
106+
public Response toResponse(WebApplicationException exception) {
107+
LOGGER.fine("ExceptionMapper was invoked.");
108+
// return the exception class name as an entity for further comparison
109+
return Response.status(200).header("writer-exception", "after-first-byte").entity(exception.getClass().getName()).build();
110+
}
111+
}
112+
113+
@Test
114+
public void testReaderThrowsCorrectException() {
115+
Response response = target().path("resource/write").request(MediaType.TEXT_PLAIN).get();
116+
assertEquals(200, response.getStatus());
117+
String resString = response.readEntity(String.class);
118+
// no MBW should have been found, InternalServerErrorException expected
119+
assertEquals("javax.ws.rs.InternalServerErrorException", resString);
120+
}
121+
122+
@Test public void testWriterThrowsCorrectException() {
123+
Response response = target().path("resource/read").request().post(Entity.entity("Hello, world", "text/plain"));
124+
assertEquals(200, response.getStatus());
125+
String resString = response.readEntity(String.class);
126+
// no MBR should have been found, NotSupportedException expected
127+
assertEquals("javax.ws.rs.NotSupportedException", resString);
128+
}
129+
}

0 commit comments

Comments
 (0)