swagger codegen is overwriting my custom code in generated files

扶醉桌前 提交于 2019-12-31 22:01:06

问题


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.


回答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.




回答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!




回答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/*


来源:https://stackoverflow.com/questions/29252817/swagger-codegen-is-overwriting-my-custom-code-in-generated-files

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!