Skip to content

Commit 9268994

Browse files
committed
Minor changes
- change message when value is missing - Value.toMap sibiling methods on Context - minor doc changes
1 parent 69a5dd6 commit 9268994

File tree

8 files changed

+82
-32
lines changed

8 files changed

+82
-32
lines changed

docs/value-api.adoc

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,5 +294,19 @@ The parser matches HTTP parameters in the following order:
294294
- As constructor arguments
295295
- As setter method
296296

297-
Also, constructor and method arguments must be annotated with
298-
https://static.javadoc.io/javax.inject/javax.inject/1/javax/inject/Named.html[Named] when HTTP parameter name is not a valid Java identifier.
297+
HTTP parameter name which are not a valid Java identifier must be annotated with https://static.javadoc.io/javax.inject/javax.inject/1/javax/inject/Named.html[Named]:
298+
299+
[source, java]
300+
----
301+
class Member {
302+
public final String firstname;
303+
304+
public final String lastname;
305+
306+
public Member(@Named("first-name") String firstname, @Named("last-name") String lastname) {
307+
....
308+
}
309+
}
310+
----
311+
312+
{love}{love}

jooby/src/main/java/io/jooby/Context.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,14 @@ public interface Context {
112112
return query().to(type);
113113
}
114114

115-
@Nonnull default Map<String, List<String>> queryMultimap() {
115+
@Nonnull default Map<String, String> queryMap() {
116116
return query().toMap();
117117
}
118118

119+
@Nonnull default Map<String, List<String>> queryMultimap() {
120+
return query().toMultimap();
121+
}
122+
119123
/* **********************************************************************************************
120124
* Header API
121125
* **********************************************************************************************
@@ -127,10 +131,14 @@ public interface Context {
127131
return headers().get(name);
128132
}
129133

130-
@Nonnull default Map<String, List<String>> headerMultimap() {
134+
@Nonnull default Map<String, String> headerMap() {
131135
return headers().toMap();
132136
}
133137

138+
@Nonnull default Map<String, List<String>> headerMultimap() {
139+
return headers().toMultimap();
140+
}
141+
134142
default boolean accept(String contentType) {
135143
String accept = header(ACCEPT).value(MediaType.ALL);
136144
return MediaType.matches(contentType, accept);
@@ -144,6 +152,10 @@ default boolean accept(String contentType) {
144152
@Nonnull Formdata form();
145153

146154
@Nonnull default Map<String, List<String>> formMultimap() {
155+
return form().toMultimap();
156+
}
157+
158+
@Nonnull default Map<String, String> formMap() {
147159
return form().toMap();
148160
}
149161

@@ -187,6 +199,10 @@ default boolean accept(String contentType) {
187199
}
188200

189201
@Nonnull default Map<String, List<String>> multipartMultimap() {
202+
return multipart().toMultimap();
203+
}
204+
205+
@Nonnull default Map<String, String> multipartMap() {
190206
return multipart().toMap();
191207
}
192208

jooby/src/main/java/io/jooby/Err.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class Err extends RuntimeException {
1919

2020
public static class Missing extends Err {
2121
public Missing(String name) {
22-
super(StatusCode.BAD_REQUEST, "Required value is not present: '" + name + "'");
22+
super(StatusCode.BAD_REQUEST, "Missing value: '" + name + "'");
2323
}
2424
}
2525

jooby/src/main/java/io/jooby/Value.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import javax.annotation.Nonnull;
2222
import javax.annotation.Nullable;
23+
import java.lang.reflect.Type;
2324
import java.util.ArrayList;
2425
import java.util.Collection;
2526
import java.util.Collections;
@@ -91,9 +92,9 @@ public Array add(String value) {
9192
return value.iterator();
9293
}
9394

94-
@Override public Map<String, List<String>> toMap() {
95+
@Override public Map<String, List<String>> toMultimap() {
9596
List<String> values = new ArrayList<>();
96-
value.stream().forEach(it -> it.toMap().values().forEach(values::addAll));
97+
value.stream().forEach(it -> it.toMultimap().values().forEach(values::addAll));
9798
return Collections.singletonMap(name, values);
9899
}
99100

@@ -267,14 +268,14 @@ public int size() {
267268
return hash.values().iterator();
268269
}
269270

270-
@Override public Map<String, List<String>> toMap() {
271+
@Override public Map<String, List<String>> toMultimap() {
271272
Map<String, List<String>> result = new LinkedHashMap<>(hash.size());
272273
Set<Map.Entry<String, Value>> entries = hash.entrySet();
273274
String scope = name == null ? "" : name + ".";
274275
for (Map.Entry<String, Value> entry : entries) {
275276
Value value = entry.getValue();
276277
if (!value.isUpload()) {
277-
value.toMap().forEach((k, v) -> {
278+
value.toMultimap().forEach((k, v) -> {
278279
result.put(scope + k, v);
279280
});
280281
}
@@ -310,7 +311,7 @@ public Missing(String name) {
310311
throw new Err.Missing(name);
311312
}
312313

313-
@Override public Map<String, List<String>> toMap() {
314+
@Override public Map<String, List<String>> toMultimap() {
314315
return Collections.emptyMap();
315316
}
316317
}
@@ -354,7 +355,7 @@ public Simple(String name, String value) {
354355
return Collections.<Value>singletonList(this).iterator();
355356
}
356357

357-
@Override public Map<String, List<String>> toMap() {
358+
@Override public Map<String, List<String>> toMultimap() {
358359
return singletonMap(name, singletonList(value));
359360
}
360361

@@ -416,7 +417,11 @@ default byte byteValue(byte defaultValue) {
416417
}
417418

418419
default float floatValue() {
419-
return Float.parseFloat(value());
420+
try {
421+
return Float.parseFloat(value());
422+
} catch (NumberFormatException x) {
423+
throw new Err.BadRequest("Type mismatch: cannot convert to number", x);
424+
}
420425
}
421426

422427
default float floatValue(float defaultValue) {
@@ -428,7 +433,11 @@ default float floatValue(float defaultValue) {
428433
}
429434

430435
default double doubleValue() {
431-
return Double.parseDouble(value());
436+
try {
437+
return Double.parseDouble(value());
438+
} catch (NumberFormatException x) {
439+
throw new Err.BadRequest("Type mismatch: cannot convert to number", x);
440+
}
432441
}
433442

434443
default double doubleValue(double defaultValue) {
@@ -551,6 +560,11 @@ default <T> T to(Class<T> type) {
551560
return injector.inject(this, type, type);
552561
}
553562

563+
default <T> T to(Type type) {
564+
ValueInjector injector = new ValueInjector();
565+
return injector.inject(this, type, Reified.rawType(type));
566+
}
567+
554568
default <T> T to(Reified<T> type) {
555569
ValueInjector injector = new ValueInjector();
556570
return injector.inject(this, type.getType(), type.getRawType());
@@ -562,7 +576,13 @@ default <T> T to(Reified<T> type) {
562576

563577
String name();
564578

565-
Map<String, List<String>> toMap();
579+
Map<String, List<String>> toMultimap();
580+
581+
default @Nonnull Map<String, String> toMap() {
582+
Map<String, String> map = new LinkedHashMap<>();
583+
toMultimap().forEach((k, v) -> map.put(k, v.get(0)));
584+
return map;
585+
}
566586

567587
/* ***********************************************************************************************
568588
* Factory methods

jooby/src/main/java/io/jooby/internal/BodyImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public BodyImpl(InputStream stream, long contentLength) {
4343
return "body";
4444
}
4545

46-
@Override public Map<String, List<String>> toMap() {
46+
@Override public Map<String, List<String>> toMultimap() {
4747
return Collections.emptyMap();
4848
}
4949
}

jooby/src/test/java/io/jooby/ValueTest.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -192,24 +192,24 @@ public void arrayArity() {
192192
@Test
193193
public void valueToMap() {
194194
queryString("?foo=bar", queryString -> {
195-
assertEquals("{foo=[bar]}", queryString.toMap().toString());
195+
assertEquals("{foo=[bar]}", queryString.toMultimap().toString());
196196
});
197197
queryString("?a=1;a=2", queryString -> {
198-
assertEquals("{a=[1, 2]}", queryString.toMap().toString());
198+
assertEquals("{a=[1, 2]}", queryString.toMultimap().toString());
199199
});
200200
queryString(
201201
"?username=xyz&address[country][name]=AR&address[line1]=Line1&address[country][city]=BA",
202202
queryString -> {
203203
assertEquals(
204204
"{username=[xyz], address.country.name=[AR], address.country.city=[BA], address.line1=[Line1]}",
205-
queryString.toMap().toString());
205+
queryString.toMultimap().toString());
206206
assertEquals(
207207
"{address.country.name=[AR], address.country.city=[BA], address.line1=[Line1]}",
208-
queryString.get("address").toMap().toString());
208+
queryString.get("address").toMultimap().toString());
209209
assertEquals("{country.name=[AR], country.city=[BA]}",
210-
queryString.get("address").get("country").toMap().toString());
210+
queryString.get("address").get("country").toMultimap().toString());
211211
assertEquals("{city=[BA]}",
212-
queryString.get("address").get("country").get("city").toMap().toString());
212+
queryString.get("address").get("country").get("city").toMultimap().toString());
213213
});
214214
}
215215

@@ -330,7 +330,7 @@ public void toEnum() {
330330
assertEquals(Letter.B, queryString.get("e").get(1).toEnum(Letter::valueOf));
331331
assertMessage(Err.Missing.class,
332332
() -> queryString.get("e").get(2).toEnum(Letter::valueOf),
333-
"Required value is not present: 'e[2]'");
333+
"Missing value: 'e[2]'");
334334
});
335335
}
336336

@@ -345,11 +345,11 @@ public void verifyExceptionMessage() {
345345
assertMessage(Err.BadRequest.class, () -> queryString.get("foo").intValue(0),
346346
"Type mismatch: cannot convert to number");
347347
assertMessage(Err.Missing.class, () -> queryString.get("foo").get("bar").value(),
348-
"Required value is not present: 'foo.bar'");
348+
"Missing value: 'foo.bar'");
349349
assertMessage(Err.Missing.class, () -> queryString.get("foo").get(1).value(),
350-
"Required value is not present: 'foo.1'");
350+
"Missing value: 'foo.1'");
351351
assertMessage(Err.Missing.class, () -> queryString.get("r").longValue(),
352-
"Required value is not present: 'r'");
352+
"Missing value: 'r'");
353353
assertEquals(1, queryString.get("a").intValue(1));
354354
});
355355

@@ -360,22 +360,22 @@ public void verifyExceptionMessage() {
360360
assertMessage(Err.BadRequest.class, () -> queryString.get("a").get(0).longValue(),
361361
"Type mismatch: cannot convert to number");
362362
assertMessage(Err.Missing.class, () -> queryString.get("a").get(3).longValue(),
363-
"Required value is not present: 'a[3]'");
363+
"Missing value: 'a[3]'");
364364
assertMessage(Err.Missing.class, () -> queryString.get("a").get("b").value(),
365-
"Required value is not present: 'a.b'");
365+
"Missing value: 'a.b'");
366366
assertMessage(Err.Missing.class, () -> queryString.get("a").get("b").get(3).longValue(),
367-
"Required value is not present: 'a.b[3]'");
367+
"Missing value: 'a.b[3]'");
368368
});
369369

370370
/** Single: */
371371
assertMessage(Err.BadRequest.class, () -> Value.value("foo", "bar").intValue(),
372372
"Type mismatch: cannot convert to number");
373373

374374
assertMessage(Err.Missing.class, () -> Value.value("foo", "bar").get("foo").value(),
375-
"Required value is not present: 'foo.foo'");
375+
"Missing value: 'foo.foo'");
376376

377377
assertMessage(Err.Missing.class, () -> Value.value("foo", "bar").get(1).value(),
378-
"Required value is not present: 'foo.1'");
378+
"Missing value: 'foo.1'");
379379

380380
}
381381

jooby/src/test/java/io/jooby/ValueToBeanTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ public void constructorInjection() {
309309

310310
queryString("?name=user", queryString -> {
311311
assertMessage(Err.Missing.class, () -> queryString.to(User.class),
312-
"Required value is not present: 'password'");
312+
"Missing value: 'password'");
313313

314314
ValueInjector injector = new ValueInjector().missingToNull();
315315
assertEquals("user:null",

tests/src/test/java/io/jooby/FeaturedTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ public void multipartFromWorker() {
530530
});
531531

532532
app.post("/multipart", ctx -> {
533-
return ctx.multipart().toMap();
533+
return ctx.multipart().toMultimap();
534534
});
535535
}).ready(client -> {
536536
client.post("/f", new MultipartBody.Builder()

0 commit comments

Comments
 (0)