Skip to content

Commit

Permalink
PR for openapi-generator-maven-plugin inputSpec -- Allow jar: URLs (#…
Browse files Browse the repository at this point in the history
…18576)

* Added support for <inputSpec/> arguments of JAR URLs.
E.g., jar:jar-specific-uri!/spec.yml.

* Resolve and search COMPILE dependencies for inputSpec resource.

* Added test cases for openapi-generator-maven-plugin:generate input
specifications:

* URLs of the form jar:jar-specific-uri!/spec.yaml

* Resources on the compilation classpath

in addition to the existing FILE test case.

* Check for inputSpecFile existence

else it is a remote URL && url is not empty

* replaced deprecated usage

* use Unix separators when on win-os

* example with jar inputSpec

* Comment not required anymore

Was introduced with #7587 could be removed with #10544

* referenced same maven version

these artifacts are referenced by same ${project.version} in https://github.com/apache/maven/blob/master/pom.xml

* updating maven dependencies to 3.9.6

---------

Co-authored-by: Allen D. Ball <ball@hcf.dev>
  • Loading branch information
parenko and allen-ball committed May 21, 2024
1 parent 9222231 commit 9a35914
Show file tree
Hide file tree
Showing 15 changed files with 178 additions and 34 deletions.
24 changes: 24 additions & 0 deletions modules/openapi-generator-maven-plugin/examples/java-client.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@
<cleanupOutput>true</cleanupOutput>
</configuration>
</execution>
<execution>
<id>jar</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<!-- specify the swagger yaml -->
<inputSpec>jar:file:${project.basedir}/../src/test/resources/default/local-repo/petstore/schema/1/schema-1.jar!/petstore.yaml</inputSpec>

<!-- target to generate java client code -->
<generatorName>java</generatorName>

<!-- hint: if you want to generate java server code, e.g. based on Spring Boot,
you can use the following target: <generatorName>spring</generatorName> -->

<!-- pass any necessary config options -->
<configOptions>
<dateLibrary>joda</dateLibrary>
</configOptions>

