) getVariableValueFromObject(mojo, "configOptions");
+ assertNotNull(configOptions);
+ assertEquals("joda", configOptions.get("dateLibrary"));
+ }
+}
\ No newline at end of file
diff --git a/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/CommonMavenProjectStub.java b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/CommonMavenProjectStub.java
new file mode 100644
index 00000000000..9577061f0a8
--- /dev/null
+++ b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/CommonMavenProjectStub.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2020 OpenAPI-Generator Contributors (https://openapi-generator.tech)
+ *
+ * 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.
+ */
+
+package org.openapitools.codegen.plugin.stubs;
+
+import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
+
+public class CommonMavenProjectStub extends MavenProjectStub {
+ public CommonMavenProjectStub() {
+ StubUtility.configureStub(this,"common-maven", "common-maven.xml");
+ }
+}
diff --git a/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/StubUtility.java b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/StubUtility.java
new file mode 100644
index 00000000000..c7ccd1a2a9e
--- /dev/null
+++ b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/StubUtility.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020 OpenAPI-Generator Contributors (https://openapi-generator.tech)
+ *
+ * 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.
+ */
+
+package org.openapitools.codegen.plugin.stubs;
+
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.plugin.testing.stubs.ArtifactStub;
+import org.apache.maven.plugin.testing.stubs.DefaultArtifactHandlerStub;
+import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class StubUtility {
+ private StubUtility() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Configures a stub to conventional directories based on test name and pom file name.
+ *
+ * Taken largely from PMD plugin:
+ * https://github.com/apache/maven-pmd-plugin/blob/d766fdb0c93a6630ad7a788f260746b05c804a71/src/test/java/org/apache/maven/plugins/pmd/stubs/CustomConfigurationMavenProjectStub.java
+ * License: Apache 2.0
+ *
+ * @param configure The stub to configure
+ * @param testName A name used to identify this stub, used in resource lookup
+ * @param pomFileName The filename and extension, e.g. "my-test-pom.xml"
+ */
+ public static void configureStub(MavenProjectStub configure, String testName, String pomFileName) {
+ MavenXpp3Reader pomReader = new MavenXpp3Reader();
+ Model model = null;
+ try {
+ File pomFile = basedPath(
+ configure.getBasedir(), "src", "test", "resources", "unit", testName, pomFileName
+ ).toFile();
+ model = pomReader.read(new InputStreamReader(new FileInputStream(pomFile), StandardCharsets.UTF_8));
+ configure.setModel(model);
+ } catch (Exception ignored) {
+
+ }
+
+ configure.setGroupId(model.getGroupId());
+ configure.setArtifactId(model.getArtifactId());
+ configure.setVersion(model.getVersion());
+ configure.setName(model.getName());
+ configure.setUrl(model.getUrl());
+ configure.setPackaging(model.getPackaging());
+
+ Build build = new Build();
+ build.setFinalName(model.getBuild().getFinalName());
+ build.setDirectory(basedPath(configure.getBasedir(), "target", "test", "unit", testName, "target").toString());
+ build.setSourceDirectory(basedPath(configure.getBasedir(), "src", "test", "resources", "unit", testName).toString());
+ configure.setBuild(build);
+
+ List compileSourceRoots = new ArrayList<>();
+ compileSourceRoots.add(basedPath(configure.getBasedir(), "src", "test", "resources", "unit", testName, "src").toString());
+ configure.setCompileSourceRoots(compileSourceRoots);
+
+ ArtifactStub artifactStub = new ArtifactStub();
+ artifactStub.setGroupId(configure.getGroupId());
+ artifactStub.setArtifactId(configure.getArtifactId());
+ artifactStub.setVersion(configure.getVersion());
+ artifactStub.setArtifactHandler(new DefaultArtifactHandlerStub("jar"));
+ configure.setArtifact(artifactStub);
+
+ configure.setFile(configure.getBasedir().toPath().resolve(pomFileName).toFile());
+ }
+
+ public static Path basedPath(File baseDir, String first, String... more) {
+ return baseDir.toPath().resolve(Paths.get(first, more)).normalize().toAbsolutePath();
+ }
+}
diff --git a/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/common-maven.xml b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/common-maven.xml
new file mode 100644
index 00000000000..767caeab2dd
--- /dev/null
+++ b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/common-maven.xml
@@ -0,0 +1,56 @@
+
+
+
+ 4.0.0
+ common.maven
+ common-maven
+ jar
+ 1.0.0-SNAPSHOT
+ OpenAPI Generator Configuration Test
+ https://openapi-generator.tech/
+
+ common-maven
+
+
+ org.openapitools
+ openapi-generator-maven-plugin
+
+
+ ${basedir}/src/test/resources/unit/common-maven/petstore.yaml
+ java
+
+ joda
+
+ jersey2
+
+ remote.org.openapitools.client.api
+ remote.org.openapitools.client.model
+ remote.org.openapitools.client
+
+
+
+ default
+ generate-sources
+
+ generate
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/petstore.yaml b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/petstore.yaml
new file mode 100644
index 00000000000..f5e98eec38d
--- /dev/null
+++ b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/petstore.yaml
@@ -0,0 +1,736 @@
+openapi: 3.0.0
+servers:
+ - url: 'http://petstore.swagger.io/v2'
+info:
+ description: >-
+ This is a sample server Petstore server. For this sample, you can use the api key
+ `special-key` to test the authorization filters.
+ version: 1.0.0
+ title: OpenAPI Petstore
+ license:
+ name: Apache-2.0
+ url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
+tags:
+ - name: pet
+ description: Everything about your Pets
+ - name: store
+ description: Access to Petstore orders
+ - name: user
+ description: Operations about user
+paths:
+ /pet:
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store
+ description: ''
+ operationId: addPet
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ '405':
+ description: Invalid input
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ requestBody:
+ $ref: '#/components/requestBodies/Pet'
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet
+ description: ''
+ operationId: updatePet
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ '400':
+ description: Invalid ID supplied
+ '404':
+ description: Pet not found
+ '405':
+ description: Validation exception
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ requestBody:
+ $ref: '#/components/requestBodies/Pet'
+ /pet/findByStatus:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by status
+ description: Multiple status values can be provided with comma separated strings
+ operationId: findPetsByStatus
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: true
+ style: form
+ explode: false
+ schema:
+ type: array
+ items:
+ type: string
+ enum:
+ - available
+ - pending
+ - sold
+ default: available
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ '400':
+ description: Invalid status value
+ security:
+ - petstore_auth:
+ - 'read:pets'
+ /pet/findByTags:
+ get:
+ tags:
+ - pet
+ summary: Finds Pets by tags
+ description: >-
+ Multiple tags can be provided with comma separated strings. Use tag1,
+ tag2, tag3 for testing.
+ operationId: findPetsByTags
+ parameters:
+ - name: tags
+ in: query
+ description: Tags to filter by
+ required: true
+ style: form
+ explode: false
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ '400':
+ description: Invalid tag value
+ security:
+ - petstore_auth:
+ - 'read:pets'
+ deprecated: true
+ '/pet/{petId}':
+ get:
+ tags:
+ - pet
+ summary: Find pet by ID
+ description: Returns a single pet
+ operationId: getPetById
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ '400':
+ description: Invalid ID supplied
+ '404':
+ description: Pet not found
+ security:
+ - api_key: []
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data
+ description: ''
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '405':
+ description: Invalid input
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ requestBody:
+ content:
+ application/x-www-form-urlencoded:
+ schema:
+ type: object
+ properties:
+ name:
+ description: Updated name of the pet
+ type: string
+ status:
+ description: Updated status of the pet
+ type: string
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet
+ description: ''
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '400':
+ description: Invalid pet value
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ '/pet/{petId}/uploadImage':
+ post:
+ tags:
+ - pet
+ summary: uploads an image
+ description: ''
+ operationId: uploadFile
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ApiResponse'
+ security:
+ - petstore_auth:
+ - 'write:pets'
+ - 'read:pets'
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ additionalMetadata:
+ description: Additional data to pass to server
+ type: string
+ file:
+ description: file to upload
+ type: string
+ format: binary
+ /store/inventory:
+ get:
+ tags:
+ - store
+ summary: Returns pet inventories by status
+ description: Returns a map of status codes to quantities
+ operationId: getInventory
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet
+ description: ''
+ operationId: placeOrder
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ '400':
+ description: Invalid Order
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ description: order placed for purchasing the pet
+ required: true
+ '/store/order/{orderId}':
+ get:
+ tags:
+ - store
+ summary: Find purchase order by ID
+ description: >-
+ For valid response try integer IDs with value <= 5 or > 10. Other values
+ will generated exceptions
+ operationId: getOrderById
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of pet that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ minimum: 1
+ maximum: 5
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ '400':
+ description: Invalid ID supplied
+ '404':
+ description: Order not found
+ delete:
+ tags:
+ - store
+ summary: Delete purchase order by ID
+ description: >-
+ For valid response try integer IDs with value < 1000. Anything above
+ 1000 or nonintegers will generate API errors
+ operationId: deleteOrder
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ '400':
+ description: Invalid ID supplied
+ '404':
+ description: Order not found
+ /user:
+ post:
+ tags:
+ - user
+ summary: Create user
+ description: This can only be done by the logged in user.
+ operationId: createUser
+ responses:
+ default:
+ description: successful operation
+ security:
+ - api_key: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ description: Created user object
+ required: true
+ /user/createWithArray:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array
+ description: ''
+ operationId: createUsersWithArrayInput
+ responses:
+ default:
+ description: successful operation
+ security:
+ - api_key: []
+ requestBody:
+ $ref: '#/components/requestBodies/UserArray'
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array
+ description: ''
+ operationId: createUsersWithListInput
+ responses:
+ default:
+ description: successful operation
+ security:
+ - api_key: []
+ requestBody:
+ $ref: '#/components/requestBodies/UserArray'
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system
+ description: ''
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: true
+ schema:
+ type: string
+ pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ headers:
+ Set-Cookie:
+ description: >-
+ Cookie authentication key for use with the `api_key`
+ apiKey authentication.
+ schema:
+ type: string
+ example: AUTH_KEY=abcde12345; Path=/; HttpOnly
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when toekn expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ '400':
+ description: Invalid username/password supplied
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session
+ description: ''
+ operationId: logoutUser
+ responses:
+ default:
+ description: successful operation
+ security:
+ - api_key: []
+ '/user/{username}':
+ get:
+ tags:
+ - user
+ summary: Get user by user name
+ description: ''
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be fetched. Use user1 for testing.
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ '400':
+ description: Invalid username supplied
+ '404':
+ description: User not found
+ put:
+ tags:
+ - user
+ summary: Updated user
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ '400':
+ description: Invalid user supplied
+ '404':
+ description: User not found
+ security:
+ - api_key: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ description: Updated user object
+ required: true
+ delete:
+ tags:
+ - user
+ summary: Delete user
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ '400':
+ description: Invalid username supplied
+ '404':
+ description: User not found
+ security:
+ - api_key: []
+externalDocs:
+ description: Find out more about Swagger
+ url: 'http://swagger.io'
+components:
+ requestBodies:
+ UserArray:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ description: List of user object
+ required: true
+ Pet:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ description: Pet object that needs to be added to the store
+ required: true
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog'
+ scopes:
+ 'write:pets': modify pets in your account
+ 'read:pets': read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: header
+ schemas:
+ Order:
+ title: Pet Order
+ description: An order for a pets from the pet store
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ petId:
+ type: integer
+ format: int64
+ quantity:
+ type: integer
+ format: int32
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ default: false
+ xml:
+ name: Order
+ Category:
+ title: Pet category
+ description: A category for a pet
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
+ xml:
+ name: Category
+ User:
+ title: a User
+ description: A User who is purchasing from the pet store
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ username:
+ type: string
+ firstName:
+ type: string
+ lastName:
+ type: string
+ email:
+ type: string
+ password:
+ type: string
+ phone:
+ type: string
+ userStatus:
+ type: integer
+ format: int32
+ description: User Status
+ xml:
+ name: User
+ Tag:
+ title: Pet Tag
+ description: A tag for a pet
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: Tag
+ Pet:
+ title: a Pet
+ description: A pet for sale in the pet store
+ type: object
+ required:
+ - name
+ - photoUrls
+ properties:
+ id:
+ type: integer
+ format: int64
+ category:
+ $ref: '#/components/schemas/Category'
+ name:
+ type: string
+ example: doggie
+ photoUrls:
+ type: array
+ xml:
+ name: photoUrl
+ wrapped: true
+ items:
+ type: string
+ tags:
+ type: array
+ xml:
+ name: tag
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Tag'
+ status:
+ type: string
+ description: pet status in the store
+ enum:
+ - available
+ - pending
+ - sold
+ xml:
+ name: Pet
+ ApiResponse:
+ title: An uploaded response
+ description: Describes the result of uploading an image resource
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ type:
+ type: string
+ message:
+ type: string
diff --git a/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/src/main/java/com/example/Example.java b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/src/main/java/com/example/Example.java
new file mode 100644
index 00000000000..8447f00216d
--- /dev/null
+++ b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/src/main/java/com/example/Example.java
@@ -0,0 +1,7 @@
+package com.example;
+
+public class Example {
+ public static void main(String[] args) {
+ System.out.println("You did it!");
+ }
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java
index 14b71d86538..861b9bc3a3d 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java
@@ -6,6 +6,7 @@ import org.openapitools.codegen.TemplateManager;
import org.openapitools.codegen.api.TemplatePathLocator;
import java.io.File;
+import java.nio.file.Paths;
/**
* Locates templates according to {@link CodegenConfig} settings.
@@ -23,7 +24,7 @@ public class GeneratorTemplateContentLocator implements TemplatePathLocator {
}
private String buildLibraryFilePath(String dir, String library, String file) {
- return dir + File.separator + "libraries" + File.separator + library + File.separator + file;
+ return Paths.get(dir, "libraries", library, file).normalize().toString();
}
/**
@@ -34,6 +35,10 @@ public class GeneratorTemplateContentLocator implements TemplatePathLocator {
* @return true if file is an embedded resource, false if it does not exist
*/
public boolean embeddedTemplateExists(String name) {
+ return classpathTemplateExists(name);
+ }
+
+ private boolean classpathTemplateExists(String name) {
return this.getClass().getClassLoader().getResource(TemplateManager.getCPResourcePath(name)) != null;
}
@@ -60,20 +65,26 @@ public class GeneratorTemplateContentLocator implements TemplatePathLocator {
if (StringUtils.isNotEmpty(library)) {
//look for the file in the library subfolder of the supplied template
final String libTemplateFile = buildLibraryFilePath(config.templateDir(), library, relativeTemplateFile);
- if (new File(libTemplateFile).exists() || this.getClass().getClassLoader().getResource(libTemplateFile) != null) {
+ // looks for user-defined file or classpath
+ // supports template dir which refers to local file system or custom path in classpath as defined by templateDir
+ if (new File(libTemplateFile).exists() || classpathTemplateExists(libTemplateFile)) {
return libTemplateFile;
}
}
- //check the supplied template main folder for the file
+ // check the supplied template main folder for the file
+ // File.separator is necessary here as the file load is OS-specific
final String template = config.templateDir() + File.separator + relativeTemplateFile;
- if (new File(template).exists() || this.getClass().getClassLoader().getResource(template) != null) {
+ // looks for user-defined file or classpath
+ // supports template dir which refers to local file system or custom path in classpath as defined by templateDir
+ if (new File(template).exists() || classpathTemplateExists(template)) {
return template;
}
//try the embedded template library folder next
if (StringUtils.isNotEmpty(library)) {
final String embeddedLibTemplateFile = buildLibraryFilePath(config.embeddedTemplateDir(), library, relativeTemplateFile);
+ // *only* looks for those files in classpath as defined by embeddedTemplateDir
if (embeddedTemplateExists(embeddedLibTemplateFile)) {
// Fall back to the template file embedded/packaged in the JAR file library folder...
return embeddedLibTemplateFile;
@@ -82,6 +93,7 @@ public class GeneratorTemplateContentLocator implements TemplatePathLocator {
// Fall back to the template file for generator root directory embedded/packaged in the JAR file...
String loc = config.embeddedTemplateDir() + File.separator + relativeTemplateFile;
+ // *only* looks for those files in classpath as defined by embeddedTemplateDir
if (embeddedTemplateExists(loc)) {
return loc;
}
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java
index 1a1806d6f83..1bf5dc70257 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java
@@ -433,4 +433,208 @@ public class DefaultGeneratorTest {
Assert.assertEquals(((Schema) codegenResponse.schema).getPattern(), expectedPattern);
Assert.assertEquals(codegenResponse.pattern, escapedPattern);
}
+
+ @Test
+ public void testBuiltinLibraryTemplates() throws IOException {
+ Path target = Files.createTempDirectory("test");
+ File output = target.toFile();
+ try {
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("kotlin")
+ .setLibrary("jvm-okhttp4")
+ .setInputSpec("src/test/resources/3_0/petstore.yaml")
+ .setSkipOverwrite(false)
+ .setOutputDir(target.toAbsolutePath().toString());
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator(false);
+
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true");
+ generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.API_TESTS, "false");
+
+ List files = generator.opts(clientOptInput).generate();
+
+ Assert.assertEquals(files.size(), 20);
+
+ // Generator should report a library templated file as a generated file
+ TestUtils.ensureContainsFile(files, output, "src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt");
+
+ // Generated file should exist on the filesystem after generation
+ File generatedFile = new File(output, "src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt");
+ Assert.assertTrue(generatedFile.exists());
+
+ // Generated file should contain some expected text
+ TestUtils.assertFileContains(generatedFile.toPath(), "package org.openapitools.client.infrastructure",
+ "open class ClientException",
+ "open class ServerException");
+ } finally {
+ output.delete();
+ }
+ }
+
+ @Test
+ public void testBuiltinNonLibraryTemplates() throws IOException {
+ Path target = Files.createTempDirectory("test");
+ File output = target.toFile();
+ try {
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("kotlin")
+ .setInputSpec("src/test/resources/3_0/petstore.yaml")
+ .setSkipOverwrite(false)
+ .setOutputDir(target.toAbsolutePath().toString());
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator(false);
+
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true");
+ generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.API_TESTS, "false");
+
+ List files = generator.opts(clientOptInput).generate();
+
+ Assert.assertEquals(files.size(), 20);
+
+ // Generator should report README.md as a generated file
+ TestUtils.ensureContainsFile(files, output, "README.md");
+
+ // Generated file should exist on the filesystem after generation
+ File readme = new File(output, "README.md");
+ Assert.assertTrue(readme.exists());
+
+ // README.md should contain some expected text
+ TestUtils.assertFileContains(readme.toPath(), "# org.openapitools.client - Kotlin client library for OpenAPI Petstore",
+ "## Requires",
+ "## Build",
+ "## Features/Implementation Notes");
+ } finally {
+ output.delete();
+ }
+ }
+
+ @Test
+ public void testCustomLibraryTemplates() throws IOException {
+ Path target = Files.createTempDirectory("test");
+ Path templates = Files.createTempDirectory("templates");
+ File output = target.toFile();
+ try {
+ // Create custom template
+ File customTemplate = new File(templates.toFile(), "libraries/jvm-okhttp/infrastructure/Errors.kt.mustache");
+ new File(customTemplate.getParent()).mkdirs();
+ StringBuilder sb = new StringBuilder();
+ sb.append("// {{someKey}}").append("\n");
+ sb.append("@file:Suppress(\"unused\")").append("\n");
+ sb.append("package org.openapitools.client.infrastructure").append("\n");
+ sb.append("import java.lang.RuntimeException").append("\n");
+ sb.append("open class CustomException(").append("\n");
+ sb.append(" message: kotlin.String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) {").append("\n");
+ sb.append(" companion object {").append("\n");
+ sb.append(" private const val serialVersionUID: Long = 789L").append("\n");
+ sb.append(" }").append("\n");
+ sb.append("}").append("\n");
+ Files.write(customTemplate.toPath(),
+ sb.toString().getBytes(StandardCharsets.UTF_8),
+ StandardOpenOption.CREATE);
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("kotlin")
+ .addAdditionalProperty("someKey", "testCustomLibraryTemplates")
+ .setTemplateDir(templates.toAbsolutePath().toString())
+ .setLibrary("jvm-okhttp4")
+ .setInputSpec("src/test/resources/3_0/petstore.yaml")
+ .setSkipOverwrite(false)
+ .setOutputDir(target.toAbsolutePath().toString());
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator(false);
+
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true");
+ generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.API_TESTS, "false");
+
+ List files = generator.opts(clientOptInput).generate();
+
+ Assert.assertEquals(files.size(), 20);
+
+ // Generator should report a library templated file as a generated file
+ TestUtils.ensureContainsFile(files, output, "src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt");
+
+ // Generated file should exist on the filesystem after generation
+ File readme = new File(output, "src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt");
+ Assert.assertTrue(readme.exists());
+
+ // Generated file should contain our custom templated text
+ TestUtils.assertFileContains(readme.toPath(), "// testCustomLibraryTemplates",
+ "package org.openapitools.client.infrastructure",
+ "open class CustomException(",
+ "private const val serialVersionUID: Long = 789L");
+ } finally {
+ output.delete();
+ templates.toFile().delete();
+ }
+ }
+
+ @Test
+ public void testCustomNonLibraryTemplates() throws IOException {
+ Path target = Files.createTempDirectory("test");
+ Path templates = Files.createTempDirectory("templates");
+ File output = target.toFile();
+ try {
+ // Create custom template
+ File customTemplate = new File(templates.toFile(), "README.mustache");
+ new File(customTemplate.getParent()).mkdirs();
+ Files.write(customTemplate.toPath(),
+ "# {{someKey}}".getBytes(StandardCharsets.UTF_8),
+ StandardOpenOption.CREATE);
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("kotlin")
+ .addAdditionalProperty("someKey", "testCustomNonLibraryTemplates")
+ .setTemplateDir(templates.toAbsolutePath().toString())
+ .setInputSpec("src/test/resources/3_0/petstore.yaml")
+ .setSkipOverwrite(false)
+ .setOutputDir(target.toAbsolutePath().toString());
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator(false);
+
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true");
+ generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
+ generator.setGeneratorPropertyDefault(CodegenConstants.API_TESTS, "false");
+
+ List files = generator.opts(clientOptInput).generate();
+
+ Assert.assertEquals(files.size(), 20);
+
+ // Generator should report README.md as a generated file
+ TestUtils.ensureContainsFile(files, output, "README.md");
+
+ // Generated file should exist on the filesystem after generation
+ File readme = new File(output, "README.md");
+ Assert.assertTrue(readme.exists());
+
+ // README.md should contain our custom templated text
+ TestUtils.assertFileContains(readme.toPath(), "# testCustomNonLibraryTemplates");
+ } finally {
+ output.delete();
+ templates.toFile().delete();
+ }
+ }
}
+