swagger codegen is overwriting my custom code in generated files

11,463

Solution 1

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

Please pull the latest master of Swagger Codegen to give it a try.

UPDATE: On May 2018, about 50 top contributors and template creators of Swagger Codegen decided to fork Swagger Codegen to maintain a community-driven version called OpenAPI Generator. Please refer to the Q&A for more information.

Solution 2


Hello,
maybe after four years the answer comes a little bit late, but better late instead of never.

If you have a right swagger file (not only a fragment) like the following

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

and you run a code generation, in this explanation for a jaxs-jersey-server without any code generaction specific configuration values (which you can download from the Swagger editor), you get a bulk of java clases like the following:

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

In the REST endpoint implementation 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();
    }
    // ...
}

Do you now exchange the magic comment

        // do some magic!

through maybe the following

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

you should see a log message if you call the endpoint from your browser after you have done a mvn clean package jetty:run. But that's not a good idea, as you realized, because after the next generation, your change is gone.

In this context, it is never a good idea to change generated code manually, because this MUST be then so well documented that a future colleague (that could after a few months or years even be you) even in halfsleep on Sundays of Monday night makes the changes again after the next code generation. But my more than 20 years of experience with different code generators says only one thing about this: Forget it! For the same reason, it is not really goal-oriented to prevent further generation after the first generation, because this too has to be documented extensively. Otherwise debugging hour over debugging hour could come up with troubleshooting why the new feature does not work.

But that is all not necessary.
In the generated class io.swagger.api.ExampleApi you would find a constructor like the following (Ok, that is the state of 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);
            }
         } 
      }
      // ...
    }
// ...
}

The importand piece of code is the servletContext.getInitParameter("..."). If you now specify in the servlet configuration a key with the the name ExampleApi.implementation with an full qualified java classname which is derived from ExampleApiService you have implemented your own endpoint code which is secure for overwriting throught future code generations.

For finishing the example, this specification would made in the (additional generated, oouuch, sorry, you can not have everything) web.xml file. 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 fragment you have to insert after the periods (which stand for other servlet configuration settings) the following:

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

Good look,
whatever you currently are!

Solution 3

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

Here is the sample self explainatory auto-generated code for .swagger-codegen-ignore file

# 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 some lines below this to ignore e.g. I want to ignore all file in folder impl so I added the following line to do that

**/impl/*
Share:
11,463

Related videos on Youtube

Nikhil S
Author by

Nikhil S

Updated on September 15, 2022

Comments

  • Nikhil S
    Nikhil S over 1 year

    I used the swagger codegen to generate jaxrs server side classes and also client side java classes.

    This is the command I used to generate the 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 had a place holder 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" in the "echo" method and regenerated the code, only to see it wiped out. One way to avoid losing custom code is to modify the codegen template to generate interface instead of a class. Then I can have all the custom code in the implemented class.

    I am trying to find out if there is a way I can preserve the custom "magic" even after regenerating the code or if there is a better way of handling this situation than changing the template to generate interfaces instead of classes.

  • Matt Kim
    Matt Kim almost 7 years
    What's your workflow of merging new endpoint boilerplate code after adding the files to .swagger-codegen-ignore?
  • Evgeni Sergeev
    Evgeni Sergeev about 6 years
    It really should generate a class with methods, instead of just functions. Then we could cleanly subclass it.
  • saravanakumar
    saravanakumar over 4 years
    could you please give some input on my question stackoverflow.com/q/58521289/1700711
  • Almer
    Almer almost 4 years
    This actually also works with the maven openapi codegen plugin! The .openapi-generator-ignore will be generated in the target/generated-sources dir and can/should not be updated, so this is the best solution for mvn users.