Skip to content

Commit fbe0ff3

Browse files
committed
Value API: refactor + context dependency
- Add context field to Value API - Moves convert code to Context.convert - Normalize Value.to(Type), now body.to(Type) also works
1 parent 6dbc93b commit fbe0ff3

File tree

69 files changed

+1028
-485
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1028
-485
lines changed

TODO

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
* multiple path params on MVC routes (fix link sync)
2+
* review toString on Value API
3+
* Value vs ValueNode API
14
* tests and coverage
25
* server options from application.conf MUST override hardcoded settings
36
* make reset headers on error configurable

jooby/src/main/java/io/jooby/Body.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111

1212
import javax.annotation.Nonnull;
1313
import java.io.InputStream;
14+
import java.lang.reflect.Type;
1415
import java.nio.channels.ReadableByteChannel;
1516
import java.nio.charset.Charset;
1617
import java.nio.file.Path;
18+
import java.util.List;
1719

1820
/**
1921
* HTTP body value. Allows to access HTTP body as string, byte[], stream, etc..
@@ -72,6 +74,16 @@ public interface Body extends Value {
7274
*/
7375
@Nonnull InputStream stream();
7476

77+
@Nonnull @Override default <T> List<T> toList(@Nonnull Class<T> type) {
78+
return to(Reified.list(type).getType());
79+
}
80+
81+
@Override default @Nonnull <T> T to(@Nonnull Class<T> type) {
82+
return to((Type) type);
83+
}
84+
85+
@Nonnull <T> T to(@Nonnull Type type);
86+
7587
/* **********************************************************************************************
7688
* Factory methods:
7789
* **********************************************************************************************
@@ -82,8 +94,8 @@ public interface Body extends Value {
8294
*
8395
* @return Empty body.
8496
*/
85-
static Body empty() {
86-
return ByteArrayBody.EMPTY;
97+
static Body empty(Context ctx) {
98+
return ByteArrayBody.empty(ctx);
8799
}
88100

89101
/**
@@ -93,8 +105,8 @@ static Body empty() {
93105
* @param size Size in bytes or <code>-1</code>.
94106
* @return A new body.
95107
*/
96-
static @Nonnull Body of(@Nonnull InputStream stream, long size) {
97-
return new InputStreamBody(stream, size);
108+
static @Nonnull Body of(Context ctx, @Nonnull InputStream stream, long size) {
109+
return new InputStreamBody(ctx, stream, size);
98110
}
99111

100112
/**
@@ -103,8 +115,8 @@ static Body empty() {
103115
* @param bytes byte array.
104116
* @return A new body.
105117
*/
106-
static @Nonnull Body of(@Nonnull byte[] bytes) {
107-
return new ByteArrayBody(bytes);
118+
static @Nonnull Body of(Context ctx, @Nonnull byte[] bytes) {
119+
return new ByteArrayBody(ctx, bytes);
108120
}
109121

110122
/**
@@ -113,7 +125,7 @@ static Body empty() {
113125
* @param file File.
114126
* @return A new body.
115127
*/
116-
static @Nonnull Body of(@Nonnull Path file) {
117-
return new FileBody(file);
128+
static @Nonnull Body of(Context ctx, @Nonnull Path file) {
129+
return new FileBody(ctx, file);
118130
}
119131
}

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

Lines changed: 10 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,22 @@
55
*/
66
package io.jooby;
77

8+
import io.jooby.internal.ValueConverters;
9+
import io.jooby.spi.ValueConverter;
10+
811
import javax.annotation.Nonnull;
912
import javax.annotation.Nullable;
1013
import java.io.InputStream;
1114
import java.io.OutputStream;
1215
import java.io.PrintWriter;
16+
import java.lang.reflect.Type;
1317
import java.nio.ByteBuffer;
1418
import java.nio.channels.FileChannel;
1519
import java.nio.channels.ReadableByteChannel;
1620
import java.nio.charset.Charset;
1721
import java.nio.file.Path;
1822
import java.time.Instant;
23+
import java.time.LocalDate;
1924
import java.time.ZoneId;
2025
import java.time.format.DateTimeFormatter;
2126
import java.util.Date;
@@ -85,6 +90,8 @@ public interface Context extends Registry {
8590
*/
8691
@Nonnull Router getRouter();
8792

93+
@Nullable <T> T convert(Value value, Class<T> type);
94+
8895
/*
8996
* **********************************************************************************************
9097
* **** Request methods *************************************************************************
@@ -181,15 +188,6 @@ public interface Context extends Registry {
181188
*/
182189
@Nonnull Value path(@Nonnull String name);
183190

184-
/**
185-
* Convert the {@link #pathMap()} to the given type.
186-
*
187-
* @param type Reified type.
188-
* @param <T> Target type.
189-
* @return Instance of target type.
190-
*/
191-
@Nonnull <T> T path(@Nonnull Reified<T> type);
192-
193191
/**
194192
* Convert the {@link #pathMap()} to the given type.
195193
*
@@ -269,15 +267,6 @@ public interface Context extends Registry {
269267
*/
270268
@Nonnull String queryString();
271269

272-
/**
273-
* Convert the queryString to the given type.
274-
*
275-
* @param type Reified type.
276-
* @param <T> Target type.
277-
* @return Query string converted to target type.
278-
*/
279-
@Nonnull <T> T query(@Nonnull Reified<T> type);
280-
281270
/**
282271
* Convert the queryString to the given type.
283272
*
@@ -455,16 +444,6 @@ public interface Context extends Registry {
455444
*/
456445
@Nonnull Value form(@Nonnull String name);
457446

458-
/**
459-
* Convert formdata to the given type. Only for <code>application/form-url-encoded</code>
460-
* request.
461-
*
462-
* @param type Reified type.
463-
* @param <T> Target type.
464-
* @return Formdata as requested type.
465-
*/
466-
@Nonnull <T> T form(@Nonnull Reified<T> type);
467-
468447
/**
469448
* Convert formdata to the given type. Only for <code>application/form-url-encoded</code>
470449
* request.
@@ -499,17 +478,6 @@ public interface Context extends Registry {
499478
*/
500479
@Nonnull Value multipart(@Nonnull String name);
501480

502-
/**
503-
* Convert multipart data to the given type.
504-
*
505-
* Only for <code>multipart/form-data</code> request.
506-
*
507-
* @param type Reified type.
508-
* @param <T> Target type.
509-
* @return Target value.
510-
*/
511-
@Nonnull <T> T multipart(@Nonnull Reified<T> type);
512-
513481
/**
514482
* Convert multipart data to the given type.
515483
*
@@ -585,17 +553,7 @@ public interface Context extends Registry {
585553
* @param <T> Conversion type.
586554
* @return Instance of conversion type.
587555
*/
588-
@Nonnull <T> T body(@Nonnull Reified<T> type);
589-
590-
/**
591-
* Convert the HTTP body to the given type.
592-
*
593-
* @param type Reified type.
594-
* @param contentType Body content type.
595-
* @param <T> Conversion type.
596-
* @return Instance of conversion type.
597-
*/
598-
@Nonnull <T> T body(@Nonnull Reified<T> type, @Nonnull MediaType contentType);
556+
@Nonnull <T> T body(@Nonnull Class<T> type);
599557

600558
/**
601559
* Convert the HTTP body to the given type.
@@ -604,17 +562,16 @@ public interface Context extends Registry {
604562
* @param <T> Conversion type.
605563
* @return Instance of conversion type.
606564
*/
607-
@Nonnull <T> T body(@Nonnull Class<T> type);
565+
@Nonnull <T> T body(@Nonnull Type type);
608566

609567
/**
610568
* Convert the HTTP body to the given type.
611569
*
612570
* @param type Reified type.
613-
* @param contentType Body content type.
614571
* @param <T> Conversion type.
615572
* @return Instance of conversion type.
616573
*/
617-
@Nonnull <T> T body(@Nonnull Class<T> type, @Nonnull MediaType contentType);
574+
@Nonnull <T> T decode(@Nonnull Type type, @Nonnull MediaType contentType);
618575

619576
/* **********************************************************************************************
620577
* Body MessageDecoder

jooby/src/main/java/io/jooby/DefaultContext.java

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import io.jooby.internal.MissingValue;
1010
import io.jooby.internal.SingleValue;
1111
import io.jooby.internal.UrlParser;
12+
import io.jooby.internal.ValueConverters;
13+
import io.jooby.internal.reflect.$Types;
1214

1315
import javax.annotation.Nonnull;
1416
import javax.annotation.Nullable;
@@ -17,6 +19,7 @@
1719
import java.io.InputStream;
1820
import java.io.OutputStream;
1921
import java.io.PrintWriter;
22+
import java.lang.reflect.Type;
2023
import java.nio.channels.FileChannel;
2124
import java.nio.charset.Charset;
2225
import java.nio.charset.StandardCharsets;
@@ -83,7 +86,7 @@ public interface DefaultContext extends Context {
8386
* @return Flash attribute.
8487
*/
8588
@Override default @Nonnull Value flash(@Nonnull String name) {
86-
return Value.create(name, flash().get(name));
89+
return Value.create(this, name, flash().get(name));
8790
}
8891

8992
@Override default @Nonnull Session session() {
@@ -121,26 +124,22 @@ public interface DefaultContext extends Context {
121124

122125
@Override default @Nonnull Value cookie(@Nonnull String name) {
123126
String value = cookieMap().get(name);
124-
return value == null ? Value.missing(name) : Value.value(name, value);
127+
return value == null ? Value.missing(name) : Value.value(this, name, value);
125128
}
126129

127130
@Override @Nonnull default Value path(@Nonnull String name) {
128131
String value = pathMap().get(name);
129132
return value == null
130133
? new MissingValue(name)
131-
: new SingleValue(name, UrlParser.decodePathSegment(value));
132-
}
133-
134-
@Override @Nonnull default <T> T path(@Nonnull Reified<T> type) {
135-
return path().to(type);
134+
: new SingleValue(this, name, UrlParser.decodePathSegment(value));
136135
}
137136

138137
@Override @Nonnull default <T> T path(@Nonnull Class<T> type) {
139138
return path().to(type);
140139
}
141140

142141
@Override @Nonnull default Value path() {
143-
HashValue path = new HashValue(null);
142+
HashValue path = new HashValue(this, null);
144143
for (Map.Entry<String, String> entry : pathMap().entrySet()) {
145144
path.put(entry.getKey(), entry.getValue());
146145
}
@@ -155,10 +154,6 @@ public interface DefaultContext extends Context {
155154
return query().queryString();
156155
}
157156

158-
@Override @Nonnull default <T> T query(@Nonnull Reified<T> type) {
159-
return query().to(type);
160-
}
161-
162157
@Override @Nonnull default <T> T query(@Nonnull Class<T> type) {
163158
return query().to(type);
164159
}
@@ -244,10 +239,6 @@ public interface DefaultContext extends Context {
244239
return form().get(name);
245240
}
246241

247-
@Override @Nonnull default <T> T form(@Nonnull Reified<T> type) {
248-
return form().to(type);
249-
}
250-
251242
@Override @Nonnull default <T> T form(@Nonnull Class<T> type) {
252243
return form().to(type);
253244
}
@@ -256,10 +247,6 @@ public interface DefaultContext extends Context {
256247
return multipart().get(name);
257248
}
258249

259-
@Override @Nonnull default <T> T multipart(@Nonnull Reified<T> type) {
260-
return multipart().to(type);
261-
}
262-
263250
@Override @Nonnull default <T> T multipart(@Nonnull Class<T> type) {
264251
return multipart().to(type);
265252
}
@@ -307,24 +294,30 @@ public interface DefaultContext extends Context {
307294
throw new TypeMismatchException(name, FileUpload.class);
308295
}
309296

310-
@Override default @Nonnull <T> T body(@Nonnull Reified<T> type) {
311-
return body(type, getRequestType(MediaType.text));
297+
@Override default @Nonnull <T> T body(@Nonnull Class<T> type) {
298+
return body().to(type);
312299
}
313300

314-
@Override default @Nonnull <T> T body(@Nonnull Reified<T> type, @Nonnull MediaType contentType) {
315-
try {
316-
return decoder(contentType).decode(this, type.getType());
317-
} catch (Exception x) {
318-
throw SneakyThrows.propagate(x);
319-
}
301+
@Override default @Nonnull <T> T body(@Nonnull Type type) {
302+
return body().to(type);
320303
}
321304

322-
@Override default @Nonnull <T> T body(@Nonnull Class<T> type) {
323-
return body(type, getRequestType(MediaType.text));
305+
@Override default @Nullable <T> T convert(Value value, Class<T> type) {
306+
T result = ValueConverters.convert(value, type, getRouter().getConverters());
307+
if (result == null) {
308+
throw new TypeMismatchException(value.name(), type);
309+
}
310+
return result;
324311
}
325312

326-
@Override default @Nonnull <T> T body(@Nonnull Class<T> type, @Nonnull MediaType contentType) {
313+
@Override default @Nonnull <T> T decode(@Nonnull Type type, @Nonnull MediaType contentType) {
327314
try {
315+
if (MediaType.text.equals(contentType)) {
316+
T result = ValueConverters.convert(body(), type, getRouter().getConverters());
317+
if (result != null) {
318+
return result;
319+
}
320+
}
328321
return decoder(contentType).decode(this, type);
329322
} catch (Exception x) {
330323
throw SneakyThrows.propagate(x);

jooby/src/main/java/io/jooby/FileUpload.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ public interface FileUpload extends Value {
8383
return new String(bytes(), charset);
8484
}
8585

86+
default @Nonnull @Override <T> T to(@Nonnull Class<T> type) {
87+
if (Path.class == type) {
88+
return (T) this.path();
89+
}
90+
if (FileUpload.class == type) {
91+
return (T) this;
92+
}
93+
throw new TypeMismatchException(name(), type);
94+
}
95+
8696
/**
8797
* Multi-value map with field name as key and file name as values.
8898
*

jooby/src/main/java/io/jooby/Formdata.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public interface Formdata extends Value {
5252
*
5353
* @return Formdata.
5454
*/
55-
static @Nonnull Formdata create() {
56-
return new HashValue(null);
55+
static @Nonnull Formdata create(@Nonnull Context ctx) {
56+
return new HashValue(ctx, null);
5757
}
5858
}

0 commit comments

Comments
 (0)