Skip to content

Commit a84fd42

Browse files
4.x - OpenAPI updates (#7669)
* OpenAPI updates. - Minimalistic SE OpenAPI support with SPI to implement the MicroProfile support and OpenAPI UI - Make openapi a multi-module with two sub-modules: openapi and openapi-ui - Add openapi/tests and move gh-5792 from tests/integration - Re-enabled test, make it strictly a test (not an app) and use version.lib.snakeyaml to override the SnakeYAML version - Created OpenApiFormat to formalize what was before OpenApiFeature.OpenAPIMediaType - Microprofile OpenAPI refactorings: - MPOpenAPIBuilder into FilteredIndexViewsBuilder as a utility to create List<FilteredIndexView> - MpOpenApiManager implements OpenApiManager using SmallRye OpenAPI (what was before in MpOpenApiFeature - Prefix utility classes with OpenApi: - ParserHelper -> OpenApiParser - Serializer -> OpenApiSerializer - Renamed HelidonAnnotationScannerExtension to JsonpAnnotationScannerExtension to remove 'Helidon' from the class name - Renamed tests to use Test as a suffix instead of prefix - Updated examples/openapi to remove the in-memory model related features (i.e. reader, filter) - Renamed examples/microprofile/openapi-basic to examples/microprofile/openapi (to be symetrical with SE) - Updated tests to use new testing patterns (i.e. helidon-microprofile-testing-junit5 for MP and helidon-webserver-testing-junit5 for SE) - Generated config docs for openapi/openapi, openapi/openapi-ui, microprofile/openapi (Removed old files) Fixes #7247 (SE OpenAPI static file support) Fixes #7240 (Fix gh-5792 integration test) Fixes #6130 (Port OpenAPI UI integration to 4.x) Fixes #7643 (OpenAPI parsing fails to handle default in some cases) Fixes #7668 (Routing path with optional sequence not supported) * Update MapMatcher javadoc * Incorporate review feedback: - Use FQN the provide statement in openapi/openapi-ui/src/main/java/module-info.java - Update META-INF/openapi.yml
1 parent 84e0d37 commit a84fd42

File tree

135 files changed

+5991
-5825
lines changed

Some content is hidden

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

135 files changed

+5991
-5825
lines changed

bom/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,11 @@
910910
<artifactId>helidon-openapi</artifactId>
911911
<version>${helidon.version}</version>
912912
</dependency>
913+
<dependency>
914+
<groupId>io.helidon.openapi</groupId>
915+
<artifactId>helidon-openapi-ui</artifactId>
916+
<version>${helidon.version}</version>
917+
</dependency>
913918
<dependency>
914919
<groupId>io.helidon.microprofile.openapi</groupId>
915920
<artifactId>helidon-microprofile-openapi</artifactId>
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* Copyright (c) 2023 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+
package io.helidon.common.testing.junit5;
17+
18+
import java.util.ArrayList;
19+
import java.util.Iterator;
20+
import java.util.List;
21+
import java.util.Map;
22+
23+
import org.hamcrest.Description;
24+
import org.hamcrest.Matcher;
25+
import org.hamcrest.TypeSafeMatcher;
26+
27+
/**
28+
* Hamcrest matchers for {@link java.util.Map}.
29+
*/
30+
public final class MapMatcher {
31+
private MapMatcher() {
32+
}
33+
34+
/**
35+
* A matcher that performs {@link java.util.Map} deep equality.
36+
* <p>
37+
* Usage example:
38+
* <pre>
39+
* assertThat(actualMap, mapEqualTo(expectedMap));
40+
* </pre>
41+
*
42+
* This method targets trees implemented using {@link java.util.Map} where values of type {@link java.util.Map}
43+
* are considered tree nodes, and values of any other type are considered leaf nodes.
44+
* <p>
45+
* The deep-equality is performed by diffing a flat string representation of each map. If the diff yields no differences,
46+
* the maps are considered deeply equal.
47+
* <p>
48+
* The entries are compared using strings, both keys and leaf nodes must implement {@link Object#toString()}.
49+
*
50+
* @param expected expected map
51+
* @param <K> type of the map keys
52+
* @param <V> type of the map values
53+
* @return matcher validating the {@link java.util.Map} is deeply equal
54+
*/
55+
public static <K, V> Matcher<Map<K, V>> mapEqualTo(Map<K, V> expected) {
56+
return new DiffMatcher<>(expected);
57+
}
58+
59+
private static final class DiffMatcher<K, V> extends TypeSafeMatcher<Map<K, V>> {
60+
61+
private final Map<K, V> expected;
62+
private volatile Map<K, V> actual;
63+
private volatile List<Diff> diffs;
64+
65+
private DiffMatcher(Map<K, V> expected) {
66+
this.expected = expected;
67+
}
68+
69+
@Override
70+
protected boolean matchesSafely(Map<K, V> actual) {
71+
this.actual = actual;
72+
this.diffs = diffs(expected, actual);
73+
return diffs.isEmpty();
74+
}
75+
76+
@Override
77+
public void describeTo(Description description) {
78+
description.appendText("deep map equality");
79+
}
80+
81+
@Override
82+
protected void describeMismatchSafely(Map<K, V> item, Description mismatchDescription) {
83+
List<Diff> diffs = actual == item ? this.diffs : diffs(expected, item);
84+
mismatchDescription.appendText("found differences" + System.lineSeparator())
85+
.appendText(String.join(System.lineSeparator(), diffs.stream().map(Diff::toString).toList()));
86+
}
87+
88+
private static List<Diff> diffs(Map<?, ?> left, Map<?, ?> right) {
89+
List<Diff> diffs = new ArrayList<>();
90+
Iterator<Map.Entry<String, String>> leftEntries = flattenEntries(left, "").iterator();
91+
Iterator<Map.Entry<String, String>> rightEntries = flattenEntries(right, "").iterator();
92+
while (true) {
93+
boolean hasLeft = leftEntries.hasNext();
94+
boolean hasRight = rightEntries.hasNext();
95+
if (hasLeft && hasRight) {
96+
Map.Entry<String, String> leftEntry = leftEntries.next();
97+
Map.Entry<String, String> rightEntry = rightEntries.next();
98+
if (!leftEntry.equals(rightEntry)) {
99+
diffs.add(new Diff(leftEntry, rightEntry));
100+
}
101+
} else if (hasLeft) {
102+
diffs.add(new Diff(leftEntries.next(), null));
103+
} else if (hasRight) {
104+
diffs.add(new Diff(null, rightEntries.next()));
105+
} else {
106+
return diffs;
107+
}
108+
}
109+
}
110+
111+
private static List<Map.Entry<String, String>> flattenEntries(Map<?, ?> map, String prefix) {
112+
List<Map.Entry<String, String>> result = new ArrayList<>();
113+
for (Map.Entry<?, ?> entry : map.entrySet()) {
114+
if (entry.getValue() instanceof Map<?, ?> node) {
115+
result.addAll(flattenEntries(node, prefix + entry.getKey() + "."));
116+
} else {
117+
result.add(Map.entry(prefix + entry.getKey(), entry.getValue().toString()));
118+
}
119+
}
120+
result.sort(Map.Entry.comparingByKey());
121+
return result;
122+
}
123+
124+
private record Diff(Map.Entry<String, String> left, Map.Entry<String, String> right) {
125+
126+
@Override
127+
public String toString() {
128+
if (left == null && right != null) {
129+
return "ADDED >> " + right;
130+
}
131+
if (left != null && right == null) {
132+
return "REMOVED << " + left;
133+
}
134+
if (left != null) {
135+
return "ADDED >> " + left + System.lineSeparator() + "REMOVED << " + right;
136+
}
137+
return "?";
138+
}
139+
}
140+
}
141+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2023 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.common.testing;
18+
19+
import java.util.Map;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import static io.helidon.common.testing.junit5.MapMatcher.mapEqualTo;
24+
import static org.hamcrest.Matchers.is;
25+
import static org.hamcrest.MatcherAssert.assertThat;
26+
import static org.hamcrest.Matchers.not;
27+
28+
class MapMatcherTest {
29+
30+
@Test
31+
void testIsMapEqual() {
32+
assertThat(Map.of("foo", "bar"), is(mapEqualTo(Map.of("foo", "bar"))));
33+
assertThat(Map.of("bar", "foo"), is(not(mapEqualTo(Map.of("foo", "bar")))));
34+
35+
assertThat(Map.of("foo", Map.of("bar", Map.of("bob", "alice"))),
36+
is(mapEqualTo(Map.of("foo", Map.of("bar", Map.of("bob", "alice"))))));
37+
38+
assertThat(Map.of("foo", Map.of("bar", Map.of("bob", "alice"))),
39+
is(not(mapEqualTo(Map.of("foo", Map.of("bar", Map.of("bob", "not-alice")))))));
40+
41+
assertThat(Map.of("foo", "bar", "bob", "alice"), is(mapEqualTo(Map.of("bob", "alice", "foo", "bar"))));
42+
}
43+
}

docs/config/config_reference.adoc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ The following section lists all configurable types in Helidon.
2828
- xref:{rootdir}/config/io_helidon_common_configurable_AllowList.adoc[AllowList (common.configurable)]
2929
- xref:{rootdir}/config/io_helidon_faulttolerance_Async.adoc[Async (faulttolerance)]
3030
- xref:{rootdir}/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc[BaseBuilder (security.providers.oidc.common)]
31-
- xref:{rootdir}/config/io_helidon_openapi_OpenApiUi_Builder.adoc[Builder (openapi.OpenApiUi)]
3231
- xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc[Builder (security.providers.idcs.mapper.IdcsRoleMapperProviderBase)]
3332
- xref:{rootdir}/config/io_helidon_webserver_servicecommon_HelidonFeatureSupport_Builder.adoc[Builder (webserver.servicecommon.HelidonFeatureSupport)]
3433
- xref:{rootdir}/config/io_helidon_faulttolerance_Bulkhead.adoc[Bulkhead (faulttolerance)]
@@ -79,7 +78,8 @@ The following section lists all configurable types in Helidon.
7978
- xref:{rootdir}/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc[ScheduledThreadPoolSupplier (common.configurable)]
8079
- xref:{rootdir}/config/io_helidon_metrics_api_ScopeConfig.adoc[ScopeConfig (metrics.api)]
8180
- xref:{rootdir}/config/io_helidon_metrics_api_ScopingConfig.adoc[ScopingConfig (metrics.api)]
82-
- xref:{rootdir}/config/io_helidon_openapi_SeOpenApiFeature.adoc[SeOpenApiFeature (openapi)]
81+
- xref:{rootdir}/config/io_helidon_openapi_OpenApiFeature.adoc[OpenApiFeature (openapi)]
82+
- xref:{rootdir}/config/io_helidon_openapi_ui_OpenApiUi.adoc[OpenApiUi (openapi.ui)]
8383
- xref:{rootdir}/config/io_helidon_security_Security.adoc[Security (security)]
8484
- xref:{rootdir}/config/io_helidon_security_SecurityTime.adoc[SecurityTime (security)]
8585
- xref:{rootdir}/config/io_helidon_microprofile_server_Server.adoc[Server (microprofile.server)]
@@ -99,3 +99,4 @@ The following section lists all configurable types in Helidon.
9999
- xref:{rootdir}/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc[ZipkinTracerBuilder (tracing.providers.zipkin)]
100100
- xref:{rootdir}/config/io_opentracing_Tracer.adoc[io_opentracing_Tracer]
101101
- xref:{rootdir}/config/org_eclipse_microprofile_config_Config.adoc[org_eclipse_microprofile_config_Config]
102+
- xref:{rootdir}/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc[MpOpenApiManagerConfig (microprofile.openapi)]
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
3+
Copyright (c) 2023 Oracle and/or its affiliates.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
17+
///////////////////////////////////////////////////////////////////////////////
18+
19+
ifndef::rootdir[:rootdir: {docdir}/..]
20+
:description: Configuration of io.helidon.microprofile.openapi.MpOpenApiManagerConfig
21+
:keywords: helidon, config, io.helidon.microprofile.openapi.MpOpenApiManagerConfig
22+
:basic-table-intro: The table below lists the configuration keys that configure io.helidon.microprofile.openapi.MpOpenApiManagerConfig
23+
include::{rootdir}/includes/attributes.adoc[]
24+
25+
= MpOpenApiManagerConfig (microprofile.openapi) Configuration
26+
27+
// tag::config[]
28+
29+
30+
Type: link:{javadoc-base-url}/io.helidon.microprofile.openapi/io/helidon/microprofile/openapi/MpOpenApiManagerConfig.html[io.helidon.microprofile.openapi.MpOpenApiManagerConfig]
31+
32+
33+
34+
35+
== Configuration options
36+
37+
38+
39+
.Optional configuration options
40+
[cols="3,3a,2,5a"]
41+
42+
|===
43+
|key |type |default value |description
44+
45+
|`mp.openapi.extensions.helidon.use-jaxrs-semantics` |boolean |{nbsp} |If `true` and the `jakarta.ws.rs.core.Application` class returns a non-empty set, endpoints defined by
46+
other resources are not included in the OpenAPI document.
47+
48+
@return `true` if enabled, `false` otherwise
49+
50+
|===
51+
52+
// end::config[]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
3+
Copyright (c) 2023 Oracle and/or its affiliates.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
17+
///////////////////////////////////////////////////////////////////////////////
18+
19+
ifndef::rootdir[:rootdir: {docdir}/..]
20+
:description: Configuration of io.helidon.openapi.OpenApiFeature
21+
:keywords: helidon, config, io.helidon.openapi.OpenApiFeature
22+
:basic-table-intro: The table below lists the configuration keys that configure io.helidon.openapi.OpenApiFeature
23+
include::{rootdir}/includes/attributes.adoc[]
24+
25+
= OpenApiFeature (openapi) Configuration
26+
27+
// tag::config[]
28+
29+
30+
Type: link:{javadoc-base-url}/io.helidon.openapi/io/helidon/openapi/OpenApiFeature.html[io.helidon.openapi.OpenApiFeature]
31+
32+
33+
This is a standalone configuration type, prefix from configuration root: `openapi`
34+
35+
36+
37+
== Configuration options
38+
39+
40+
41+
.Optional configuration options
42+
[cols="3,3a,2,5a"]
43+
44+
|===
45+
|key |type |default value |description
46+
47+
|`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |CORS config.
48+
49+
@return CORS config
50+
|`enabled` |boolean |`true` |Sets whether the feature should be enabled.
51+
52+
@return `true` if enabled, `false` otherwise
53+
|`manager` |io.helidon.openapi.OpenApiManager (service provider interface) |{nbsp} |OpenAPI manager.
54+
55+
@return the OpenAPI manager
56+
|`services` |io.helidon.openapi.OpenApiService[&#93; (service provider interface) |{nbsp} |OpenAPI services.
57+
58+
@return the OpenAPI services
59+
|`static-file` |string |{nbsp} |Path of the static OpenAPI document file. Default types are `json`, `yaml`, and `yml`.
60+
61+
@return location of the static OpenAPI document file
62+
|`web-context` |string |`/openapi` |Web context path for the OpenAPI endpoint.
63+
64+
@return webContext to use
65+
66+
|===
67+
68+
// end::config[]

docs/config/io_helidon_openapi_OpenApiUi_Builder.adoc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
///////////////////////////////////////////////////////////////////////////////
22

3-
Copyright (c) 2023 Oracle and/or its affiliates.
3+
Copyright (c) 2022, 2023 Oracle and/or its affiliates.
44

55
Licensed under the Apache License, Version 2.0 (the "License");
66
you may not use this file except in compliance with the License.
@@ -17,17 +17,17 @@
1717
///////////////////////////////////////////////////////////////////////////////
1818
1919
ifndef::rootdir[:rootdir: {docdir}/..]
20-
:description: Configuration of io.helidon.openapi.OpenApiUi.Builder
21-
:keywords: helidon, config, io.helidon.openapi.OpenApiUi.Builder
22-
:basic-table-intro: The table below lists the configuration keys that configure io.helidon.openapi.OpenApiUi.Builder
20+
:description: Configuration of io.helidon.openapi.OpenApiUi
21+
:keywords: helidon, config, io.helidon.openapi.OpenApiUi
22+
:basic-table-intro: The table below lists the configuration keys that configure io.helidon.openapi.OpenApiUi
2323
include::{rootdir}/includes/attributes.adoc[]
2424
25-
= Builder (openapi.OpenApiUi) Configuration
25+
= OpenApiUi (openapi) Configuration
2626
2727
// tag::config[]
2828
2929
30-
Type: link:{javadoc-base-url}/io.helidon.openapi.OpenApiUi/io/helidon/openapi/OpenApiUi/Builder.html[io.helidon.openapi.OpenApiUi.Builder]
30+
Type: link:{javadoc-base-url}/io.helidon.openapi/io/helidon/openapi/OpenApiUi.html[io.helidon.openapi.OpenApiUi]
3131
3232
3333
[source,text]
@@ -49,7 +49,7 @@ ui
4949
|key |type |default value |description
5050
5151
|`enabled` |boolean |`true` |Sets whether the UI should be enabled.
52-
|`options` |Map&lt;string, string&gt; |{nbsp} |Merges implementation-specific UI options.
52+
|`options` |Map&lt;string, string&gt; |{nbsp} |Sets implementation-specific UI options.
5353
|`web-context` |string |{nbsp} |web context (path) where the UI will respond
5454
5555
|===

0 commit comments

Comments
 (0)