Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

An example Maven project that uses the OpenAPI Generator Maven plugin with template customization to generate an API model and server

License

NotificationsYou must be signed in to change notification settings

sigpwned/openapi-generator-maven-plugin-template-customization-example

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Motivation

TheOpenAPIGenerator is amarvelous piece of technology. It allows users to generate model,interface, and implementation code for server and client for a varietyof platforms from an OpenAPI spec quickly and easily. At least, fordefault configurations.

But sometimes users need to do something outside of thedefault. Fortunately, the project offers rich capabilities fortemplate andad-hoccustomization. Unfortunately, those customization features can bedifficult to set up and use in practice.

This project is aSSCCE for performing templatecustomization using the OpenAPI Generator Maven Plugin. The chosencustomization usesextensionsto add per-method support for JAX-RS 2.0@Suspended AsyncResponsefeatures to thejaxrs-specgenerator. If anyone happens to needAsyncResponse code generationfor the OpenAPI Generator Maven Plugin, this should work out of thebox.

This project is also a fine starting point for a Reasonable Default ofusing the OpenAPI Generator Maven Plugin, for anyone looking for anexample to start from.

Introduction

Let's dive into the particulars of this example.

OpenAPI Spec

The OpenAPI spec for this example is very simple:

openapi: 3.0.2info:  title: OpenAPI Generator Maven Plugin Template Customization Example  description: An example Maven project that uses the OpenAPI Generator Maven plugin with template customization to generate an API model and server.  contact:    email: andy.boothe@gmail.com  version: 0.0.0servers:  - url: http://localhost:8080/v1tags:  - name: example    description: Example endpointpaths:  /greet:    post:      tags:        - example      summary: Greet the user      description: Generate a greeting for the given name      operationId: greet      # We can set determine whether each method is synchronous or asynchronous using this flag.      # This particular option is an extension, so you won't find documentation for it anywhere.      # Implementing it is the point of this exercise.      x-async-enabled: false      requestBody:        description: The name to greet        content:          application/json:            schema:              $ref: '#/components/schemas/Name'      responses:        200:          description: The greeting was generated successfully          content:            application/json:              schema:                $ref: '#/components/schemas/Greeting'components:  schemas:    Name:      type: object      properties:        name:          type: string    Greeting:      type: object      properties:        greeting:          type: string

There is one endpoint, which generates a greeting given a name, andone model object each for a Name and a Greeting. We'll be looking atcode generated for this spec a little later on.

POM

Naturally, the OpenAPI Generator Maven Plugin is configured using thePOM. This project uses a reasonably simple and sane configuration ofthe plugin:

<configuration>    <!-- This section includes the "global" configuration options, so called because they apply to all generators. Users generally don't need to care about this dxcept to make sure their configuration information lands in the correct place - <configuration> vs <configOptions>. -->    <!-- https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin -->    <!-- The OpenAPI spec is in a file in this repository called "openapi.yml". It can also be a hyperlink. -->    <inputSpec>openapi.yml</inputSpec>    <!-- There are many generators available. We are using jaxrs-spec. -->    <generatorName>jaxrs-spec</generatorName>    <!-- APIs are service interfaces or implementations. -->    <generateApis>true</generateApis>    <!-- Models are DTOs, generally from the schemas portion of the spec. -->    <generateModels>true</generateModels>    <!-- In this example, we're not generating the POM, README, etc. Just the code, ma'am. -->    <generateSupportingFiles>false</generateSupportingFiles>    <!-- We are showing off template customization today. The custom templates are stored here. -->    <templateDirectory>${project.basedir}/openapi/templates</templateDirectory>    <!-- This is the director where generated code will be stored. The plugin automatically adds this directory to your build. This is the default value. You generally don't need to change this, but it's worth calling out in this example so users know where to look for generated code. -->    <output>${project.build.directory}/generated-sources/openapi</output>    <configOptions>        <!-- These are the "local" configuration options that apply only to this generator. -->        <!-- https://openapi-generator.tech/docs/generators/jaxrs-spec -->        <!-- These are the packages we want our APIs and Models generated in, respectively. -->        <apiPackage>com.sigpwned.greeting.spi.service</apiPackage>        <modelPackage>com.sigpwned.greeting.spi.model</modelPackage>        <!-- I personally consider these to be best practices. However, they are up to you! -->        <dateLibrary>java8</dateLibrary>        <useSwaggerAnnotations>false</useSwaggerAnnotations>        <!-- These values are largely up to you, and depend on your goals and philosophy. This SSCCE should support all permutations of the below. -->        <!-- I prefer to have interface methods return model objects, not JAX-RS Response objects. I can still generate any response I want by throwing WebApplicationException classes. -->        <!-- If this is set to true, then all generated service methods will return javax.ws.rs.core.Response objects. -->        <!-- If this is set to false, then all generated service methods will return their respective model objects. -->        <returnResponse>false</returnResponse>        <!-- I prefer to generate interfaces, not implementation. This allows me to make sure that my client and server implementations are in sync. -->        <!-- If this is set to true, then service interfaces will be generated. -->        <!-- If this is set to false, then service implementations will be generated. -->        <interfaceOnly>true</interfaceOnly>        <!-- This is a useful feature for web frameworks that support the JAX-RS 2.1 feature of implementing asynchronous processing by returning CompletionStage instances. In all cases, generated service methods return either Response or a model object, depending on the above configuration. This configuration option affects all methods. Users cannot choose to make individual methods synchronous versus asynchronous.  -->        <!-- If this is set to true, then all generated service method return types will be changed from T to CompletionStage<T>. -->        <!-- If this is set to false, then all generate service method return types will be unchanged. -->        <supportAsync>false</supportAsync>    </configOptions></configuration>

