Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.x - OpenAPI updates #7669

Merged
merged 3 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,11 @@
<artifactId>helidon-openapi</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.openapi</groupId>
<artifactId>helidon-openapi-ui</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.openapi</groupId>
<artifactId>helidon-microprofile-openapi</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.common.testing.junit5;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;

/**
* Hamcrest matchers for {@link java.util.Map}.
*/
public final class MapMatcher {
private MapMatcher() {
}

/**
* A matcher that performs {@link java.util.Map} deep equality.
* <p>
* Usage example:
* <pre>
* assertThat(actualMap, mapEqualTo(expectedMap));
* </pre>
*
* This method targets trees implemented using {@link java.util.Map} where values of type {@link java.util.Map}
* are considered tree nodes, and values of any other type are considered leaf nodes.
* <p>
* The deep-equality is performed by diffing a flat string representation of each map. If the diff yields no differences,
* the maps are considered deeply equal.
* <p>
* The entries are compared using strings, both keys and leaf nodes must implement {@link Object#toString()}.
*
* @param expected expected map
* @param <K> type of the map keys
* @param <V> type of the map values
* @return matcher validating the {@link java.util.Map} is deeply equal
*/
public static <K, V> Matcher<Map<K, V>> mapEqualTo(Map<K, V> expected) {
return new DiffMatcher<>(expected);
}

private static final class DiffMatcher<K, V> extends TypeSafeMatcher<Map<K, V>> {

private final Map<K, V> expected;
private volatile Map<K, V> actual;
private volatile List<Diff> diffs;

private DiffMatcher(Map<K, V> expected) {
this.expected = expected;
}

@Override
protected boolean matchesSafely(Map<K, V> actual) {
this.actual = actual;
this.diffs = diffs(expected, actual);
return diffs.isEmpty();
}

@Override
public void describeTo(Description description) {
description.appendText("deep map equality");
}

@Override
protected void describeMismatchSafely(Map<K, V> item, Description mismatchDescription) {
List<Diff> diffs = actual == item ? this.diffs : diffs(expected, item);
mismatchDescription.appendText("found differences" + System.lineSeparator())
.appendText(String.join(System.lineSeparator(), diffs.stream().map(Diff::toString).toList()));
}

private static List<Diff> diffs(Map<?, ?> left, Map<?, ?> right) {
List<Diff> diffs = new ArrayList<>();
Iterator<Map.Entry<String, String>> leftEntries = flattenEntries(left, "").iterator();
Iterator<Map.Entry<String, String>> rightEntries = flattenEntries(right, "").iterator();
while (true) {
boolean hasLeft = leftEntries.hasNext();
boolean hasRight = rightEntries.hasNext();
if (hasLeft && hasRight) {
Map.Entry<String, String> leftEntry = leftEntries.next();
Map.Entry<String, String> rightEntry = rightEntries.next();
if (!leftEntry.equals(rightEntry)) {
diffs.add(new Diff(leftEntry, rightEntry));
}
} else if (hasLeft) {
diffs.add(new Diff(leftEntries.next(), null));
} else if (hasRight) {
diffs.add(new Diff(null, rightEntries.next()));
} else {
return diffs;
}
}
}

private static List<Map.Entry<String, String>> flattenEntries(Map<?, ?> map, String prefix) {
List<Map.Entry<String, String>> result = new ArrayList<>();
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (entry.getValue() instanceof Map<?, ?> node) {
result.addAll(flattenEntries(node, prefix + entry.getKey() + "."));
} else {
result.add(Map.entry(prefix + entry.getKey(), entry.getValue().toString()));
}
}
result.sort(Map.Entry.comparingByKey());
return result;
}

private record Diff(Map.Entry<String, String> left, Map.Entry<String, String> right) {

@Override
public String toString() {
if (left == null && right != null) {
return "ADDED >> " + right;
}
if (left != null && right == null) {
return "REMOVED << " + left;
}
if (left != null) {
return "ADDED >> " + left + System.lineSeparator() + "REMOVED << " + right;
}
return "?";
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.common.testing;

import java.util.Map;

import org.junit.jupiter.api.Test;

import static io.helidon.common.testing.junit5.MapMatcher.mapEqualTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.not;

class MapMatcherTest {

@Test
void testIsMapEqual() {
assertThat(Map.of("foo", "bar"), is(mapEqualTo(Map.of("foo", "bar"))));
assertThat(Map.of("bar", "foo"), is(not(mapEqualTo(Map.of("foo", "bar")))));

assertThat(Map.of("foo", Map.of("bar", Map.of("bob", "alice"))),
is(mapEqualTo(Map.of("foo", Map.of("bar", Map.of("bob", "alice"))))));

assertThat(Map.of("foo", Map.of("bar", Map.of("bob", "alice"))),
is(not(mapEqualTo(Map.of("foo", Map.of("bar", Map.of("bob", "not-alice")))))));

assertThat(Map.of("foo", "bar", "bob", "alice"), is(mapEqualTo(Map.of("bob", "alice", "foo", "bar"))));
}
}
5 changes: 3 additions & 2 deletions docs/config/config_reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ The following section lists all configurable types in Helidon.
- xref:{rootdir}/config/io_helidon_common_configurable_AllowList.adoc[AllowList (common.configurable)]
- xref:{rootdir}/config/io_helidon_faulttolerance_Async.adoc[Async (faulttolerance)]
- xref:{rootdir}/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc[BaseBuilder (security.providers.oidc.common)]
- xref:{rootdir}/config/io_helidon_openapi_OpenApiUi_Builder.adoc[Builder (openapi.OpenApiUi)]
- xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc[Builder (security.providers.idcs.mapper.IdcsRoleMapperProviderBase)]
- xref:{rootdir}/config/io_helidon_webserver_servicecommon_HelidonFeatureSupport_Builder.adoc[Builder (webserver.servicecommon.HelidonFeatureSupport)]
- xref:{rootdir}/config/io_helidon_faulttolerance_Bulkhead.adoc[Bulkhead (faulttolerance)]
Expand Down Expand Up @@ -79,7 +78,8 @@ The following section lists all configurable types in Helidon.
- xref:{rootdir}/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc[ScheduledThreadPoolSupplier (common.configurable)]
- xref:{rootdir}/config/io_helidon_metrics_api_ScopeConfig.adoc[ScopeConfig (metrics.api)]
- xref:{rootdir}/config/io_helidon_metrics_api_ScopingConfig.adoc[ScopingConfig (metrics.api)]
- xref:{rootdir}/config/io_helidon_openapi_SeOpenApiFeature.adoc[SeOpenApiFeature (openapi)]
- xref:{rootdir}/config/io_helidon_openapi_OpenApiFeature.adoc[OpenApiFeature (openapi)]
- xref:{rootdir}/config/io_helidon_openapi_ui_OpenApiUi.adoc[OpenApiUi (openapi.ui)]
- xref:{rootdir}/config/io_helidon_security_Security.adoc[Security (security)]
- xref:{rootdir}/config/io_helidon_security_SecurityTime.adoc[SecurityTime (security)]
- xref:{rootdir}/config/io_helidon_microprofile_server_Server.adoc[Server (microprofile.server)]
Expand All @@ -99,3 +99,4 @@ The following section lists all configurable types in Helidon.
- xref:{rootdir}/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc[ZipkinTracerBuilder (tracing.providers.zipkin)]
- xref:{rootdir}/config/io_opentracing_Tracer.adoc[io_opentracing_Tracer]
- xref:{rootdir}/config/org_eclipse_microprofile_config_Config.adoc[org_eclipse_microprofile_config_Config]
- xref:{rootdir}/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc[MpOpenApiManagerConfig (microprofile.openapi)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////////

Copyright (c) 2023 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

///////////////////////////////////////////////////////////////////////////////

ifndef::rootdir[:rootdir: {docdir}/..]
:description: Configuration of io.helidon.microprofile.openapi.MpOpenApiManagerConfig
:keywords: helidon, config, io.helidon.microprofile.openapi.MpOpenApiManagerConfig
:basic-table-intro: The table below lists the configuration keys that configure io.helidon.microprofile.openapi.MpOpenApiManagerConfig
include::{rootdir}/includes/attributes.adoc[]

= MpOpenApiManagerConfig (microprofile.openapi) Configuration

// tag::config[]


Type: link:{javadoc-base-url}/io.helidon.microprofile.openapi/io/helidon/microprofile/openapi/MpOpenApiManagerConfig.html[io.helidon.microprofile.openapi.MpOpenApiManagerConfig]




== Configuration options



.Optional configuration options
[cols="3,3a,2,5a"]

|===
|key |type |default value |description

|`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
other resources are not included in the OpenAPI document.

@return `true` if enabled, `false` otherwise

|===

// end::config[]
68 changes: 68 additions & 0 deletions docs/config/io_helidon_openapi_OpenApiFeature.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
///////////////////////////////////////////////////////////////////////////////

Copyright (c) 2023 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

///////////////////////////////////////////////////////////////////////////////

ifndef::rootdir[:rootdir: {docdir}/..]
:description: Configuration of io.helidon.openapi.OpenApiFeature
:keywords: helidon, config, io.helidon.openapi.OpenApiFeature
:basic-table-intro: The table below lists the configuration keys that configure io.helidon.openapi.OpenApiFeature
include::{rootdir}/includes/attributes.adoc[]

= OpenApiFeature (openapi) Configuration

// tag::config[]


Type: link:{javadoc-base-url}/io.helidon.openapi/io/helidon/openapi/OpenApiFeature.html[io.helidon.openapi.OpenApiFeature]


This is a standalone configuration type, prefix from configuration root: `openapi`



== Configuration options



.Optional configuration options
[cols="3,3a,2,5a"]

|===
|key |type |default value |description

|`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |CORS config.

@return CORS config
|`enabled` |boolean |`true` |Sets whether the feature should be enabled.

@return `true` if enabled, `false` otherwise
|`manager` |io.helidon.openapi.OpenApiManager (service provider interface) |{nbsp} |OpenAPI manager.

@return the OpenAPI manager
|`services` |io.helidon.openapi.OpenApiService[&#93; (service provider interface) |{nbsp} |OpenAPI services.

@return the OpenAPI services
|`static-file` |string |{nbsp} |Path of the static OpenAPI document file. Default types are `json`, `yaml`, and `yml`.

@return location of the static OpenAPI document file
|`web-context` |string |`/openapi` |Web context path for the OpenAPI endpoint.

@return webContext to use

|===

// end::config[]
14 changes: 7 additions & 7 deletions docs/config/io_helidon_openapi_OpenApiUi_Builder.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////

Copyright (c) 2023 Oracle and/or its affiliates.
Copyright (c) 2022, 2023 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -17,17 +17,17 @@
///////////////////////////////////////////////////////////////////////////////

ifndef::rootdir[:rootdir: {docdir}/..]
:description: Configuration of io.helidon.openapi.OpenApiUi.Builder
:keywords: helidon, config, io.helidon.openapi.OpenApiUi.Builder
:basic-table-intro: The table below lists the configuration keys that configure io.helidon.openapi.OpenApiUi.Builder
:description: Configuration of io.helidon.openapi.OpenApiUi
:keywords: helidon, config, io.helidon.openapi.OpenApiUi
:basic-table-intro: The table below lists the configuration keys that configure io.helidon.openapi.OpenApiUi
include::{rootdir}/includes/attributes.adoc[]

= Builder (openapi.OpenApiUi) Configuration
= OpenApiUi (openapi) Configuration

// tag::config[]


Type: link:{javadoc-base-url}/io.helidon.openapi.OpenApiUi/io/helidon/openapi/OpenApiUi/Builder.html[io.helidon.openapi.OpenApiUi.Builder]
Type: link:{javadoc-base-url}/io.helidon.openapi/io/helidon/openapi/OpenApiUi.html[io.helidon.openapi.OpenApiUi]


[source,text]
Expand All @@ -49,7 +49,7 @@ ui
|key |type |default value |description

|`enabled` |boolean |`true` |Sets whether the UI should be enabled.
|`options` |Map&lt;string, string&gt; |{nbsp} |Merges implementation-specific UI options.
|`options` |Map&lt;string, string&gt; |{nbsp} |Sets implementation-specific UI options.
|`web-context` |string |{nbsp} |web context (path) where the UI will respond

|===
Expand Down