Swagger codegen overwrites my custom code in generated files

I used swagger codegen to generate server side jaxrs classes as well as client side java classes.

This is the command I used to generate classes

java -jar modules/swagger-codegen-distribution/target/swagger-codegen-distribution-2.1.2-M1.jar -i /Users/me/Workspace/swagger-codegen/samples/yaml/echo.yaml -l jaxrs -o samples/server/echo/java 

The server code that was generated contained a placeholder to write my "magic".

 public Response echo(@ApiParam(value = "" )@HeaderParam("headerParam") String headerParam, @ApiParam(value = "",required=true) @QueryParam("message") String message) throws NotFoundException { // do some magic! return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build(); } 

I added the magic to the echo method and regenerated the code just to see how it was destroyed. One way to avoid losing custom code is to modify the codegen template to create an interface instead of a class. Then I can have all the user code in the implemented class.

I'm trying to figure out if there is a way to preserve user "magic" even after the code is regenerated, or is there a better way to deal with this situation than changing the template to generate interfaces instead of classes.

+10
source share
3 answers

The latest version of Swagger Codegen allows you to specify files that will not be overwritten in .swagger-codegen-ignore (similar to .gitignore) during code generation.

Please take the latest version of Swagger Codegen to try it.

UPDATE: In May 2018, about 50 leading contributors and template makers of Swagger Codegen decided to fork out for Swagger Codegen to support the community-driven version of OpenAPI Generator . Please refer to Q&A for more information.

+2
source

You can specify the files you want to ignore in .swagger-codegen-ignore

Here is an example of self explanatory code for .swagger-codegen-ignore

 # Swagger Codegen Ignore # Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen # Use this file to prevent files from being overwritten by the generator. # The patterns follow closely to .gitignore or .dockerignore. # As an example, the C# client generator defines ApiClient.cs. # You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: #ApiClient.cs # You can match any string of characters against a directory, file or extension with a single asterisk (*): #foo/*/qux # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux # You can recursively match patterns against a directory, file or extension with a double asterisk (**): #foo/**/qux # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux # You can also negate patterns with an exclamation (!). # For example, you can ignore all files in a docs folder with the file extension .md: #docs/*.md # Then explicitly reverse the ignore rule for a single file: #!docs/README.md 

You can add a few lines below this to ignore, for example, I want to ignore all the files in the impl folder , so I added the following line to do this

 **/impl/* 
0
source


Hello,
Maybe four years later the answer comes a little later, but better late than never.

If you have the correct swag file (not just a snippet) as shown below

 openapi: "3.0.0" : paths: /example: get: operationId: showIt : 

and you start code generation, in this explanation for jaxs-jersey-server without any specific configuration values ​​for code generation (which you can download from the Swagger editor ), you get most of the java sentences, such as:

 io.swagger.api. ExampleApi io.swagger.api. ExampleApiService io.swagger.api.factories.ExampleApiServicefactory io.swagger.api.impl. ExampleApiServiceImpl 

In the implementation of the REST endpoint ExampleApiServiceImpl, you see more or less something like the following:

 package io.swagger.api.impl; : import ... ; : @javax.annotation.Generated(...) public class ExampleApiServiceImpl extends ExampleApiService { // ... @Override public Response showIt( /* additional parameters , */ SecurityContext securityContext) throws NotFoundException { // do some magic! return Response.ok() .entity(new ApiResponseMessage( ApiResponseMessage.OK , "magic!" ) ) .build(); } // ... } 

You are now sharing a magical comment

  // do some magic! 

perhaps through

  String className = this.getClass().getSimpleName(); System.out.println("Entered REST endpoint: path=|" + className.substring(0, className.length() - 14) + "| operationId=|showId|"); 

you should see a message in the log if you call the endpoint from the browser after you mvn clean package jetty:run . But this is not a good idea, as you understand, because after the next generation your changes have disappeared.

In this context, you should never change the manually generated code, because it MUST be so well documented that the future colleague (who may even be you in a few months or years), even in the half-sleepy Sundays on Monday night, changes again after the next code generation. But my more than 20 years of experience working with various code generators says only one thing about it : forget about it! For the same reason, it is not practical to prevent further generation after the first generation, because this should also be documented in detail. Otherwise, the debugging hour compared to the debugging hour can lead to troubleshooting why the new feature does not work.

But all this is not necessary.
In the generated io.swagger.api.ExampleApi class , you will find a constructor similar to the following (ok, this is state 2019-05-17. I don't know if it was the same (or similar) four years ago)

 package io.swagger.api; : import ... ; : @Path("/example") @javax.annotation.Generated(...) public class ExampleApi { private final ExampleApiService delegate; public ExampleApi(@Context ServletConfig servletContext) { // ... if (servletContext != null) { String implClass = servletContext.getInitParameter("ExampleApi.implementation"); if (implClass != null && !"".equals(implClass.trim())) { try { delegate = (ExampleApiService) Class.forName(implClass).newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } } // ... } // ... } 

An important piece of code is servletContext.getInitParameter("...") . If you are now ExampleApi.implementation in the servlet configuration, a key named ExampleApi.implementation with the fully qualified name of the java class, which is obtained from ExampleApiService you have implemented your own endpoint code that is safe for rewriting in future generations of code.

To complete the example, this specification will be made in the web.xml (additionally generated, sorry, you cannot have everything). This file contains something like:

  <servlet> <servlet-name>jersey</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> ... <load-on-startup>1</load-on-startup> </servlet> 

In this XML snippet, you should insert the following after periods (which indicate other servlet configuration parameters):

  <init-param> <param-name>ExampleApi.implementation</param-name> <param-value>my.swagger.api.MyExample</param-value> </init-param> 

You look good
whoever you are now!

0
source

Source: https://habr.com/ru/post/1270871/


All Articles