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

[OpenAPI Generator] Enable allow-list for API and Model classes #530

Closed
wants to merge 11 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@ public OperationsMap postProcessOperationsWithModels(
private static void setGlobalSettings( @Nonnull final GenerationConfiguration configuration )
{
if( configuration.isGenerateApis() ) {
GlobalSettings.setProperty(CodegenConstants.APIS, "");
GlobalSettings.setProperty(CodegenConstants.APIS, getAllowedIds(configuration, "apisToGenerate"));
}
if( configuration.isGenerateModels() ) {
GlobalSettings.setProperty(CodegenConstants.MODELS, "");
GlobalSettings.setProperty(CodegenConstants.MODELS, getAllowedIds(configuration, "modelsToGenerate"));
}
if( configuration.isDebugModels() ) {
GlobalSettings.setProperty("debugModels", "true");
Expand All @@ -111,6 +111,15 @@ private static void setGlobalSettings( @Nonnull final GenerationConfiguration co
GlobalSettings.setProperty(CodegenConstants.HIDE_GENERATION_TIMESTAMP, Boolean.TRUE.toString());
}

static String getAllowedIds( @Nonnull final GenerationConfiguration config, @Nonnull final String property )
{
final var allowIds = config.getAdditionalProperties().get(property);
if( allowIds == null || allowIds.isBlank() ) {
return "";
}
return String.join(",", allowIds.trim().split("\\W+"));
}

private static OpenAPI parseOpenApiSpec( @Nonnull final String inputSpecFile )
{
final List<AuthorizationValue> authorizationValues = List.of();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.sap.cloud.sdk.datamodel.openapi.generator;

import static java.util.Map.entry;
import static java.util.Map.ofEntries;

import static org.assertj.core.api.Assertions.assertThat;

import java.nio.file.Files;
Expand Down Expand Up @@ -94,14 +97,10 @@ private enum TestCase
true,
true,
6,
Map
.of(
"pojoBuilderMethodName",
"builder",
"pojoBuildMethodName",
"build",
"pojoConstructorVisibility",
"private")),
ofEntries(
entry("pojoBuilderMethodName", "builder"),
entry("pojoBuildMethodName", "build"),
entry("pojoConstructorVisibility", "private"))),
REMOVE_OPERATION_ID_PREFIX(
"remove-operation-id-prefix",
"sodastore.json",
Expand All @@ -111,14 +110,10 @@ private enum TestCase
true,
true,
6,
Map
.of(
"removeOperationIdPrefix",
"true",
"removeOperationIdPrefixDelimiter",
"\\.",
"removeOperationIdPrefixCount",
"3")),
ofEntries(
entry("removeOperationIdPrefix", "true"),
entry("removeOperationIdPrefixDelimiter", "\\."),
entry("removeOperationIdPrefixCount", "3"))),
GENERATE_APIS(
"generate-apis",
"sodastore.yaml",
Expand All @@ -128,7 +123,19 @@ private enum TestCase
true,
false,
7,
Map.of());
Map.of()),
GENERATE_MODELS(
"generate-models",
"sodastore.yaml",
"test",
"test",
ApiMaturity.RELEASED,
true,
true,
3,
ofEntries(
entry("apisToGenerate", "Default, NotExist"),
entry("modelsToGenerate", "Cola, Fanta, NotExist")));

final String testCaseName;
final String inputSpecFileName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import com.google.common.collect.ImmutableMap;
import com.sap.cloud.sdk.datamodel.openapi.generator.model.GenerationConfiguration;

class GenerationConfigurationConverterTest
Expand All @@ -35,6 +36,37 @@ void testCopyrightHeaderResolution()
assertThat(resultNoHeader).isNull();
}

@Test
void testGetAllowedIds()
{
// assertion definition: given input -> expected output
final var assertions =
ImmutableMap
.<String, String> builder()
.put("", "") // empty
.put("\n", "") // newline
.put("Foo", "Foo") // single
.put("Foo,Bar", "Foo,Bar") // list
.put("Foo;Bar", "Foo,Bar") // custom separator
.put("Foo Bar", "Foo,Bar") // space separator
.put("Foo \n Bar", "Foo,Bar") // new-line separator
.build();

// feed the assertion input arguments into the config
var configBuilder = GenerationConfiguration.builder();
int i = 0;
for( String input : assertions.keySet() ) {
configBuilder.additionalProperty("property" + (i++), input);
}
var config = configBuilder.build();

// run the test
int j = 0;
for( String output : assertions.values() ) {
assertThat(GenerationConfigurationConverter.getAllowedIds(config, "property" + (j++))).isEqualTo(output);
}
}

