Skip to content

Commit f7d90a8

Browse files
authored
Media support methods (helidon-io#1905)
* Get method removed from MessageBodyOperators * JSON-P support changed * JSON-B support changed * Jackson support changed * Default support builder added Signed-off-by: David Kral <david.k.kral@oracle.com>
1 parent 4fd2129 commit f7d90a8

28 files changed

Lines changed: 506 additions & 287 deletions

File tree

health/health/src/main/java/io/helidon/health/HealthSupport.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,15 @@
3535
import javax.json.JsonBuilderFactory;
3636
import javax.json.JsonObject;
3737
import javax.json.JsonObjectBuilder;
38+
import javax.json.JsonStructure;
3839

3940
import io.helidon.common.GenericType;
4041
import io.helidon.common.HelidonFeatures;
4142
import io.helidon.common.HelidonFlavor;
4243
import io.helidon.common.http.Http;
4344
import io.helidon.common.reactive.Single;
4445
import io.helidon.config.Config;
45-
import io.helidon.media.jsonp.JsonpBodyWriter;
46+
import io.helidon.media.common.MessageBodyWriter;
4647
import io.helidon.media.jsonp.JsonpSupport;
4748
import io.helidon.webserver.Routing;
4849
import io.helidon.webserver.ServerRequest;
@@ -88,7 +89,7 @@ public final class HealthSupport implements Service {
8889
private final Set<String> excludedHealthChecks;
8990
private final boolean backwardCompatible;
9091
private final CorsEnabledServiceHelper corsEnabledServiceHelper;
91-
private final JsonpBodyWriter jsonpWriter = JsonpSupport.writer();
92+
private final MessageBodyWriter<JsonStructure> jsonpWriter = JsonpSupport.writer();
9293

9394
private HealthSupport(Builder builder) {
9495
this.enabled = builder.enabled;

media/common/src/main/java/io/helidon/media/common/ByteChannelBodyWriter.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
2828
/**
2929
* Message body writer for {@link ReadableByteChannel}.
3030
*/
31-
public final class ByteChannelBodyWriter implements MessageBodyWriter<ReadableByteChannel> {
31+
final class ByteChannelBodyWriter implements MessageBodyWriter<ReadableByteChannel> {
3232

3333
static final RetrySchema DEFAULT_RETRY_SCHEMA = RetrySchema.linear(0, 10, 250);
3434

35+
private static final ByteChannelBodyWriter DEFAULT = new ByteChannelBodyWriter(DEFAULT_RETRY_SCHEMA);
36+
3537
private final ByteChannelToChunks mapper;
3638

3739
/**
@@ -62,20 +64,21 @@ public Publisher<DataChunk> write(Single<? extends ReadableByteChannel> content,
6264
* @param schema retry schema
6365
* @return {@link ReadableByteChannel} message body writer
6466
*/
65-
public static ByteChannelBodyWriter create(RetrySchema schema) {
67+
static ByteChannelBodyWriter create(RetrySchema schema) {
6668
return new ByteChannelBodyWriter(schema);
6769
}
6870

6971
/**
70-
* Create a new instance of {@link ByteChannelBodyWriter}.
72+
* Return an instance of {@link ByteChannelBodyWriter}.
73+
*
7174
* @return {@link ReadableByteChannel} message body writer
7275
*/
73-
public static ByteChannelBodyWriter create() {
74-
return new ByteChannelBodyWriter(DEFAULT_RETRY_SCHEMA);
76+
static ByteChannelBodyWriter create() {
77+
return DEFAULT;
7578
}
7679

7780
/**
78-
* Implementation of {@link MultiMapper} that converts a
81+
* Implementation of {@link Mapper} that converts a
7982
* {@link ReadableByteChannel} to a publisher of {@link DataChunk}.
8083
*/
8184
private static final class ByteChannelToChunks implements Mapper<ReadableByteChannel, Publisher<DataChunk>> {

media/common/src/main/java/io/helidon/media/common/CharSequenceBodyWriter.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
/**
2828
* Writer for {@code CharSequence}.
2929
*/
30-
public final class CharSequenceBodyWriter implements MessageBodyWriter<CharSequence> {
30+
final class CharSequenceBodyWriter implements MessageBodyWriter<CharSequence> {
31+
32+
private static final CharSequenceBodyWriter DEFAULT = new CharSequenceBodyWriter();
3133

3234
/**
3335
* Enforce the use of {@link #create()}.
@@ -50,11 +52,12 @@ public Publisher<DataChunk> write(Single<? extends CharSequence> content,
5052
}
5153

5254
/**
53-
* Create a new instance of {@link CharSequenceBodyWriter}.
55+
* Return an instance of {@link CharSequenceBodyWriter}.
56+
*
5457
* @return {@link CharSequence} message body writer.
5558
*/
56-
public static CharSequenceBodyWriter create() {
57-
return new CharSequenceBodyWriter();
59+
static CharSequenceBodyWriter create() {
60+
return DEFAULT;
5861
}
5962

6063
private static final class CharSequenceToChunks implements Mapper<CharSequence, Publisher<DataChunk>> {

media/common/src/main/java/io/helidon/media/common/ContentReaders.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ public static Reader<byte[]> byteArrayReader() {
120120
* {@link InputStream#read()}) block.
121121
*
122122
* @return a input stream content reader
123+
* @deprecated use {@link DefaultMediaSupport#inputStreamReader()}
123124
*/
125+
@Deprecated(since = "2.0.0")
124126
public static Reader<InputStream> inputStreamReader() {
125127
return (publisher, clazz) -> CompletableFuture.completedFuture(new DataChunkInputStream(publisher));
126128
}

media/common/src/main/java/io/helidon/media/common/DefaultMediaSupport.java

Lines changed: 166 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,195 @@
1515
*/
1616
package io.helidon.media.common;
1717

18+
import java.io.File;
19+
import java.io.InputStream;
20+
import java.nio.channels.ReadableByteChannel;
21+
import java.nio.file.Path;
1822
import java.util.Collection;
1923
import java.util.List;
24+
import java.util.Objects;
25+
26+
import io.helidon.common.reactive.RetrySchema;
27+
import io.helidon.config.Config;
2028

2129
/**
2230
* MediaSupport which registers default readers and writers to the contexts.
2331
*/
2432
public class DefaultMediaSupport implements MediaSupport {
2533

26-
private final boolean includeStackTraces;
34+
private final ByteChannelBodyWriter byteChannelBodyWriter;
35+
private final ThrowableBodyWriter throwableBodyWriter;
2736

28-
private DefaultMediaSupport(boolean includeStackTraces) {
29-
this.includeStackTraces = includeStackTraces;
37+
private DefaultMediaSupport(Builder builder) {
38+
byteChannelBodyWriter = ByteChannelBodyWriter.create(builder.schema);
39+
throwableBodyWriter = ThrowableBodyWriter.create(builder.includeStackTraces);
3040
}
3141

3242
/**
3343
* Creates new instance of {@link DefaultMediaSupport}.
3444
*
35-
* @param includeStackTraces include stack traces
3645
* @return new service instance
3746
*/
38-
public static DefaultMediaSupport create(boolean includeStackTraces) {
39-
return new DefaultMediaSupport(includeStackTraces);
47+
public static DefaultMediaSupport create() {
48+
return builder().build();
49+
}
50+
51+
/**
52+
* Return new {@link Builder} of the {@link DefaultMediaSupport}.
53+
*
54+
* @return default media support builder
55+
*/
56+
public static Builder builder() {
57+
return new Builder();
58+
}
59+
60+
/**
61+
* Return {@link String} reader instance.
62+
*
63+
* @return {@link String} reader
64+
*/
65+
public static MessageBodyReader<String> stringReader() {
66+
return StringBodyReader.create();
67+
}
68+
69+
/**
70+
* Return {@link InputStream} reader instance.
71+
*
72+
* @return {@link InputStream} reader
73+
*/
74+
public static MessageBodyReader<InputStream> inputStreamReader() {
75+
return InputStreamBodyReader.create();
76+
}
77+
78+
/**
79+
* Return {@link CharSequence} writer instance.
80+
*
81+
* @return {@link CharSequence} writer
82+
*/
83+
public static MessageBodyWriter<CharSequence> charSequenceWriter() {
84+
return CharSequenceBodyWriter.create();
85+
}
86+
87+
/**
88+
* Create a new instance of {@link ReadableByteChannel} writer.
89+
*
90+
* @return {@link ReadableByteChannel} writer
91+
*/
92+
public static MessageBodyWriter<ReadableByteChannel> byteChannelWriter() {
93+
return ByteChannelBodyWriter.create();
94+
}
95+
96+
/**
97+
* Return new {@link ReadableByteChannel} writer instance with specific {@link RetrySchema}.
98+
*
99+
* @param schema retry schema
100+
* @return {@link ReadableByteChannel} writer
101+
*/
102+
public static MessageBodyWriter<ReadableByteChannel> byteChannelWriter(RetrySchema schema) {
103+
return ByteChannelBodyWriter.create(schema);
104+
}
105+
106+
/**
107+
* Return {@link Path} writer instance.
108+
*
109+
* @return {@link Path} writer
110+
*/
111+
public static MessageBodyWriter<Path> pathWriter() {
112+
return PathBodyWriter.create();
113+
}
114+
115+
/**
116+
* Return {@link File} writer instance.
117+
*
118+
* @return {@link File} writer
119+
*/
120+
public static MessageBodyWriter<File> fileWriter() {
121+
return FileBodyWriter.create();
122+
}
123+
124+
/**
125+
* Return {@link Throwable} writer instance.
126+
*
127+
* @param includeStackTraces whether stack traces are to be written
128+
* @return {@link Throwable} writer
129+
*/
130+
public static MessageBodyWriter<Throwable> throwableWriter(boolean includeStackTraces) {
131+
return ThrowableBodyWriter.create(includeStackTraces);
40132
}
41133

42134
@Override
43135
public Collection<MessageBodyReader<?>> readers() {
44-
return List.of(StringBodyReader.create(),
45-
InputStreamBodyReader.create());
136+
return List.of(stringReader(),
137+
inputStreamReader());
46138
}
47139

48140
@Override
49141
public Collection<MessageBodyWriter<?>> writers() {
50-
return List.of(CharSequenceBodyWriter.create(),
51-
ByteChannelBodyWriter.create(),
52-
PathBodyWriter.create(),
53-
FileBodyWriter.create(),
54-
ThrowableBodyWriter.create(includeStackTraces));
142+
return List.of(charSequenceWriter(),
143+
byteChannelBodyWriter,
144+
pathWriter(),
145+
fileWriter(),
146+
throwableBodyWriter);
147+
}
148+
149+
/**
150+
* Default media support builder.
151+
*/
152+
public static class Builder implements io.helidon.common.Builder<DefaultMediaSupport> {
153+
154+
private boolean includeStackTraces = false;
155+
private RetrySchema schema = ByteChannelBodyWriter.DEFAULT_RETRY_SCHEMA;
156+
157+
private Builder() {
158+
}
159+
160+
@Override
161+
public DefaultMediaSupport build() {
162+
return new DefaultMediaSupport(this);
163+
}
164+
165+
/**
166+
* Whether stack traces should be included in response.
167+
*
168+
* @param includeStackTraces include stack trace
169+
* @return updated builder instance
170+
*/
171+
public Builder includeStackTraces(boolean includeStackTraces) {
172+
this.includeStackTraces = includeStackTraces;
173+
return this;
174+
}
175+
176+
/**
177+
* Set specific {@link RetrySchema} to the byte channel.
178+
*
179+
* @param schema retry schema
180+
* @return updated builder instance
181+
*/
182+
public Builder byteChannelRetrySchema(RetrySchema schema) {
183+
this.schema = Objects.requireNonNull(schema);
184+
return this;
185+
}
186+
187+
/**
188+
* Configures this {@link DefaultMediaSupport.Builder} from the supplied {@link Config}.
189+
* <table class="config">
190+
* <caption>Optional configuration parameters</caption>
191+
* <tr>
192+
* <th>key</th>
193+
* <th>description</th>
194+
* </tr>
195+
* <tr>
196+
* <td>include-stack-traces</td>
197+
* <td>Whether stack traces should be included in response</td>
198+
* </tr>
199+
* </table>
200+
*
201+
* @param config media support config
202+
* @return updated builder instance
203+
*/
204+
public Builder config(Config config) {
205+
config.get("include-stack-traces").asBoolean().ifPresent(this::includeStackTraces);
206+
return this;
207+
}
55208
}
56209
}

media/common/src/main/java/io/helidon/media/common/FileBodyWriter.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
/**
3636
* Message body writer for {@link File}.
3737
*/
38-
public final class FileBodyWriter implements MessageBodyWriter<File> {
38+
final class FileBodyWriter implements MessageBodyWriter<File> {
39+
40+
private static final FileBodyWriter DEFAULT = new FileBodyWriter();
3941

4042
/**
4143
* Enforces the use of {@link #create()}.
@@ -56,11 +58,12 @@ public Publisher<DataChunk> write(Single<? extends File> content,
5658
}
5759

5860
/**
59-
* Create a new {@link FileBodyWriter} instance.
61+
* Return an instance of {@link FileBodyWriter}.
62+
*
6063
* @return {@link File} message body writer.
6164
*/
62-
public static FileBodyWriter create() {
63-
return new FileBodyWriter();
65+
static FileBodyWriter create() {
66+
return DEFAULT;
6467
}
6568

6669
/**

media/common/src/main/java/io/helidon/media/common/InputStreamBodyReader.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
/**
2626
* Message body reader for {@link InputStream}.
2727
*/
28-
public class InputStreamBodyReader implements MessageBodyReader<InputStream> {
28+
class InputStreamBodyReader implements MessageBodyReader<InputStream> {
29+
30+
private static final InputStreamBodyReader DEFAULT = new InputStreamBodyReader();
2931

3032
/**
3133
* Enforce the use of {@link #create()}.
@@ -35,7 +37,11 @@ private InputStreamBodyReader() {
3537

3638
@Override
3739
public PredicateResult accept(GenericType<?> type, MessageBodyReaderContext context) {
38-
return PredicateResult.supports(InputStream.class, type);
40+
if (InputStream.class.equals(type.rawType())
41+
|| DataChunkInputStream.class.equals(type.rawType())) {
42+
return PredicateResult.SUPPORTED;
43+
}
44+
return PredicateResult.NOT_SUPPORTED;
3945
}
4046

4147
@Override
@@ -47,10 +53,11 @@ public <U extends InputStream> Single<U> read(Publisher<DataChunk> publisher, Ge
4753
}
4854

4955
/**
50-
* Create a new instance of {@link InputStreamBodyReader}.
56+
* Return an instance of {@link InputStreamBodyReader}.
57+
*
5158
* @return {@link InputStream} message body reader.
5259
*/
53-
public static InputStreamBodyReader create() {
54-
return new InputStreamBodyReader();
60+
static InputStreamBodyReader create() {
61+
return DEFAULT;
5562
}
5663
}

0 commit comments

Comments
 (0)