Skip to content

Commit 4508695

Browse files
authored
Update of JSON media supports (helidon-io#11234)
* Update media supports - consistent approach to analysis of media types - consistent approach in handling charsets - consistent approach in configuring supports - added methods with `io.helidon.config.Conifg` and deprecated old ones - now using service registry instead of service loader in GSON (backward compatible) - media types are now validated against the `Accept` header of request (for server responses) - content type and accepted types are now configurable for all JSON supports - failure to parse charset now returns 415 - Use an explicit media support in metrics, to avoid problems when JSON-P support is not added by users. As part of testing, I found out we have a lot of warnings for generated builders, as they use deprecated Config, added suppress warnings annotation.
1 parent c0e8234 commit 4508695

71 files changed

Lines changed: 1741 additions & 952 deletions

File tree

Some content is hidden

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

builder/codegen/src/main/java/io/helidon/builder/codegen/BuilderCodegen.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,8 @@ private void generatePrototype(RoundContext ctx,
705705
.copyright(CodegenUtil.copyright(GENERATOR,
706706
blueprint.typeName(),
707707
prototype))
708+
// adding suppress warnings for config - once we remove helidon-common-config, we can remove this
709+
.addAnnotation(Annotation.create(SuppressWarnings.class, "removal"))
708710
.accessModifier(prototypeInfo.accessModifier());
709711

710712
typeArguments.forEach(classModel::addGenericArgument);

http/http/src/main/java/io/helidon/http/HeaderNames.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, 2025 Oracle and/or its affiliates.
2+
* Copyright (c) 2023, 2026 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,12 +35,14 @@ public final class HeaderNames {
3535
public static final HeaderName ACCEPT = HeaderNameEnum.ACCEPT;
3636
/**
3737
* The {@value} header name.
38-
* Character sets that are acceptedTypes.
38+
* This header is no longer sent by browsers, and it should be ignored by servers.
39+
* Character sets that are accepted.
3940
*/
4041
public static final String ACCEPT_CHARSET_NAME = Strings.ACCEPT_CHARSET_NAME;
4142
/**
4243
* The {@value #ACCEPT_CHARSET_NAME} header name.
43-
* Character sets that are acceptedTypes.
44+
* This header is no longer sent by browsers, and it should be ignored by servers.
45+
* Character sets that are accepted.
4446
*/
4547
public static final HeaderName ACCEPT_CHARSET = HeaderNameEnum.ACCEPT_CHARSET;
4648
/**

http/http/src/main/java/io/helidon/http/HttpMediaTypes.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023 Oracle and/or its affiliates.
2+
* Copyright (c) 2023, 2026 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,14 @@ public final class HttpMediaTypes {
3131
.mediaType(MediaTypes.APPLICATION_JSON)
3232
.charset("UTF-8")
3333
.build();
34+
35+
/**
36+
* application/json media type with no explicit charset.
37+
*/
38+
public static final HttpMediaType JSON = HttpMediaType.builder()
39+
.mediaType(MediaTypes.APPLICATION_JSON)
40+
.build();
41+
3442
/**
3543
* Predicate to test if {@link io.helidon.common.media.type.MediaType} is {@code application/json} or has {@code json} suffix.
3644
*/

http/media/gson/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@
4242
<groupId>io.helidon.common</groupId>
4343
<artifactId>helidon-common-config</artifactId>
4444
</dependency>
45+
<dependency>
46+
<groupId>io.helidon.common</groupId>
47+
<artifactId>helidon-common-types</artifactId>
48+
</dependency>
49+
<dependency>
50+
<groupId>io.helidon.service</groupId>
51+
<artifactId>helidon-service-registry</artifactId>
52+
</dependency>
4553
<dependency>
4654
<groupId>io.helidon.config</groupId>
4755
<artifactId>helidon-config</artifactId>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2026 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.helidon.http.media.gson;
18+
19+
import java.util.Map;
20+
import java.util.function.Consumer;
21+
22+
import io.helidon.builder.api.Prototype;
23+
24+
import com.google.gson.Gson;
25+
import com.google.gson.GsonBuilder;
26+
27+
final class GsonConfigSupport {
28+
private GsonConfigSupport() {
29+
}
30+
31+
static class Decorator implements Prototype.BuilderDecorator<GsonSupportConfig.BuilderBase<?, ?>> {
32+
private static final Gson GSON = new GsonBuilder().create();
33+
private static final Map<String, Consumer<GsonBuilder>> BOOLEAN_PROPERTIES;
34+
35+
static {
36+
BOOLEAN_PROPERTIES = Map.of("pretty-printing",
37+
GsonBuilder::setPrettyPrinting,
38+
"disable-html-escaping",
39+
GsonBuilder::disableHtmlEscaping,
40+
"disable-inner-class-serialization",
41+
GsonBuilder::disableInnerClassSerialization,
42+
"disable-jdk-unsafe",
43+
GsonBuilder::disableJdkUnsafe,
44+
"enable-complex-map-key-serialization",
45+
GsonBuilder::enableComplexMapKeySerialization,
46+
"exclude-fields-without-expose-annotation",
47+
GsonBuilder::excludeFieldsWithoutExposeAnnotation,
48+
"generate-non-executable-json",
49+
GsonBuilder::generateNonExecutableJson,
50+
"serialize-special-floating-point-values",
51+
GsonBuilder::serializeSpecialFloatingPointValues,
52+
"lenient",
53+
GsonBuilder::setLenient,
54+
"serialize-nulls",
55+
GsonBuilder::serializeNulls);
56+
}
57+
58+
@Override
59+
public void decorate(GsonSupportConfig.BuilderBase<?, ?> target) {
60+
if (target.gson().isEmpty()) {
61+
if (target.properties().isEmpty() && target.typeAdapterFactories().isEmpty()) {
62+
target.gson(GSON);
63+
} else {
64+
GsonBuilder builder = new GsonBuilder();
65+
target.properties()
66+
.entrySet()
67+
.stream()
68+
.filter(Map.Entry::getValue)
69+
.filter(entry -> BOOLEAN_PROPERTIES.containsKey(entry.getKey()))
70+
.forEach(entry -> BOOLEAN_PROPERTIES.get(entry.getKey()).accept(builder));
71+
target.typeAdapterFactories()
72+
.forEach(builder::registerTypeAdapterFactory);
73+
target.gson(builder.create());
74+
}
75+
}
76+
}
77+
}
78+
}

http/media/gson/src/main/java/io/helidon/http/media/gson/GsonMediaSupportProvider.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2025 Oracle and/or its affiliates.
2+
* Copyright (c) 2025, 2026 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
1616
package io.helidon.http.media.gson;
1717

1818
import io.helidon.common.Weighted;
19-
import io.helidon.common.config.Config;
19+
import io.helidon.config.Config;
2020
import io.helidon.http.media.MediaSupport;
2121
import io.helidon.http.media.spi.MediaSupportProvider;
2222

@@ -35,12 +35,13 @@ public GsonMediaSupportProvider() {
3535

3636
@Override
3737
public String configKey() {
38-
return "gson";
38+
return GsonSupport.ID;
3939
}
4040

41+
@SuppressWarnings("removal")
4142
@Override
42-
public MediaSupport create(Config config, String name) {
43-
return GsonSupport.create(config, name);
43+
public MediaSupport create(io.helidon.common.config.Config config, String name) {
44+
return GsonSupport.create(Config.config(config), name);
4445
}
4546

4647
@Override

http/media/gson/src/main/java/io/helidon/http/media/gson/GsonReader.java

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2025 Oracle and/or its affiliates.
2+
* Copyright (c) 2025, 2026 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,20 +15,16 @@
1515
*/
1616
package io.helidon.http.media.gson;
1717

18-
1918
import java.io.InputStream;
2019
import java.io.InputStreamReader;
21-
import java.nio.charset.Charset;
22-
import java.nio.charset.StandardCharsets;
2320

2421
import io.helidon.common.GenericType;
2522
import io.helidon.http.Headers;
26-
import io.helidon.http.HttpMediaType;
27-
import io.helidon.http.media.EntityReader;
23+
import io.helidon.http.media.EntityReaderBase;
2824

2925
import com.google.gson.Gson;
3026

31-
class GsonReader<T> implements EntityReader<T> {
27+
class GsonReader<T> extends EntityReaderBase<T> {
3228
private final Gson gson;
3329

3430
GsonReader(Gson gson) {
@@ -44,11 +40,4 @@ public T read(GenericType<T> type, InputStream stream, Headers headers) {
4440
public T read(GenericType<T> type, InputStream stream, Headers requestHeaders, Headers responseHeaders) {
4541
return gson.fromJson(new InputStreamReader(stream, contentTypeCharset(responseHeaders)), type.type());
4642
}
47-
48-
private Charset contentTypeCharset(Headers headers) {
49-
return headers.contentType()
50-
.flatMap(HttpMediaType::charset)
51-
.map(Charset::forName)
52-
.orElse(StandardCharsets.UTF_8);
53-
}
5443
}

0 commit comments

Comments
 (0)