private GenerationConfiguration.GenerationConfigurationBuilder createBasicConfig()
{
return GenerationConfiguration
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
openapi: 3.0.0
info:
title: Soda Store API
version: 1.0.0
description: API for managing sodas in a soda store
paths:
/sodas:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor) since there is only one API, this only tests that NotExist doesn't cause the generation to fail..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the implication of this statement

get:
summary: Get a list of all sodas
operationId: getSodas
responses:
'200':
description: A list of sodas
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/OneOf'
components:
schemas:
ShouldNotBeGenerated:
oneOf:
- $ref: '#/components/schemas/Cola'
- $ref: '#/components/schemas/Fanta'
discriminator:
propertyName: sodaType
mapping:
Cola: '#/components/schemas/Cola'
Fanta: '#/components/schemas/Fanta'
OneOfWithDiscriminator:
oneOf:
- $ref: '#/components/schemas/Cola'
- $ref: '#/components/schemas/Fanta'
discriminator:
propertyName: sodaType
OneOf:
oneOf:
- $ref: '#/components/schemas/Cola'
- $ref: '#/components/schemas/Fanta'
AnyOf:
anyOf:
- $ref: '#/components/schemas/Cola'
- $ref: '#/components/schemas/Fanta'
AllOf:
allOf:
- $ref: '#/components/schemas/Cola'
- $ref: '#/components/schemas/Fanta'
Cola:
type: object
properties:
sodaType:
type: string
Fanta:
type: object
properties:
sodaType:
type: string
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* Copyright (c) 2024 SAP SE or an SAP affiliate company. All rights reserved.
*/

/*
* Soda Store API
* API for managing sodas in a soda store
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

package test;

import java.util.Objects;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
* Cola
*/
// CHECKSTYLE:OFF
public class Cola
// CHECKSTYLE:ON
{
@JsonProperty("sodaType")
private String sodaType;

@JsonAnySetter
@JsonAnyGetter
private final Map<String, Object> cloudSdkCustomFields = new LinkedHashMap<>();

/**
* Set the sodaType of this {@link Cola} instance and return the same instance.
*
* @param sodaType The sodaType of this {@link Cola}
* @return The same instance of this {@link Cola} class
*/
@Nonnull public Cola sodaType( @Nullable final String sodaType) {
this.sodaType = sodaType;
return this;
}

/**
* Get sodaType
* @return sodaType The sodaType of this {@link Cola} instance.
*/
@Nonnull
public String getSodaType() {
return sodaType;
}

/**
* Set the sodaType of this {@link Cola} instance.
*
* @param sodaType The sodaType of this {@link Cola}
*/
public void setSodaType( @Nullable final String sodaType) {
this.sodaType = sodaType;
}

/**
* Get the names of the unrecognizable properties of the {@link Cola}.
* @return The set of properties names
*/
@JsonIgnore
@Nonnull
public Set<String> getCustomFieldNames() {
return cloudSdkCustomFields.keySet();
}

/**
* Get the value of an unrecognizable property of this {@link Cola} instance.
* @param name The name of the property
* @return The value of the property
* @throws NoSuchElementException If no property with the given name could be found.
*/
@Nullable
public Object getCustomField( @Nonnull final String name ) throws NoSuchElementException {
if( !cloudSdkCustomFields.containsKey(name) ) {
throw new NoSuchElementException("Cola has no field with name '" + name + "'.");
}
return cloudSdkCustomFields.get(name);
}

/**
* Set an unrecognizable property of this {@link Cola} instance. If the map previously contained a mapping
* for the key, the old value is replaced by the specified value.
* @param customFieldName The name of the property
* @param customFieldValue The value of the property
*/
@JsonIgnore
public void setCustomField( @Nonnull String customFieldName, @Nullable Object customFieldValue )
{
cloudSdkCustomFields.put(customFieldName, customFieldValue);
}


@Override
public boolean equals(@Nullable final java.lang.Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Cola cola = (Cola) o;
return Objects.equals(this.cloudSdkCustomFields, cola.cloudSdkCustomFields) &&
Objects.equals(this.sodaType, cola.sodaType);
}

@Override
public int hashCode() {
return Objects.hash(sodaType, cloudSdkCustomFields);
}

@Override
@Nonnull public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("class Cola {\n");
sb.append(" sodaType: ").append(toIndentedString(sodaType)).append("\n");
cloudSdkCustomFields.forEach((k,v) -> sb.append(" ").append(k).append(": ").append(toIndentedString(v)).append("\n"));
sb.append("}");
return sb.toString();
}

/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private String toIndentedString(final java.lang.Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}

}

Loading
Loading