Skip to content

Commit 41f2f2d

Browse files
committed
Return HTTP 404 when NoSuchElementException is thrown.
1 parent c730c0e commit 41f2f2d

File tree

5 files changed

+76
-137
lines changed

5 files changed

+76
-137
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,12 @@ protected boolean isAuthorized(HttpServletRequest request, Method method) { ...
238238
The first argument contains the current request, and the second the service method to be invoked. If `isAuthorized()` returns `true` (the default), method execution will proceed. Otherwise, the method will not be invoked, and an HTTP 403 response will be returned.
239239

240240
### Exceptions
241-
If an exception is thrown by a service method and the response has not yet been committed, the exception message (if any) will be returned as plain text in the response body. If the exception is an instance of `IllegalArgumentException` or `UnsupportedOperationException`, an HTTP 403 response will be returned. For `IllegalStateException`, HTTP 409 will be returned. For any other exception type, HTTP 500 will be returned.
241+
If an exception is thrown by a service method and the response has not yet been committed, the exception message (if any) will be returned as plain text in the response body. Error status will be returned as shown below:
242+
243+
* `IllegalArgumentException` or `UnsupportedOperationException` - HTTP 403 (forbidden)
244+
* `NoSuchElementException` - HTTP 404 (not found)
245+
* `IllegalStateException` - HTTP 409 (conflict)
246+
* Any other exception type - HTTP 500 (internal server error)
242247

243248
### API Documentation
244249
API documentation can be viewed by appending "?api" to a service URL; for example:

httprpc-server/src/main/java/org/httprpc/WebService.java

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import java.util.LinkedList;
5454
import java.util.List;
5555
import java.util.Map;
56+
import java.util.NoSuchElementException;
5657
import java.util.TreeMap;
5758

5859
import static java.util.Collections.emptyList;
@@ -359,38 +360,40 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
359360
} catch (IllegalAccessException | InvocationTargetException exception) {
360361
if (response.isCommitted()) {
361362
throw new ServletException(exception);
362-
} else {
363-
Throwable cause = exception.getCause();
364-
365-
if (cause != null) {
366-
int status;
367-
if (cause instanceof IllegalArgumentException || cause instanceof UnsupportedOperationException) {
368-
status = HttpServletResponse.SC_FORBIDDEN;
369-
} else if (cause instanceof IllegalStateException) {
370-
status = HttpServletResponse.SC_CONFLICT;
371-
} else {
372-
status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
373-
}
363+
}
374364

375-
response.setStatus(status);
365+
Throwable cause = exception.getCause();
376366

377-
String message = cause.getMessage();
367+
if (cause == null) {
368+
throw new ServletException(exception);
369+
}
378370

379-
if (message != null) {
380-
response.setContentType(String.format("text/plain;charset=%s", UTF_8));
371+
int status;
372+
if (cause instanceof IllegalArgumentException || cause instanceof UnsupportedOperationException) {
373+
status = HttpServletResponse.SC_FORBIDDEN;
374+
} else if (cause instanceof NoSuchElementException) {
375+
status = HttpServletResponse.SC_NOT_FOUND;
376+
} else if (cause instanceof IllegalStateException) {
377+
status = HttpServletResponse.SC_CONFLICT;
378+
} else {
379+
status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
380+
}
381381

382-
PrintWriter writer = response.getWriter();
382+
response.setStatus(status);
383383

384-
writer.append(message);
384+
String message = cause.getMessage();
385385

386-
writer.flush();
387-
}
386+
if (message != null) {
387+
response.setContentType(String.format("text/plain;charset=%s", UTF_8));
388388

389-
return;
390-
} else {
391-
throw new ServletException(exception);
392-
}
389+
PrintWriter writer = response.getWriter();
390+
391+
writer.append(message);
392+
393+
writer.flush();
393394
}
395+
396+
return;
394397
} finally {
395398
this.request.set(null);
396399
this.response.set(null);

httprpc-test/src/main/java/org/httprpc/test/CatalogService.java

Lines changed: 37 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -14,117 +14,92 @@
1414

1515
package org.httprpc.test;
1616

17+
import org.httprpc.Content;
1718
import org.httprpc.Description;
1819
import org.httprpc.RequestMethod;
1920
import org.httprpc.ResourcePath;
2021
import org.httprpc.WebService;
22+
import org.httprpc.beans.Key;
2123

22-
import javax.servlet.ServletException;
2324
import javax.servlet.annotation.WebServlet;
2425
import javax.servlet.http.HttpServletResponse;
25-
import java.util.ArrayList;
26-
import java.util.List;
26+
import java.util.HashMap;
27+
import java.util.Map;
2728

2829
@WebServlet(urlPatterns={"/catalog/*"}, loadOnStartup=1)
2930
@Description("Simulates a product catalog.")
3031
public class CatalogService extends WebService {
3132
@Description("Represents an item in the catalog.")
3233
public static class Item {
34+
private Integer id;
3335
private String description;
34-
private double price;
36+
private Double price;
3537

36-
private Item(String description, double price) {
37-
this.description = description;
38-
this.price = price;
38+
@Key("id")
39+
@Description("The item's ID.")
40+
public Integer getID() {
41+
return id;
3942
}
4043

4144
@Description("The item's description.")
4245
public String getDescription() {
4346
return description;
4447
}
4548

46-
private void setDescription(String description) {
49+
public void setDescription(String description) {
4750
this.description = description;
4851
}
4952

5053
@Description("The item's price.")
51-
public double getPrice() {
54+
public Double getPrice() {
5255
return price;
5356
}
5457

55-
private void setPrice(double price) {
58+
public void setPrice(Double price) {
5659
this.price = price;
5760
}
5861
}
5962

60-
private List<Item> items = new ArrayList<>();
63+
private Map<Integer, Item> items = new HashMap<>();
6164

62-
@Override
63-
public void init() throws ServletException {
64-
super.init();
65-
66-
addItem("Hat", 15.00);
67-
addItem("Mittens", 12.00);
68-
addItem("Scarf", 9.00);
69-
}
65+
private int nextID = 1;
7066

7167
@RequestMethod("GET")
7268
@ResourcePath("items")
7369
@Description("Returns a list of all items in the catalog.")
74-
public List<Item> getItems() {
75-
return items;
70+
public Iterable<Item> getItems() {
71+
return items.values();
7672
}
7773

7874
@RequestMethod("POST")
7975
@ResourcePath("items")
80-
@Description("Adds a new item to the catalog.")
81-
public int addItem(
82-
@Description("The item's description.") String description,
83-
@Description("The item's price.") double price
84-
) {
85-
items.add(new Item(description, price));
76+
@Description("Adds an item to the catalog.")
77+
@Content(Item.class)
78+
public Item addItem() {
79+
Item item = getBody();
8680

87-
HttpServletResponse response = getResponse();
81+
item.id = nextID++;
8882

89-
if (response != null) {
90-
response.setStatus(HttpServletResponse.SC_CREATED);
91-
}
83+
items.put(item.id, item);
9284

93-
return items.size();
94-
}
95-
96-
@RequestMethod("GET")
97-
@ResourcePath("items/?:itemID")
98-
@Description("Returns a single item.")
99-
public Item getItem() {
100-
int itemID = Integer.parseInt(getKey("itemID"));
101-
102-
Item item;
103-
if (itemID > 0 && itemID <= items.size()) {
104-
item = items.get(itemID - 1);
105-
} else {
106-
item = null;
107-
}
85+
getResponse().setStatus(HttpServletResponse.SC_CREATED);
10886

10987
return item;
11088
}
11189

112-
@RequestMethod("POST")
113-
@ResourcePath("items/?:itemID")
90+
@RequestMethod("PUT")
91+
@ResourcePath("items/?")
11492
@Description("Updates an item.")
115-
public void updateItem(
116-
@Description("The item's description.") String description,
117-
@Description("The item's price.") double price
118-
) {
119-
int itemID = Integer.parseInt(getKey("itemID"));
120-
121-
if (itemID > 0 && itemID <= items.size()) {
122-
Item item = items.get(itemID - 1);
123-
124-
item.setDescription(description);
125-
item.setPrice(price);
126-
} else {
127-
throw new IllegalArgumentException("Item not found.");
128-
}
93+
@Content(Item.class)
94+
public void updateItem() {
95+
// TODO Ensure that IDs match?
96+
// TODO How to handle "not found"?
97+
}
98+
99+
@RequestMethod("DELETE")
100+
@ResourcePath("items/?")
101+
@Description("Deletes an item.")
102+
public void deleteItem() {
103+
// TODO Return 404 if not found?
129104
}
130105
}

httprpc-test/src/main/webapp/index.jsp

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,42 +21,6 @@
2121
<hr/>
2222

2323
<a href="${pageContext.request.contextPath}/catalog?api">Catalog (API)</a><br/>
24-
<br/>
25-
<a href="${pageContext.request.contextPath}/catalog/items">Items</a><br/>
26-
27-
<br/>
28-
29-
<form action="${pageContext.request.contextPath}/catalog/items" method="post" enctype="application/x-www-form-urlencoded">
30-
<table>
31-
<tr>
32-
<td>Description</td><td><input name="description"/></td>
33-
</tr>
34-
<tr>
35-
<td>Price</td><td><input name="price"/></td>
36-
</tr>
37-
<tr>
38-
<td colspan="2"><input type="submit" value="Add Item"/></td>
39-
</tr>
40-
</table>
41-
</form>
42-
43-
<a href="${pageContext.request.contextPath}/catalog/items/1">Item 1</a><br/>
44-
45-
<br/>
46-
47-
<form action="${pageContext.request.contextPath}/catalog/items/1" method="post" enctype="application/x-www-form-urlencoded">
48-
<table>
49-
<tr>
50-
<td>Description</td><td><input name="description"/></td>
51-
</tr>
52-
<tr>
53-
<td>Price</td><td><input name="price"/></td>
54-
</tr>
55-
<tr>
56-
<td colspan="2"><input type="submit" value="Update Item 1"/></td>
57-
</tr>
58-
</table>
59-
</form>
6024

6125
<hr/>
6226

httprpc-test/src/test/java/org/httprpc/WebServiceProxyTest.java

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -119,19 +119,6 @@ interface TreeNode {
119119

120120
private static final int EOF = -1;
121121

122-
public static class AttachmentInfo {
123-
private int bytes = 0;
124-
private int checksum = 0;
125-
126-
public int getBytes() {
127-
return bytes;
128-
}
129-
130-
public int getChecksum() {
131-
return checksum;
132-
}
133-
}
134-
135122
public WebServiceProxyTest() throws IOException {
136123
serverURL = new URL("http://localhost:8080/httprpc-test-1.0/");
137124
}
@@ -472,7 +459,12 @@ public void testTree() throws IOException {
472459
}
473460

474461
@Test
475-
public void testAdapt() throws Exception {
462+
public void testCatalog() throws IOException {
463+
// TODO Test positive and negative (not found) cases
464+
}
465+
466+
@Test
467+
public void testObjectMethodDelegation() throws Exception {
476468
TestService testService1 = WebServiceProxy.adapt(new URL(serverURL, "test1/"), TestService.class);
477469
TestService testService2 = WebServiceProxy.adapt(new URL(serverURL, "test2/"), TestService.class);
478470

0 commit comments

Comments
 (0)