diff --git a/dependencies/pom.xml b/dependencies/pom.xml
index 0c2a6d10fdd..2f13453985e 100644
--- a/dependencies/pom.xml
+++ b/dependencies/pom.xml
@@ -81,7 +81,7 @@
3.0.02.0.03.0.1
- 2.3.1.Final
+ 2.4.1.Final3.0.23.0.21.2.5.Final
@@ -137,7 +137,7 @@
42.2.180.9.01.7.32
- 2.1.15
+ 2.1.161.271.4.12.0.1
diff --git a/docs/mp/openapi/01_openapi.adoc b/docs/mp/openapi/01_openapi.adoc
index f2b6671ee06..cf6efb8eaa7 100644
--- a/docs/mp/openapi/01_openapi.adoc
+++ b/docs/mp/openapi/01_openapi.adoc
@@ -178,7 +178,7 @@ link:{mp-openapi-spec}#configuration[configuration section] of the MicroProfile
OpenAPI spec.
== Accessing the OpenAPI document
-Now your Helidon MP application will automatially respond to an additional endpoint --
+Now your Helidon MP application will automatically respond to an additional endpoint --
`/openapi` -- and it will return the OpenAPI document describing the endpoints
in your application.
@@ -187,5 +187,5 @@ There is not yet an adopted IANA YAML media type, but a proposed one specificall
for OpenAPI documents that has some support is `application/vnd.oai.openapi`.
That is what Helidon returns, by default.
-A client can specify `Accept:` as either `application/vnd.oai.openapi+json` or `application/json`
-to request JSON.
+In addition a client can specify the HTTP header `Accept:` as either `application/vnd.oai.openapi+json` or `application/json`
+to request JSON. Alternatively, the client can pass the query parameter `format` as either `JSON` or `YAML` to receive `application/json` or `application/vnd.oai.openapi` (YAML) output, respectively.
diff --git a/docs/se/openapi/01_openapi.adoc b/docs/se/openapi/01_openapi.adoc
index 3214d5a837c..451f1d1f3be 100644
--- a/docs/se/openapi/01_openapi.adoc
+++ b/docs/se/openapi/01_openapi.adoc
@@ -152,6 +152,7 @@ those described in the MicroProfile OpenAPI spec, two of which were mentioned ab
servers for given paths
|`openapi.servers.operation` |Prefix for config properties specifying alternative
servers for given operations
+|`openapi.schema` |Prefix for config properties defining the schema for a class
|===
For more information on what these settings do consult the MicroProfile OpenAPI spec.
@@ -182,5 +183,5 @@ There is not yet an adopted IANA YAML media type, but a proposed one specificall
for OpenAPI documents that has some support is `application/vnd.oai.openapi`.
That is what Helidon returns, by default.
-In addition a client can specify `Accept:` as either `application/vnd.oai.openapi+json` or `application/json`
-to request JSON.
+In addition a client can specify the HTTP header `Accept:` as either `application/vnd.oai.openapi+json` or `application/json`
+to request JSON. Alternatively, the client can pass the query parameter `format` as either `JSON` or `YAML` to receive `application/json` or `application/vnd.oai.openapi` (YAML) output, respectively.
diff --git a/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java b/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java
index f8feae5efa5..00bdcab6d12 100644
--- a/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java
+++ b/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java
@@ -32,8 +32,6 @@
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-@Disabled("3.0.0-JAKARTA") // OpenAPI: Caused by: java.lang.NoSuchMethodError:
- // 'java.util.List org.jboss.jandex.ClassInfo.unsortedFields()'
class MainTest {
private static Server server;
diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java
index f8feae5efa5..00bdcab6d12 100644
--- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java
+++ b/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java
@@ -32,8 +32,6 @@
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-@Disabled("3.0.0-JAKARTA") // OpenAPI: Caused by: java.lang.NoSuchMethodError:
- // 'java.util.List org.jboss.jandex.ClassInfo.unsortedFields()'
class MainTest {
private static Server server;
diff --git a/microprofile/openapi/src/main/java/io/helidon/microprofile/openapi/MPOpenAPIBuilder.java b/microprofile/openapi/src/main/java/io/helidon/microprofile/openapi/MPOpenAPIBuilder.java
index e1f3d867123..f4d46477bea 100644
--- a/microprofile/openapi/src/main/java/io/helidon/microprofile/openapi/MPOpenAPIBuilder.java
+++ b/microprofile/openapi/src/main/java/io/helidon/microprofile/openapi/MPOpenAPIBuilder.java
@@ -68,10 +68,6 @@ public final class MPOpenAPIBuilder extends OpenAPISupport.Buildertck-openapi
Helidon Microprofile Tests TCK OpenAPI
-
-
- true
-
-
io.helidon.microprofile.tests
@@ -72,6 +67,24 @@
jakarta.activation-apitest
+
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+ 2.3.2
+ test
+
+
+
+
+ org.glassfish.jaxb
+ jaxb-runtime
+ 2.3.2
+ test
+
diff --git a/openapi/src/main/java/io/helidon/openapi/CustomConstructor.java b/openapi/src/main/java/io/helidon/openapi/CustomConstructor.java
index 826a8a9749e..091593950b1 100644
--- a/openapi/src/main/java/io/helidon/openapi/CustomConstructor.java
+++ b/openapi/src/main/java/io/helidon/openapi/CustomConstructor.java
@@ -16,9 +16,9 @@
package io.helidon.openapi;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -40,56 +40,141 @@
import org.yaml.snakeyaml.nodes.Tag;
/**
- * Specialized SnakeYAML constructor for modifying {@code Node} objects for OpenAPI types that extend {@code Map} to adjust the
- * type of the child nodes of such nodes.
+ * Specialized SnakeYAML constructor for modifying {@code Node} objects for OpenAPI types needing special attention.
*
- * Several MicroProfile OpenAPI interfaces extend {@code Map}. For example, {@code Paths} extends {@code Map
- * } and {@code SecurityRequirement} extends {@code Map>}. When SnakeYAML builds the node
- * corresponding to one of these types, it correctly creates each child node as a {@code MappingNode} but it assigns those
- * child nodes a type of {@code Object} instead of the mapped type -- {@code PathItem} in the example above.
- *
- *
- * This class customizes the preparation of the node tree in these situations by setting the types for the child nodes explicitly
- * to the corresponding child type. In OpenAPI 1.1.2 there are two situations, depending on whether the mapped-to type is a
- * {@code List} or not.
- *
- *
- * The MicroProfile OpenAPI 2.0 versions of the interfaces no longer use this construct of an interface extending {@code Map}, so
- * ideally we can remove this workaround when we adopt 2.0.
+ * Several MP OpenAPI types resemble maps with strings for keys and various child types as values. Such interfaces
+ * expose an {@code addX} method, where X is the child type (e.g., {@link Paths} exposes {@link Paths#addPathItem}.
+ * SnakeYAML parsing, left to itself, would incorrectly attempt to use the string keys as property names in converting OpenAPI
+ * documents to and from the in-memory POJO model. To prevent that, this custom constructor takes over the job of
+ * creating these parent instances and populating the children from the SnakeYAML node graph.
*
*/
final class CustomConstructor extends Constructor {
- // maps OpenAPI interfaces which extend Map, type> to the mapped-to type where that mapped-to type is NOT List
- private static final Map, Class>> CHILD_MAP_TYPES = new HashMap<>();
+ // OpenAPI interfaces which resemble Map, type>, linked to info used to prepare the type description for that type where
+ // the mapped-to type is NOT a list. For typing reasons (in ExpandedTypeDescription$MapLikeTypeDescription#create)
+ // we provide type-specific factory functions as part of the type metadata here where we can specify the actual parent
+ // and child types.
+ static final Map, ChildMapType, ?>> CHILD_MAP_TYPES = Map.of(
+ APIResponses.class, new ChildMapType<>(APIResponses.class,
+ APIResponse.class,
+ APIResponses::addAPIResponse,
+ impl -> ExpandedTypeDescription.MapLikeTypeDescription.create(
+ APIResponses.class,
+ impl,
+ APIResponse.class,
+ APIResponses::addAPIResponse)),
+ Callback.class, new ChildMapType<>(Callback.class,
+ PathItem.class,
+ Callback::addPathItem,
+ impl -> ExpandedTypeDescription.MapLikeTypeDescription.create(
+ Callback.class,
+ impl,
+ PathItem.class,
+ Callback::addPathItem)),
+ Content.class, new ChildMapType<>(Content.class,
+ MediaType.class,
+ Content::addMediaType,
+ impl -> ExpandedTypeDescription.MapLikeTypeDescription.create(
+ Content.class,
+ impl,
+ MediaType.class,
+ Content::addMediaType)),
+ Paths.class, new ChildMapType<>(Paths.class,
+ PathItem.class,
+ Paths::addPathItem,
+ impl -> ExpandedTypeDescription.MapLikeTypeDescription.create(
+ Paths.class,
+ impl,
+ PathItem.class,
+ Paths::addPathItem)));
- // maps OpenAPI interfaces which extend Map, List> to the type that appears in the list
- private static final Map, Class>> CHILD_MAP_OF_LIST_TYPES = new HashMap<>();
+ // OpenAPI interfaces which resemble Map, List>, linked to info used to prepare the type description for that type
+ // where the mapped-to type IS a list.
+ static final Map, ChildMapListType, ?>> CHILD_MAP_OF_LIST_TYPES = Map.of(
+ SecurityRequirement.class, new ChildMapListType<>(SecurityRequirement.class,
+ String.class,
+ SecurityRequirement::addScheme,
+ SecurityRequirement::addScheme,
+ SecurityRequirement::addScheme,
+ impl -> ExpandedTypeDescription.ListMapLikeTypeDescription.create(
+ SecurityRequirement.class,
+ impl,
+ String.class,
+ SecurityRequirement::addScheme,
+ SecurityRequirement::addScheme,
+ SecurityRequirement::addScheme)));
- private static final Logger LOGGER = Logger.getLogger(CustomConstructor.class.getName());
+ /**
+ * Adds a single named child to the parent.
+ *
+ * @param
parent type
+ * @param child type
+ */
+ @FunctionalInterface
+ interface ChildAdder
{
+ Object addChild(P parent, String name, C child);
+ }
+
+ /**
+ * Adds a list of children to the parent.
+ *
+ * @param
parent type
+ * @param child type
+ */
+ @FunctionalInterface
+ interface ChildListAdder
{
+ Object addChildren(P parent, String name, List children);
+ }
- static {
- CHILD_MAP_TYPES.put(Paths.class, PathItem.class);
- CHILD_MAP_TYPES.put(Callback.class, PathItem.class);
- CHILD_MAP_TYPES.put(Content.class, MediaType.class);
- CHILD_MAP_TYPES.put(APIResponses.class, APIResponse.class);
- /*
- TODO 3.0.0-JAKARTA
- CHILD_MAP_TYPES.put(ServerVariables.class, ServerVariable.class);
- CHILD_MAP_TYPES.put(Scopes.class, String.class);
- */
- CHILD_MAP_OF_LIST_TYPES.put(SecurityRequirement.class, String.class);
+ /**
+ * Adds a valueless child name to the parent.
+ *
+ * @param
parent type
+ */
+ @FunctionalInterface
+ interface ChildNameAdder
{
+ P addChild(P parent, String name);
}
+ /**
+ * Type information about a map-resembling interface.
+ *
+ * @param
parent type
+ * @param child type
+ */
+ record ChildMapType
> typeDescriptionFactory) { }
+
+ /**
+ * Type information about a map-resembling interface in which a child can have 0, 1, or more values i.e., the child is
+ * a list).
+ *
+ * @param
parent type
+ * @param child type
+ */
+ record ChildMapListType