Skip to content

Commit

Permalink
Merge branch 'main' into 312-bug-duplicate-name-object-result-in-inco…
Browse files Browse the repository at this point in the history
…rrect-code-generation
  • Loading branch information
jemacineiras authored Aug 4, 2024
2 parents 8a2860a + f1c42c5 commit ceb97ca
Show file tree
Hide file tree
Showing 39 changed files with 1,585 additions and 59 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ As commented above, they both could be used at the same time, setting a double
<plugin>
<groupId>com.sngular</groupId>
<artifactId>scs-multiapi-maven-plugin</artifactId>
<version>5.3.4</version>
<version>5.4.3</version>
<executions>
<execution>
<id>asyncapi</id>
Expand Down Expand Up @@ -140,7 +140,7 @@ Apply the plugin in the `build.gradle` file and invoke the task.
```groovy
plugins {
id "java"
id "com.sngular.scs-multiapi-gradle-plugin' version '5.3.4"
id "com.sngular.scs-multiapi-gradle-plugin' version '5.4.3"
openapimodel {
Expand Down Expand Up @@ -189,7 +189,7 @@ which the plugin is designed.
<plugin>
<groupId>com.sngular</groupId>
<artifactId>scs-multiapi-maven-plugin</artifactId>
<version>5.3.4</version>
<version>5.4.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
Expand Down Expand Up @@ -404,10 +404,10 @@ order/createCommand:
$ref: '#/components/messages/com.sngular.apigenerator.asyncapi.model.CreateOrder'
```

- **Namespace from Avro**: If the user doesn't provide a package name, and the
entity is defined by an Avro Schema, the plugin will check for a `namespace`
attribute defined in the Avro file, and if there is, it will use it. The plugin
expects to receive a relative path from the `yml` file folder.
- **Namespace from Avro**: The plugin will check for a `namespace`
attribute defined in the Avro file and use it, if a namespace is
not defined it will throw an exception. The plugin expects to receive
a relative path from the `yml` file folder.