<!-- override the default library to jersey2 -->
<library>jersey2</library>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
Expand Down
16 changes: 11 additions & 5 deletions modules/openapi-generator-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sonar.exclusions>**/src/main/java/org/openapitools/codegen/plugin/**/*</sonar.exclusions>
<!-- used for integration tests verification scripts, managed by the test harness plugin -->
<maven.version>3.9.6</maven.version>
</properties>
<dependencies>
<dependency>
Expand All @@ -27,25 +27,25 @@
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.9.4</version>
<version>${maven.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.9.4</version>
<version>${maven.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
<version>3.9.4</version>
<version>${maven.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.9.4</version>
<version>${maven.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand All @@ -64,6 +64,12 @@
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-provider</artifactId>
<version>${maven.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-verifier</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
Expand All @@ -50,14 +52,17 @@
import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.util.ClasspathHelper;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;

import org.apache.maven.project.MavenProjectHelper;
Expand All @@ -82,7 +87,7 @@
* Goal which generates client/server code from a OpenAPI json/yaml definition.
*/
@SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection"})
@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true)
@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES, requiresDependencyResolution = ResolutionScope.COMPILE, threadSafe = true)
public class CodeGenMojo extends AbstractMojo {

private final Logger LOGGER = LoggerFactory.getLogger(CodeGenMojo.class);
Expand Down Expand Up @@ -662,7 +667,13 @@ public void execute() throws MojoExecutionException {
}

if (isNotEmpty(inputSpec)) {
configurator.setInputSpec(inputSpec);
URL url = inputSpecRemoteUrl();

if ((! inputSpecFile.exists()) && url != null) {
configurator.setInputSpec(url.toString());
} else {
configurator.setInputSpec(inputSpec);
}
}

if (isNotEmpty(gitHost)) {
Expand Down Expand Up @@ -1075,15 +1086,35 @@ private String calculateInputSpecHash(File inputSpecFile) throws IOException {
}

/**
* Try to parse inputSpec setting string into URL
* Try to parse inputSpec setting string into URL (truly remote or resource)
* @return A valid URL or null if inputSpec is not a valid URL
*/
private URL inputSpecRemoteUrl(){
try {
return new URI(inputSpec).toURL();
} catch (URISyntaxException | MalformedURLException | IllegalArgumentException e) {
return null;
private URL inputSpecRemoteUrl() {
URL url = dependencyClassLoader().getResource(inputSpec);

if (url == null) {
try {
url = new URI(FilenameUtils.separatorsToUnix(inputSpec)).toURL();
} catch (URISyntaxException | MalformedURLException | IllegalArgumentException e) {
}
}

return url;
}

private ClassLoader dependencyClassLoader() {
List<URL> list = new ArrayList<>();

for (Artifact artifact : project.getArtifacts()) {
try {
if (artifact.isResolved() && artifact.getType().equals("jar")) {
list.add(new URL("jar:" + artifact.getFile().toURI() + "!/"));
}
} catch (Exception e) {
}
}

return new URLClassLoader(list.toArray(new URL[] { }), getClass().getClassLoader());
}

/**
Expand All @@ -1096,7 +1127,7 @@ private File getHashFile(File inputSpecFile) {
String name = inputSpecFile.getName();

URL url = inputSpecRemoteUrl();
if (url != null) {
if (inputSpecFile.exists() && url != null) {
String[] segments = url.getPath().split("/");
name = Files.getNameWithoutExtension(segments[segments.length - 1]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,35 @@
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.RepositorySystem;

public class CodeGenMojoTest extends BaseTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
}

public void testCommonConfigurationWithFileInputSpec() throws Exception {
testCommonConfiguration("file");
}

public void testCommonConfigurationWithResourceInputSpec() throws Exception {
testCommonConfiguration("resource");
}

public void testCommonConfigurationWithURLInputSpec() throws Exception {
testCommonConfiguration("url");
}

@SuppressWarnings("unchecked")
public void testCommonConfiguration() throws Exception {
private void testCommonConfiguration(String profile) throws Exception {
File folder = Files.createTempDirectory("test").toFile();
CodeGenMojo mojo = loadMojo(folder, "src/test/resources/default");
CodeGenMojo mojo = loadMojo(folder, "src/test/resources/default", profile);
mojo.execute();
assertEquals("java", getVariableValueFromObject(mojo, "generatorName"));
assertEquals("jersey2", getVariableValueFromObject(mojo, "library"));
Expand All @@ -65,7 +82,7 @@ public void testCommonConfiguration() throws Exception {
public void testHashGenerationFileContainsExecutionId() throws Exception {
// GIVEN
Path folder = Files.createTempDirectory("test");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "executionId");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "file", "executionId");

// WHEN
mojo.execute();
Expand All @@ -86,7 +103,7 @@ public void testSkipRegenerationForClasspathSpecFileNoChange() throws Exception
//GIVEN
/* Setup the mojo */
final Path folder = Files.createTempDirectory("test-classpath");
final CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/classpath", "executionId");
final CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/classpath", null, "executionId");

/* Perform an initial generation */
mojo.execute();
Expand Down Expand Up @@ -124,7 +141,7 @@ public void testSkipRegenerationForClasspathSpecFileWithChange() throws Exceptio
//GIVEN
/* Setup the mojo */
final Path folder = Files.createTempDirectory("test-classpath");
final CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/classpath", "executionId");
final CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/classpath", null, "executionId");

/* Perform an initial generation */
mojo.execute();
Expand Down Expand Up @@ -159,7 +176,7 @@ public void testSkipRegenerationForClasspathSpecFileWithChange() throws Exceptio
public void testCollapsedSpecProduced() throws Exception {
// GIVEN
Path folder = Files.createTempDirectory("test");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "executionId");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "file", "executionId");

// WHEN
mojo.execute();
Expand All @@ -172,7 +189,7 @@ public void testCollapsedSpecProduced() throws Exception {
public void testCollapsedSpecAddedToArtifacts() throws Exception {
// GIVEN
Path folder = Files.createTempDirectory("test");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "executionId");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "file", "executionId");

// WHEN
mojo.execute();
Expand All @@ -187,7 +204,7 @@ public void testCollapsedSpecAddedToArtifacts() throws Exception {
public void testAnyInputSpecMustBeProvided() throws Exception {
// GIVEN
Path folder = Files.createTempDirectory("test");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "executionId");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "file", "executionId");
mojo.inputSpec = null;
mojo.inputSpecRootDirectory = null;

Expand All @@ -201,7 +218,7 @@ public void testAnyInputSpecMustBeProvided() throws Exception {
public void testInputSpecRootDirectoryDoesNotRequireInputSpec() throws Exception {
// GIVEN
Path folder = Files.createTempDirectory("test");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "executionId");
CodeGenMojo mojo = loadMojo(folder.toFile(), "src/test/resources/default", "file", "executionId");
mojo.inputSpec = null;
mojo.inputSpecRootDirectory = "src/test/resources/default";

Expand All @@ -214,14 +231,14 @@ public void testInputSpecRootDirectoryDoesNotRequireInputSpec() throws Exception
assertTrue(hashFolder.resolve("_merged_spec.yaml-executionId.sha256").toFile().exists());
}

protected CodeGenMojo loadMojo(File temporaryFolder, String projectRoot) throws Exception {
return loadMojo(temporaryFolder, projectRoot, "default");
protected CodeGenMojo loadMojo(File temporaryFolder, String projectRoot, String profile) throws Exception {
return loadMojo(temporaryFolder, projectRoot, profile, "default");
}

protected CodeGenMojo loadMojo(File temporaryFolder, String projectRoot, String executionId) throws Exception {
protected CodeGenMojo loadMojo(File temporaryFolder, String projectRoot, String profile, String executionId) throws Exception {
File file = new File(projectRoot);
FileUtils.copyDirectory(file, temporaryFolder);
MavenProject project = readMavenProject(temporaryFolder);
MavenProject project = readMavenProject(temporaryFolder, profile);
MavenSession session = newMavenSession(project);
MojoExecution execution = newMojoExecution("generate");
MojoExecution executionWithId = copyWithExecutionId(executionId, execution);
Expand All @@ -234,15 +251,22 @@ private MojoExecution copyWithExecutionId(String executionId, MojoExecution exec
return executionWithId;
}

protected MavenProject readMavenProject(File basedir)
protected MavenProject readMavenProject(File basedir, String profile)
throws Exception {
File pom = new File(basedir, "pom.xml");
LocalRepository localRepo = new LocalRepository(new File(basedir, "local-repo"));
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
session.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory().newInstance(session, localRepo));
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
request.setBaseDirectory(basedir);
if (profile != null) {
request.addActiveProfile(profile);
}
ProjectBuildingRequest configuration = request.getProjectBuildingRequest();
configuration.setRepositorySession(new DefaultRepositorySystemSession());
configuration.setRepositorySession(session);
configuration.setResolveDependencies(true);
MavenProject project = lookup(ProjectBuilder.class).build(pom, configuration).getProject();
assertNotNull(project);
return project;
}
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>petstore</groupId>
<artifactId>schema</artifactId>
<version>1</version>
<description>POM was created from install:install-file</description>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>petstore</groupId>
<artifactId>schema</artifactId>
<versioning>
<release>1</release>
<versions>
<version>1</version>
</versions>
<lastUpdated>20210724220722</lastUpdated>
</versioning>
</metadata>
Loading

0 comments on commit 9a35914

Please sign in to comment.