Skip to content

Commit

Permalink
[4.x] Adopt SnakeYAML 2.0; add integration tests for reactive and Nima (
Browse files Browse the repository at this point in the history
  • Loading branch information
tjquinno authored Mar 31, 2023
1 parent 6c801eb commit 1fa6694
Show file tree
Hide file tree
Showing 36 changed files with 1,663 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 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 Down Expand Up @@ -39,6 +39,7 @@
import io.helidon.config.MutabilitySupport;

import org.eclipse.microprofile.config.spi.ConfigSource;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;

Expand Down Expand Up @@ -380,7 +381,7 @@ public String getName() {
static Map toMap(Reader reader) {
// the default of Snake YAML is a Map, safe constructor makes sure we never deserialize into anything
// harmful
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
return (Map) yaml.loadAs(reader, Object.class);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022 Oracle and/or its affiliates.
* Copyright (c) 2020, 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 Down Expand Up @@ -32,6 +32,7 @@
import io.helidon.config.spi.ConfigParser;
import io.helidon.config.spi.ConfigParserException;

import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;

Expand Down Expand Up @@ -113,7 +114,7 @@ public ObjectNode parse(Content content) throws ConfigParserException {
static Map toMap(Reader reader) {
// the default of Snake YAML is a Map, safe constructor makes sure we never deserialize into anything
// harmful
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
return (Map) yaml.loadAs(reader, Object.class);
}

Expand Down
2 changes: 1 addition & 1 deletion dependencies/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
<version.lib.prometheus>0.9.0</version.lib.prometheus>
<version.lib.slf4j>2.0.0</version.lib.slf4j>
<version.lib.smallrye-openapi>2.1.16</version.lib.smallrye-openapi>
<version.lib.snakeyaml>1.32</version.lib.snakeyaml>
<version.lib.snakeyaml>2.0</version.lib.snakeyaml>
<version.lib.typesafe-config>1.4.2</version.lib.typesafe-config>
<version.lib.tyrus>2.0.4</version.lib.tyrus>
<version.lib.weld-api>5.0.SP3</version.lib.weld-api>
Expand Down
6 changes: 6 additions & 0 deletions examples/todo-app/backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<version.datastax.driver.core>4.9.0</version.datastax.driver.core>
<version.datastax.driver.query.builder>4.9.0</version.datastax.driver.query.builder>
<version.codahale.metrics.core>3.0.2</version.codahale.metrics.core>
<version.lib.snakeyaml.override>1.32</version.lib.snakeyaml.override>
</properties>

<dependencyManagement>
Expand All @@ -57,6 +58,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${version.lib.snakeyaml.override}</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
16 changes: 16 additions & 0 deletions microprofile/tests/tck/tck-openapi/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@
<artifactId>tck-openapi</artifactId>
<name>Helidon Microprofile Tests TCK OpenAPI</name>

<properties>
<selectedSnakeYamlVersion>1.32</selectedSnakeYamlVersion>
</properties>

<!-- The TCK uses Jackson which in turn uses SnakeYAML APIs that have disappeared in 2.0. So, for running the TCK
use the earlier SnakeYAML release (until an updated Jackson release becomes available). -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${selectedSnakeYamlVersion}</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.helidon.microprofile.tests</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,9 @@ private OpenApiStaticFile getExplicitStaticFile() {
+ " is not one of recognized types: "
+ OpenAPIMediaType.recognizedFileTypes()));

try (InputStream is = new BufferedInputStream(Files.newInputStream(path))) {
// DO NOT use try-with-close; the stream needs to remain open because it is not consumed until later.
try {
InputStream is = new BufferedInputStream(Files.newInputStream(path));
LOGGER.log(Level.DEBUG,
() -> String.format(
OPENAPI_EXPLICIT_STATIC_FILE_LOG_MESSAGE_FORMAT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.eclipse.microprofile.openapi.models.responses.APIResponse;
import org.eclipse.microprofile.openapi.models.responses.APIResponses;
import org.eclipse.microprofile.openapi.models.security.SecurityRequirement;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.error.Mark;
Expand Down Expand Up @@ -148,7 +149,7 @@ record ChildMapType<P, C>(Class<P> parentType,
Function<Class<?>, ExpandedTypeDescription.MapLikeTypeDescription<P, C>> typeDescriptionFactory) { }

/**
* Type information about a map-resembling interface in which a child can have 0, 1, or more values i.e., the child is
* 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 <P> parent type
Expand All @@ -165,7 +166,7 @@ record ChildMapListType<P, C>(
private static final System.Logger LOGGER = System.getLogger(CustomConstructor.class.getName());

CustomConstructor(TypeDescription td) {
super(td);
super(td, new LoaderOptions());
yamlClassConstructors.put(NodeId.mapping, new ConstructMapping());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021 Oracle and/or its affiliates.
* Copyright (c) 2020, 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 Down Expand Up @@ -61,46 +61,18 @@ public Tag getTag() {
return delegate.getTag();
}

@Override
public void setTag(Tag tag) {
delegate.setTag(tag);
}

@Override
public void setTag(String tag) {
delegate.setTag(tag);
}

@Override
@Deprecated
public void putListPropertyType(String property, Class<?> type) {
delegate.putListPropertyType(property, type);
}

@Override
@Deprecated
public Class<? extends Object> getListPropertyType(String property) {
return delegate.getListPropertyType(property);
}

@Override
@Deprecated
public void putMapPropertyType(String property, Class<?> key, Class<?> value) {
delegate.putMapPropertyType(property, key, value);
}

@Override
@Deprecated
public Class<? extends Object> getMapKeyType(String property) {
return delegate.getMapKeyType(property);
}

@Override
@Deprecated
public Class<? extends Object> getMapValueType(String property) {
return delegate.getMapValueType(property);
}

@Override
public void addPropertyParameters(String pName, Class<?>... classes) {
delegate.addPropertyParameters(pName, classes);
Expand Down
13 changes: 12 additions & 1 deletion openapi/src/main/java/io/helidon/openapi/ParserHelper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 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 Down Expand Up @@ -32,13 +32,24 @@
* Wraps generated parser and uses {@link io.helidon.openapi.ExpandedTypeDescription} as its type.
*/
public class ParserHelper {

// Temporary to suppress SnakeYAML warnings.
// As a static we keep a reference to the logger, thereby making sure any changes we make are persistent. (JUL holds
// only weak references to loggers internally.)
private static final java.util.logging.Logger SNAKE_YAML_INTROSPECTOR_LOGGER =
java.util.logging.Logger.getLogger(org.yaml.snakeyaml.introspector.PropertySubstitute.class.getPackage().getName());

/**
* The SnakeYAMLParserHelper is generated by a maven plug-in.
*/
private final SnakeYAMLParserHelper<ExpandedTypeDescription> generatedHelper;

private ParserHelper(SnakeYAMLParserHelper<ExpandedTypeDescription> generatedHelper) {
this.generatedHelper = generatedHelper;
boolean warningsEnabled = Boolean.getBoolean("openapi.parsing.warnings.enabled");
if (SNAKE_YAML_INTROSPECTOR_LOGGER.isLoggable(java.util.logging.Level.WARNING) && !warningsEnabled) {
SNAKE_YAML_INTROSPECTOR_LOGGER.setLevel(java.util.logging.Level.SEVERE);
}
}

/**
Expand Down
3 changes: 1 addition & 2 deletions openapi/src/main/java/io/helidon/openapi/Serializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,16 +114,15 @@ static class CustomRepresenter extends Representer {

private static final String EXTENSIONS = "extensions";

private final DumperOptions dumperOptions;
private final DumperOptions.ScalarStyle stringStyle;

private final Map<Class<?>, ExpandedTypeDescription> implsToTypes;

CustomRepresenter(Map<Class<?>, ExpandedTypeDescription> types,
Map<Class<?>, ExpandedTypeDescription> implsToTypes, DumperOptions dumperOptions,
DumperOptions.ScalarStyle stringStyle) {
super(dumperOptions);
this.implsToTypes = implsToTypes;
this.dumperOptions = dumperOptions;
this.stringStyle = stringStyle;
types.values().stream()
.map(ImplTypeDescription::new)
Expand Down
1 change: 1 addition & 0 deletions openapi/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
requires transitive microprofile.openapi.api;

requires static io.helidon.config.metadata;
requires java.logging; // temporary to adjust SnakeYAML logger level

exports io.helidon.openapi;
exports io.helidon.openapi.internal to io.helidon.microprofile.openapi, io.helidon.reactive.openapi, io.helidon.nima.openapi;
Expand Down
21 changes: 21 additions & 0 deletions tests/integration/gh-5792-nima/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

# helidon-tests-integration-yaml-parsing

Sample Helidon Níma project to make sure that we can build and run using an older release of SnakeYAML in case users need to fall back.

Note that the static OpenAPI document packaged into the application JAR file intentionally _does not_ describe the API for this service.
It contains a much richer definition to exercise YAML parsing a bit more.

## Build and run

With JDK19+
```bash
mvn package
java --enable-preview -jar target/helidon-tests-integration-yaml-parsing.jar
```

## Try OpenAPI

```
curl -s -X GET http://localhost:8080/openapi
```
117 changes: 117 additions & 0 deletions tests/integration/gh-5792-nima/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2019, 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.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.helidon.applications</groupId>
<artifactId>helidon-nima</artifactId>
<version>4.0.0-SNAPSHOT</version>
<relativePath>../../../applications/nima/pom.xml</relativePath>
</parent>
<groupId>io.helidon.tests.integration</groupId>
<artifactId>helidon-tests-integration-yaml-parsing-nima</artifactId>
<version>4.0.0-SNAPSHOT</version>

<name>Helidon SnakeYAML Earlier Version Test - Nima</name>

<properties>
<mainClass>io.helidon.tests.integration.yamlparsing.Main</mainClass>
<selectedSnakeYamlVersion>1.32</selectedSnakeYamlVersion>
</properties>

<dependencyManagement>
<dependencies>
<!-- Verify that the app builds correctly and that config and OpenAPI document YAML parsing work with the older
SnakeYAML release. -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${selectedSnakeYamlVersion}</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.helidon.nima.webserver</groupId>
<artifactId>helidon-nima-webserver</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.nima.webclient</groupId>
<artifactId>helidon-nima-webclient</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.nima.http.media</groupId>
<artifactId>helidon-nima-http-media-jsonp</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.nima.openapi</groupId>
<artifactId>helidon-nima-openapi</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config-yaml</artifactId>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.nima.testing.junit5</groupId>
<artifactId>helidon-nima-testing-junit5-webserver</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<selected-snakeyaml-version>${selectedSnakeYamlVersion}</selected-snakeyaml-version>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-libs</id>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Loading

0 comments on commit 1fa6694

Please sign in to comment.