```yaml
order/created:
Expand Down Expand Up @@ -628,7 +628,7 @@ file. Here is an example of a basic configuration:
<plugin>
<groupId>com.sngular</groupId>
<artifactId>scs-multiapi-maven-plugin</artifactId>
<version>5.3.4</version>
<version>5.4.3</version>
<executions>
<execution>
<goals>
Expand Down
4 changes: 2 additions & 2 deletions multiapi-engine/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>com.sngular</groupId>
<artifactId>multiapi-engine</artifactId>
<version>5.3.4</version>
<version>5.4.3</version>
<packaging>jar</packaging>

<properties>
Expand Down Expand Up @@ -63,7 +63,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.sngular.api.generator.plugin.PluginConstants;
import com.sngular.api.generator.plugin.asyncapi.exception.ChannelNameException;
import com.sngular.api.generator.plugin.asyncapi.exception.DuplicateClassException;
import com.sngular.api.generator.plugin.asyncapi.exception.DuplicatedOperationException;
import com.sngular.api.generator.plugin.asyncapi.exception.ExternalRefComponentNotFoundException;
import com.sngular.api.generator.plugin.asyncapi.exception.FileSystemException;
import com.sngular.api.generator.plugin.asyncapi.exception.InvalidAsyncAPIException;
import com.sngular.api.generator.plugin.asyncapi.exception.*;
import com.sngular.api.generator.plugin.asyncapi.model.ProcessBindingsResult;
import com.sngular.api.generator.plugin.asyncapi.model.ProcessBindingsResult.ProcessBindingsResultBuilder;
import com.sngular.api.generator.plugin.asyncapi.model.ProcessMethodResult;
Expand Down Expand Up @@ -591,8 +586,11 @@ private String processExternalAvro(final String modelPackage, final FileLocation
final ObjectMapper mapper = new ObjectMapper();
try {
final JsonNode fileTree = mapper.readTree(avroFile);
final String fullNamespace = fileTree.get("namespace").asText() + PACKAGE_SEPARATOR + fileTree.get("name").asText();
namespace = processModelPackage(fullNamespace, modelPackage);
final JsonNode avroNamespace = fileTree.get("namespace");

if (avroNamespace == null) throw new InvalidAvroException(avroFilePath);

namespace = avroNamespace.asText() + PACKAGE_SEPARATOR + fileTree.get("name").asText();;//processModelPackage(fullNamespace, avroPackage);
} catch (final IOException e) {
throw new FileSystemException(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* * License, v. 2.0. If a copy of the MPL was not distributed with this
* * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

package com.sngular.api.generator.plugin.asyncapi.exception;

public class InvalidAvroException extends RuntimeException {
private static final String ERROR_MESSAGE = "AsyncApi -> Avro schema at path %s lacks a namespace.";
public InvalidAvroException(final String enumName) {
super(String.format(ERROR_MESSAGE, enumName));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,22 @@

package com.sngular.api.generator.plugin.openapi.utils;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.BiConsumer;

import com.fasterxml.jackson.databind.JsonNode;
import com.sngular.api.generator.plugin.common.tools.ApiTool;
import com.sngular.api.generator.plugin.common.tools.SchemaUtil;
import com.sngular.api.generator.plugin.openapi.exception.DuplicatedOperationException;
import com.sngular.api.generator.plugin.openapi.exception.InvalidOpenAPIException;
import com.sngular.api.generator.plugin.openapi.model.AuthSchemaObject;
import com.sngular.api.generator.plugin.openapi.model.ContentObject;
import com.sngular.api.generator.plugin.openapi.model.GlobalObject;
import com.sngular.api.generator.plugin.openapi.model.*;
import com.sngular.api.generator.plugin.openapi.model.GlobalObject.GlobalObjectBuilder;
import com.sngular.api.generator.plugin.openapi.model.OperationObject;
import com.sngular.api.generator.plugin.openapi.model.ParameterObject;
import com.sngular.api.generator.plugin.openapi.model.PathObject;
import com.sngular.api.generator.plugin.openapi.model.RequestObject;
import com.sngular.api.generator.plugin.openapi.model.ResponseObject;
import com.sngular.api.generator.plugin.openapi.model.SchemaFieldObjectType;
import com.sngular.api.generator.plugin.openapi.model.TypeConstants;
import com.sngular.api.generator.plugin.openapi.parameter.SpecFile;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.lang3.StringUtils;

import java.nio.file.Path;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.BiConsumer;

public class MapperPathUtil {

public static final String INLINE_PARAMETER = "InlineParameter";
Expand Down Expand Up @@ -358,11 +343,16 @@ private static List<ContentObject> mapContentObject(
final String pojoName = preparePojoName(inlineObject, schema, specFile);
final SchemaFieldObjectType dataType = getSchemaType(schema, pojoName, specFile, globalObject, baseDir);
final String importName = getImportFromType(dataType);
SchemaObject schemaObject = null;
if (mediaType.equals("application/x-www-form-urlencoded") || mediaType.equals("multipart/form-data")) {
schemaObject = MapperContentUtil.mapComponentToSchemaObject(globalObject.getSchemaMap(), new HashMap<String, SchemaObject>(), schema, dataType.getBaseType(), specFile, baseDir).get("object");
}
contentObjects.add(ContentObject.builder()
.dataType(dataType)
.name(mediaType)
.importName(importName)
.build());
.dataType(dataType)
.name(mediaType)
.importName(importName)
.schemaObject(schemaObject)
.build());
}
}
return contentObjects;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class ${streamBridgeClassName?cap_first} {
}

<#list streamBridgeMethods as method>
public void ${method.operationId?uncap_first}(final ${method.className}<#if streamBridgeEntitiesSuffix?has_content>${subscribeEntitiesSuffix}</#if> ${method.className?uncap_first}) {
public void ${method.operationId?uncap_first}(final ${method.className}<#if streamBridgeEntitiesSuffix?has_content>${streamBridgeEntitiesSuffix}</#if> ${method.className?uncap_first}) {
streamBridge.send("${method.channelName}", ${method.className?uncap_first});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class ${streamBridgeClassName?cap_first} {
}

<#list streamBridgeMethods as method>
public void ${method.operationId?uncap_first}(final ${method.className}<#if streamBridgeEntitiesSuffix?has_content>${subscribeEntitiesSuffix}</#if> ${method.className?uncap_first}, final ${method.keyClassName}<#if streamBridgeEntitiesSuffix?has_content>${subscribeEntitiesSuffix}</#if> ${method.keyClassName?uncap_first}) {
public void ${method.operationId?uncap_first}(final ${method.className}<#if streamBridgeEntitiesSuffix?has_content>${streamBridgeEntitiesSuffix}</#if> ${method.className?uncap_first}, final ${method.keyClassName}<#if streamBridgeEntitiesSuffix?has_content>${streamBridgeEntitiesSuffix}</#if> ${method.keyClassName?uncap_first}) {
final var message = MessageBuilder.withPayload(${method.className?uncap_first}).setHeader("key", ${method.keyClassName?uncap_first}).build();
streamBridge.send("${method.channelName}", message);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ public class ${className?cap_first}Api {
*/
public <@compress single_line=true><#if operation.responseObjects[0].contentObjects[0]??>
${operation.responseObjects[0].contentObjects[0].dataType}
<#else>Void</#if></@compress> ${operation.operationId}<#compress>(<#if operation.parameterObjects?has_content><#list operation.parameterObjects as parameter>${parameter.dataType} ${parameter.name}<#if parameter?has_next || operation.requestObjects?has_content>, </#if></#list></#if><#if path.parameterObjects?has_content><#list path.parameterObjects as parameter>${parameter.dataType} ${parameter.name}<#if parameter?has_next || operation.requestObjects?has_content>, </#if></#list></#if><#if operation.requestObjects?has_content><#list operation.requestObjects as request><#list request.contentObjects as content>${content.dataType} ${content.dataType?api.getVariableNameString()} <#if content?has_next>, </#if></#list></#list></#if>)</#compress> throws RestClientException {
return ${operation.operationId}WithHttpInfo(<#compress><#if operation.parameterObjects?has_content><#list operation.parameterObjects as parameter>${parameter.name}<#if parameter?has_next || operation.requestObjects?has_content>, </#if></#list></#if><#if path.parameterObjects?has_content><#list path.parameterObjects as parameter>${parameter.name}<#if parameter?has_next || operation.requestObjects?has_content>, </#if></#list></#if><#if operation.requestObjects?has_content><#list operation.requestObjects as request><#list request.contentObjects as content>${content.dataType?api.getVariableNameString()}<#if content?has_next>, </#if></#list></#list></#if>)<#if operation.responseObjects[0].contentObjects[0]??>.getBody()</#if>;</#compress>
<#else>void</#if></@compress> ${operation.operationId}<#compress>(<#if operation.parameterObjects?has_content><#list operation.parameterObjects as parameter>${parameter.dataType} ${parameter.name}<#if parameter?has_next || operation.requestObjects?has_content>, </#if></#list></#if><#if path.parameterObjects?has_content><#list path.parameterObjects as parameter>${parameter.dataType} ${parameter.name}<#if parameter?has_next || operation.requestObjects?has_content>, </#if></#list></#if><#if operation.requestObjects?has_content><#list operation.requestObjects as request><#list request.contentObjects as content>${content.dataType} ${content.dataType?api.getVariableNameString()} <#if content?has_next>, </#if></#list></#list></#if>)</#compress> throws RestClientException {
<#if operation.responseObjects[0].contentObjects[0]??>return </#if>${operation.operationId}WithHttpInfo(<#compress><#if operation.parameterObjects?has_content><#list operation.parameterObjects as parameter>${parameter.name}<#if parameter?has_next || operation.requestObjects?has_content>, </#if></#list></#if><#if path.parameterObjects?has_content><#list path.parameterObjects as parameter>${parameter.name}<#if parameter?has_next || operation.requestObjects?has_content>, </#if></#list></#if><#if operation.requestObjects?has_content><#list operation.requestObjects as request><#list request.contentObjects as content>${content.dataType?api.getVariableNameString()}<#if content?has_next>, </#if></#list></#list></#if>)<#if operation.responseObjects[0].contentObjects[0]??>.getBody()</#if>;</#compress>
}

public <@compress single_line=true><#if operation.responseObjects[0].contentObjects[0]??>
Expand Down Expand Up @@ -141,6 +141,13 @@ public class ${className?cap_first}Api {
final HttpHeaders headerParams = new HttpHeaders();
final MultiValueMap<String, String> cookieParams = new LinkedMultiValueMap<String, String>();
final MultiValueMap<String, Object> formParams = new LinkedMultiValueMap<String, Object>();
<#if operation.requestObjects?has_content>
<#if operation.requestObjects[0].contentObjects[0].schemaObject?has_content>
<#list operation.requestObjects[0].contentObjects[0].schemaObject.fieldObjectList as field>
formParams.put("${field.baseName}", List.of(${operation.requestObjects[0].contentObjects[0].dataType?api.getVariableNameString()}.get${field.baseName?cap_first}()));
</#list>
</#if>
</#if>

<#if operation.parameterObjects?has_content>
<#list operation.parameterObjects as parameter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ public class AsyncApiGeneratorFixtures {
.builder()
.filePath("src/test/resources/asyncapigenerator/testFileGenerationExternalAvro/event-api.yml")
.consumer(OperationParameterObject.builder()
.ids("subscribeOperationExternalAvro")
.ids("subscribeOperationExternalAvro,subscribeReceiptExternalAvro")
.apiPackage("com.sngular.scsplugin.externalavro.model.event.consumer")
.modelPackage("com.sngular.scsplugin.externalavro.model.event")
.build())
Expand All @@ -180,6 +180,23 @@ public class AsyncApiGeneratorFixtures {
.build()
);

final static List<SpecFile> TEST_ISSUE_INVALID_AVRO = List.of(
SpecFile
.builder()
.filePath("src/test/resources/asyncapigenerator/testIssueInvalidAvro/event-api.yml")
.consumer(OperationParameterObject.builder()
.ids("subscribeOperationExternalAvro")
.apiPackage("com.sngular.scsplugin.issueAvro.model.event.consumer")
.modelPackage("com.sngular.scsplugin.issueAvro.model.event")
.build())
.supplier(OperationParameterObject.builder()
.ids("publishOperationExternalAvro")
.apiPackage("com.sngular.scsplugin.issueAvro.model.event.producer")
.modelPackage("com.sngular.scsplugin.issueAvro.model.event")
.build())
.build()
);

final static List<SpecFile> TEST_FILE_GENERATION_STREAM_BRIDGE = List.of(
SpecFile
.builder()
Expand Down Expand Up @@ -761,6 +778,7 @@ static Function<Path, Boolean> validateTestFileGenerationExternalAvro() {

final List<String> expectedConsumerFiles = List.of(
ASSETS_PATH + "ISubscribeOperationExternalAvro.java",
ASSETS_PATH + "ISubscribeReceiptExternalAvro.java",
ASSETS_PATH + "Subscriber.java"
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.function.Function;
import java.util.stream.Stream;

import com.sngular.api.generator.plugin.asyncapi.exception.InvalidAvroException;
import com.sngular.api.generator.plugin.asyncapi.parameter.SpecFile;
import com.sngular.api.generator.plugin.exception.InvalidAPIException;
import org.assertj.core.api.Assertions;
Expand Down Expand Up @@ -91,4 +92,9 @@ void testExceptionForTestGenerationWithNoOperationConfiguration() {
Assertions.assertThatThrownBy(() -> asyncApiGenerator.processFileSpec(AsyncApiGeneratorFixtures.TEST_FILE_GENERATION_NO_CONFIG)).isInstanceOf(InvalidAPIException.class);
}

@Test
void testExceptionForTestIssueInvalidAvro() {
Assertions.assertThatThrownBy(() -> asyncApiGenerator.processFileSpec(AsyncApiGeneratorFixtures.TEST_ISSUE_INVALID_AVRO)).isInstanceOf(InvalidAvroException.class);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public final class OpenApiGeneratorFixtures {
static final List<SpecFile> TEST_REST_CLIENT_GENERATION = List.of(
SpecFile
.builder()
.filePath("openapigenerator/testClientPackageWebClientApiGeneration/api-test.yml")
.filePath("openapigenerator/testRestClientApiGeneration/api-test.yml")
.apiPackage("com.sngular.multifileplugin.restclient")
.modelPackage("com.sngular.multifileplugin.restclient.model")
.clientPackage("com.sngular.multifileplugin.restclient.client")
Expand All @@ -210,6 +210,20 @@ public final class OpenApiGeneratorFixtures {
.build()
);

static final List<SpecFile> TEST_REST_CLIENT_API_WITH_REQUEST_OBJECTS_GENERATION = List.of(
SpecFile
.builder()
.filePath("openapigenerator/testRestClientApiWithRequestObjectGeneration/api-test.yml")
.apiPackage("com.sngular.multifileplugin.restclientWithRequestObjects")
.modelPackage("com.sngular.multifileplugin.restclientWithRequestObjects.model")
.clientPackage("com.sngular.multifileplugin.restclientWithRequestObjects.client")
.modelNamePrefix("Api")
.modelNameSuffix("DTO")
.useLombokModelAnnotation(false)
.callMode(true)
.build()
);

static final List<SpecFile> TEST_ENUMS_GENERATION = List.of(
SpecFile
.builder()
Expand Down Expand Up @@ -491,6 +505,7 @@ public final class OpenApiGeneratorFixtures {
.build()
);


static Function<Path, Boolean> validateOneOfInResponse() {

final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testoneofinresponse";
Expand Down Expand Up @@ -911,6 +926,36 @@ static Function<Path, Boolean> validateRestClientGeneration() {
commonTest(path, expectedTestClientApiFile, expectedTestClientAuthModelFiles, CLIENT_TARGET_API, CLIENT_MODEL_API, Collections.emptyList(), null);
}

static Function<Path, Boolean> validateRestClientWithRequestBodyGeneration() {

final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/restclientWithRequestObjects";

final String CLIENT_TARGET_API = "generated/com/sngular/multifileplugin/restclientWithRequestObjects/client";

final String CLIENT_MODEL_API = "generated/com/sngular/multifileplugin/restclientWithRequestObjects/client/auth";

final String COMMON_PATH = "openapigenerator/testRestClientApiWithRequestObjectGeneration/";

final String ASSETS_PATH = COMMON_PATH + "assets/";

List<String> expectedTestApiFile = List.of(
ASSETS_PATH + "TestApi.java"
);

List<String> expectedTestClientApiFile = List.of(
ASSETS_PATH + "client/ApiRestClient.java"
);

List<String> expectedTestClientAuthModelFiles = List.of(
ASSETS_PATH + "client/auth/Authentication.java",
ASSETS_PATH + "client/auth/HttpBasicAuth.java"
);

return (path) ->
commonTest(path, expectedTestApiFile, Collections.emptyList(), DEFAULT_TARGET_API, null, Collections.emptyList(), null) &&
commonTest(path, expectedTestClientApiFile, expectedTestClientAuthModelFiles, CLIENT_TARGET_API, CLIENT_MODEL_API, Collections.emptyList(), null);
}

static Function<Path, Boolean> validateEnumsGeneration() {

final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/enumgeneration";
Expand Down
Loading

0 comments on commit ceb97ca

Please sign in to comment.