The<configuration> (as opposed to<configOptions>) portion ofthis project is largely boilerplate, and won't change much even if youswitch generators. The<configOptions> section is much more tailoredto the task. In the default example, note that we are generatinginterfaces that return model objects synchronously.

Default Behavior

Before we dive into template customization, let's understand thegenerator's out-of-the-box functionality first. Some of this isspecific to thejaxrs-spec generator, but much of it is universal toall generators.

Running the build

Let's run the maven build with this default configuration. Thisproduces the following output:

$ mvn clean compile[INFO] Scanning for projects...[INFO] [INFO] --< com.sigpwned:openapi-generator-maven-plugin-template-customization-example >--[INFO] Building openapi-generator-maven-plugin-template-customization-example 0.0.0-SNAPSHOT[INFO] --------------------------------[ pom ]---------------------------------[INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ openapi-generator-maven-plugin-template-customization-example ---[INFO] Deleting /Users/aboothe/eclipse-workspace/openapi-generator-maven-plugin-template-customization-example/target[INFO] [INFO] --- openapi-generator-maven-plugin:5.4.0:generate (generate) @ openapi-generator-maven-plugin-template-customization-example ---[INFO] Generating with dryRun=false[INFO] Output directory (/Users/aboothe/eclipse-workspace/openapi-generator-maven-plugin-template-customization-example/target/generated-sources/openapi) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.[INFO] OpenAPI Generator: jaxrs-spec (server)[INFO] Generator 'jaxrs-spec' is considered stable.[INFO] Environment variable JAVA_POST_PROCESS_FILE not defined so the Java code may not be properly formatted. To define it, try 'export JAVA_POST_PROCESS_FILE="/usr/local/bin/clang-format -i"' (Linux/Mac)[INFO] NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).[INFO] Invoker Package Name, originally not set, is now derived from api package name: com.sigpwned.greeting.spi[INFO] Processing operation greet[INFO] writing file /Users/aboothe/eclipse-workspace/openapi-generator-maven-plugin-template-customization-example/target/generated-sources/openapi/src/gen/java/com/sigpwned/greeting/spi/model/Greeting.java[INFO] writing file /Users/aboothe/eclipse-workspace/openapi-generator-maven-plugin-template-customization-example/target/generated-sources/openapi/src/gen/java/com/sigpwned/greeting/spi/model/Name.java[INFO] writing file /Users/aboothe/eclipse-workspace/openapi-generator-maven-plugin-template-customization-example/target/generated-sources/openapi/src/gen/java/com/sigpwned/greeting/spi/service/GreetApi.java[INFO] Skipping generation of supporting files.################################################################################# Thanks for using OpenAPI Generator.                                          ## Please consider donation to help us maintain this project 🙏                 ## https://opencollective.com/openapi_generator/donate                          #################################################################################[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time:  0.679 s[INFO] Finished at: 2022-04-07T11:54:52-05:00[INFO] ------------------------------------------------------------------------

The OpenAPI Generator Maven Plugin generates some useful diagnosticand progress output. In particular, it logs the files it generates,which is a good starting point to confirm you're generating the codeyou want.

Of course, you can generate a lot more output withmvn -X -e generate-sources.

Checking the code

Let's see what code we generated:

