Skip to content

Commit 8464ff2

Browse files
committed
feat: Add Builder.jsonMapper(TypeMapper) shortcut
bodyMapper("application/json", mapper) is the 95% case; jsonMapper(mapper) removes the repeated media-type literal. Generic bodyMapper(mediaType, mapper) stays for text/csv, application/xml, etc.
1 parent 1813bc7 commit 8464ff2

3 files changed

Lines changed: 48 additions & 2 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ It is designed to be simple to use while providing the essential features needed
2525
- For `application/json` request/response bodies, either:
2626
- Gson on the classpath — auto-registered via the built-in `GsonJsonMapper` (integer-preserving, JSR-310 written as ISO-8601), or
2727
- Jackson via the built-in `JacksonJsonTypeMapper(ObjectMapper)` adapter (caller supplies a configured `ObjectMapper`), or
28-
- any other `TypeMapper` you register via `Builder.bodyMapper("application/json", mapper)`.
28+
- any other `TypeMapper` you register via `Builder.jsonMapper(mapper)` (shortcut for `bodyMapper("application/json", mapper)`).
2929
- Built-in mappers for `application/x-www-form-urlencoded` and `text/plain` need no configuration. Any other media type (`application/xml`, `application/cbor`, etc.) requires registering its own `TypeMapper`.
3030

3131

@@ -131,7 +131,7 @@ ObjectMapper objectMapper = new ObjectMapper()
131131

132132
var server = OpenApiServer.builder()
133133
.spec(spec)
134-
.bodyMapper("application/json", new JacksonJsonTypeMapper(objectMapper))
134+
.jsonMapper(new JacksonJsonTypeMapper(objectMapper))
135135
.handlers(handlers)
136136
.build();
137137
```

src/main/java/com/retailsvc/http/OpenApiServer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ public Builder bodyMapper(String mediaType, TypeMapper mapper) {
145145
return this;
146146
}
147147

148+
public Builder jsonMapper(TypeMapper mapper) {
149+
return bodyMapper("application/json", mapper);
150+
}
151+
148152
public Builder handlers(Map<String, RequestHandler> handlers) {
149153
this.handlers = handlers;
150154
return this;

src/test/java/com/retailsvc/http/TypeMapperRegistrationTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,48 @@ public byte[] writeTo(Object v) {
8888
assertThat(readFromCalled).isTrue();
8989
}
9090

91+
@Test
92+
void jsonMapperShortcutRegistersUnderApplicationJson() throws Exception {
93+
AtomicBoolean readFromCalled = new AtomicBoolean();
94+
TypeMapper marker =
95+
new TypeMapper() {
96+
@Override
97+
public Object readFrom(byte[] b, String h) {
98+
readFromCalled.set(true);
99+
return Map.of("aList", List.of("x"), "feelingGood", true);
100+
}
101+
102+
@Override
103+
public byte[] writeTo(Object v) {
104+
return new byte[0];
105+
}
106+
};
107+
RequestHandler echo = req -> Response.status(200);
108+
server =
109+
OpenApiServer.builder()
110+
.spec(spec)
111+
.jsonMapper(marker)
112+
.handlers(Map.of("get-data", echo, "post-data", echo))
113+
.port(0)
114+
.build();
115+
HttpClient.newHttpClient()
116+
.send(
117+
HttpRequest.newBuilder()
118+
.uri(URI.create("http://localhost:%d/api/v1/data".formatted(server.listenPort())))
119+
.header("Content-Type", "application/json")
120+
.POST(BodyPublishers.ofString("{\"anything\":\"goes\"}"))
121+
.build(),
122+
ofString());
123+
124+
assertThat(readFromCalled).isTrue();
125+
}
126+
127+
@Test
128+
void jsonMapperRejectsNullMapper() {
129+
OpenApiServer.Builder b = OpenApiServer.builder();
130+
assertThatThrownBy(() -> b.jsonMapper(null)).isInstanceOf(NullPointerException.class);
131+
}
132+
91133
@Test
92134
void bodyMapperRejectsNullArgs() {
93135
OpenApiServer.Builder b = OpenApiServer.builder();

0 commit comments

Comments
 (0)