$ find target/generated-sources/openapi -type f                                      target/generated-sources/openapi/.openapi-generator/openapi.yml-generate.sha256target/generated-sources/openapi/src/gen/java/com/sigpwned/greeting/spi/model/Greeting.javatarget/generated-sources/openapi/src/gen/java/com/sigpwned/greeting/spi/model/Name.javatarget/generated-sources/openapi/src/gen/java/com/sigpwned/greeting/spi/service/GreetApi.java$ cat target/generated-sources/openapi/src/gen/java/com/sigpwned/greeting/spi/model/Greeting.javapackage com.sigpwned.greeting.spi.model;import javax.validation.constraints.*;import javax.validation.Valid;import java.util.Objects;import com.fasterxml.jackson.annotation.JsonProperty;import com.fasterxml.jackson.annotation.JsonCreator;import com.fasterxml.jackson.annotation.JsonValue;import com.fasterxml.jackson.annotation.JsonTypeName;@JsonTypeName("Greeting")@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", date = "2022-04-07T11:54:52.045724-05:00[America/Chicago]")public class Greeting   {    private @Valid String greeting;  /**   **/  public Greeting greeting(String greeting) {    this.greeting = greeting;    return this;  }      @JsonProperty("greeting")  public String getGreeting() {    return greeting;  }  @JsonProperty("greeting")  public void setGreeting(String greeting) {    this.greeting = greeting;  }  @Override  public boolean equals(Object o) {    if (this == o) {      return true;    }    if (o == null || getClass() != o.getClass()) {      return false;    }    Greeting greeting = (Greeting) o;    return Objects.equals(this.greeting, greeting.greeting);  }  @Override  public int hashCode() {    return Objects.hash(greeting);  }  @Override  public String toString() {    StringBuilder sb = new StringBuilder();    sb.append("class Greeting {\n");        sb.append("    greeting: ").append(toIndentedString(greeting)).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(Object o) {    if (o == null) {      return "null";    }    return o.toString().replace("\n", "\n    ");  }}$ cat target/generated-sources/openapi/src/gen/java/com/sigpwned/greeting/spi/model/Name.javapackage com.sigpwned.greeting.spi.model;import javax.validation.constraints.*;import javax.validation.Valid;import java.util.Objects;import com.fasterxml.jackson.annotation.JsonProperty;import com.fasterxml.jackson.annotation.JsonCreator;import com.fasterxml.jackson.annotation.JsonValue;import com.fasterxml.jackson.annotation.JsonTypeName;@JsonTypeName("Name")@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", date = "2022-04-07T11:54:52.045724-05:00[America/Chicago]")public class Name   {    private @Valid String name;  /**   **/  public Name name(String name) {    this.name = name;    return this;  }      @JsonProperty("name")  public String getName() {    return name;  }  @JsonProperty("name")  public void setName(String name) {    this.name = name;  }  @Override  public boolean equals(Object o) {    if (this == o) {      return true;    }    if (o == null || getClass() != o.getClass()) {      return false;    }    Name name = (Name) o;    return Objects.equals(this.name, name.name);  }  @Override  public int hashCode() {    return Objects.hash(name);  }  @Override  public String toString() {    StringBuilder sb = new StringBuilder();    sb.append("class Name {\n");        sb.append("    name: ").append(toIndentedString(name)).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(Object o) {    if (o == null) {      return "null";    }    return o.toString().replace("\n", "\n    ");  }}$ cat target/generated-sources/openapi/src/gen/java/com/sigpwned/greeting/spi/service/GreetApi.javapackage com.sigpwned.greeting.spi.service;import com.sigpwned.greeting.spi.model.Greeting;import com.sigpwned.greeting.spi.model.Name;import javax.ws.rs.*;import javax.ws.rs.core.Response;import java.util.concurrent.CompletionStage;import java.util.concurrent.CompletableFuture;import java.io.InputStream;import java.util.Map;import java.util.List;import javax.validation.constraints.*;import javax.validation.Valid;@Path("/greet")@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", date = "2022-04-07T11:54:52.045724-05:00[America/Chicago]")public interface GreetApi {    @POST    @Consumes({ "application/json" })    @Produces({ "application/json" })    Greeting greet(@Valid Name name);}

Generated Model Classes

We have two Model classes --Greeting andName -- which correspondto our named model objects from the spec. They are totally genericPOJOs. They support a default constructor, private attributes withaccessors, plus sane implementations ofhashCode,equals, andtoString.

The generator does exactly what it says on the tin here, and we aren'tcustomizing the Model objects in this example, so we won't spend anymore time looking at the Model objects here.

Generated API Classes

The API class is more interesting.

We have one endpoint,POST /greet, so we have one method across allgenerated API classes. That method is calledgreet, which is itsoperationId in the spec.

Methods are collected into classes by the first slug on their endpointpaths, so in this case we have one class calledGreetApi. If ourspec had two endpointsPOST /greet/one andGET /greet/two, thenthere would be one classGreetApi with two methods in it. If ourspec had two endpointsPOST /greet andPOST /farewell, then therewould be two classesGreetApi andFarewellApi with one method each.

Because of the configuration values we chose in our POM file:

  • GreetApi is an interface because<interfaceOnly>true</interfaceOnly>
  • greet returns aGreeting (as opposed to aResponse) because<returnResponse>false</returnResponse>
  • greet returns aGreeting (as opposed to aCompletionStage<Greeting>) because<supportAsync>false</supportAsync>

Template Customization

Now that we understand the generator's default behavior, let's makesome customizations. For the purposes of this example, we will addJAX-RSAsyncResponse code generation to the generator.

The Customization Requirements

Out of the box, the OpenAPI Generator supports code generation forasynchronous processing using the JAX-RS 2.1CompletionStageparadigm. However, some web frameworks -- e.g.,Dropwizard -- only support the earlierAsyncResponse paradigm. Let's add@Suspended AsyncResponseasynchronous processing code generation to the generator.

In our example spec, the generator can already generate methoddefinitions usingCompletionStage using<supportAsync>true</supportAsync>:

@POST@Consumes({ "application/json" })@Produces({ "application/json" })CompletionStage<Greeting> greet(@Valid Name name);

We want to be able to generate method definitions like this:

@POST@Consumes({ "application/json" })@Produces({ "application/json" })void greet(@Valid Name name, @Suspended AsyncResponse response);

OpenAPI Spec Extensions

TheOpenAPI Spec explicitlyprovides theextensionsmechanism to allow users to extend the spec for their ownneeds. Essentially, users can add specially-named attributes anywherein their specs, and they will be treated as "vendor extensions."

For this example, we will add a new method-level vendor extension,x-async-enabled, to indicate which methods should use asyncprocessing.

This will allow us to be use compatible asynchronous processing withmore web frameworks, and to declare on a per-method basis exactlywhich methods should and should not use asynchronous processing.

The Template Customizations

The OpenAPI Generator provides rich customization hooks. The easiestto use aretemplateoverrides.

Each generator is implemented usingmustachetemplates,specificallyjmustache. Typically,generators implement multiple templates that call each other. Thegenerator allows users toBYOT ("bring yourown templates") to override default templates.

In our POM, we told the generator we were going to BYOT:

<!-- We are showing off template customization today. The custom templates are stored here. --><templateDirectory>${project.basedir}/openapi/templates</templateDirectory>

Here are the templates we brought:

$ ls openapi/templatesapi.mustacheapiInterface.mustacheapiMethod.mustacheasyncParams.mustachereturnAsyncTypeInterface.mustachereturnTypeInterface.mustache

Notice that these templates overlap withthe existing JavaJaxRS/spectemplates. Whenthe generator generates code, it will find our templates instead ofthe default templates, and use them instead. So in essence, eachtemplate is a customization hook that we can plug into to generatewhatever code we need.

Understanding the Template Customization

The defaultJavaJaxRS/specapiInterface.mustache template looks like this:

@{{httpMethod}}{{#subresourceOperation}}@Path("{{{path}}}"){{/subresourceOperation}}{{#hasConsumes}}@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}{{#useSwaggerAnnotations}}@ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}"{{#hasAuthMethods}}, authorizations = {    {{#authMethods}}{{#isOAuth}}@Authorization(value = "{{name}}", scopes = {        {{#scopes}}@AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{^-last}},        {{/-last}}{{/scopes}} }){{^-last}},{{/-last}}{{/isOAuth}}    {{^isOAuth}}@Authorization(value = "{{name}}"){{^-last}},{{/-last}}    {{/isOAuth}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{^-last}}, {{/-last}}{{/vendorExtensions.x-tags}} }){{#implicitHeadersParams.0}}@io.swagger.annotations.ApiImplicitParams({    {{#implicitHeadersParams}}    @io.swagger.annotations.ApiImplicitParam(name = "{{{baseName}}}", value = "{{{description}}}", {{#required}}required = true,{{/required}} dataType = "{{{dataType}}}", paramType = "header"){{^-last}},{{/-last}}    {{/implicitHeadersParams}}}){{/implicitHeadersParams.0}}@ApiResponses(value = { {{#responses}}    @ApiResponse(code = {{{code}}}, message = "{{{message}}}", response = {{{baseType}}}.class{{#returnContainer}}, responseContainer = "{{{.}}}"{{/returnContainer}}){{^-last}},{{/-last}}{{/responses}} }){{/useSwaggerAnnotations}}{{#supportAsync}}{{>returnAsyncTypeInterface}}{{/supportAsync}}{{^supportAsync}}{{#returnResponse}}Response{{/returnResponse}}{{^returnResponse}}{{>returnTypeInterface}}{{/returnResponse}}{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}});

Our customized template looks like this:

@{{httpMethod}}{{#subresourceOperation}}@Path("{{{path}}}"){{/subresourceOperation}}{{#hasConsumes}}@Consumes({ {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }){{/hasConsumes}}{{#hasProduces}}@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }){{/hasProduces}}{{#useSwaggerAnnotations}}@ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}"{{#hasAuthMethods}}, authorizations = {    {{#authMethods}}{{#isOAuth}}@Authorization(value = "{{name}}", scopes = {        {{#scopes}}@AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{^-last}},        {{/-last}}{{/scopes}} }){{^-last}},{{/-last}}{{/isOAuth}}    {{^isOAuth}}@Authorization(value = "{{name}}"){{^-last}},{{/-last}}    {{/isOAuth}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{^-last}}, {{/-last}}{{/vendorExtensions.x-tags}} }){{#implicitHeadersParams.0}}@io.swagger.annotations.ApiImplicitParams({    {{#implicitHeadersParams}}    @io.swagger.annotations.ApiImplicitParam(name = "{{{baseName}}}", value = "{{{description}}}", {{#required}}required = true,{{/required}} dataType = "{{{dataType}}}", paramType = "header"){{^-last}},{{/-last}}    {{/implicitHeadersParams}}}){{/implicitHeadersParams.0}}@ApiResponses(value = { {{#responses}}    @ApiResponse(code = {{{code}}}, message = "{{{message}}}", response = {{{baseType}}}.class{{#returnContainer}}, responseContainer = "{{{.}}}"{{/returnContainer}}){{^-last}},{{/-last}}{{/responses}} }){{/useSwaggerAnnotations}}{{#supportAsync}}{{>returnAsyncTypeInterface}}{{/supportAsync}}{{^supportAsync}}{{#returnResponse}}Response{{/returnResponse}}{{^returnResponse}}{{>returnTypeInterface}}{{/returnResponse}}{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}{{#vendorExtensions.x-async-enabled}}{{#allParams.0}},{{/allParams.0}}{{>asyncParams}}{{/vendorExtensions.x-async-enabled}});

These templates are pretty dense! Let's look at the differences between the two:

$ diff original.mustache customization.mustache20c20<     {{#supportAsync}}{{>returnAsyncTypeInterface}}{{/supportAsync}}{{^supportAsync}}{{#returnResponse}}Response{{/returnResponse}}{{^returnResponse}}{{>returnTypeInterface}}{{/returnResponse}}{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}});--->     {{#supportAsync}}{{>returnAsyncTypeInterface}}{{/supportAsync}}{{^supportAsync}}{{#returnResponse}}Response{{/returnResponse}}{{^returnResponse}}{{>returnTypeInterface}}{{/returnResponse}}{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}{{#vendorExtensions.x-async-enabled}}{{#allParams.0}},{{/allParams.0}}{{>asyncParams}}{{/vendorExtensions.x-async-enabled}});

There's only one line of difference! Essentially, we just added logicto generate special async parameters using a new template if thevendor extension is present and truthy.

So even though these templates are pretty complex, the good news isthat they're also pretty well-factored and easy to work on once youunderstand the task you're trying to accomplish.

Of course, this isn't the only change. Readers are encouraged to lookat the other changes, too. But they're all pretty simple, like thisone.

Confirming Code Generation

If we update our spec to usex-async-enabled: true on a method, wedo indeed get our updated code generation:

@POST@Consumes({ "application/json" })@Produces({ "application/json" })void greet(@Valid Name name,@Suspended final AsyncResponse asyncResponse);

Success!

Summary

That's it! Once you have a working code generation configuration, youtypically only need to override a couple of template updates to effectany code generation change you want. Good luck, and happy customizing!

This configuration should work and generate useful code for generatingAsyncResponse methods using the OpenAPI Generator for anyone whoneeds it.

References

This Stack Overflowanswer was the startingpoint for this example. Thank you,philonous!

The JAX-RS 2.1 spec is availableherefor anyone who is curious to read it. TheAsyncResponse asynchronousprocessing paradigm is covered in section 8.2.1. TheCompletionStage asynchronousprocessing paradigm is covered in section 8.2.2.

About

An example Maven project that uses the OpenAPI Generator Maven plugin with template customization to generate an API model and server

Topics

Resources

License

Stars

Watchers

Forks


[8]ページ先頭

©2009-2025 Movatter.jp