swagger codegen is overwriting my custom code in generated files

后端 未结 3 1549
死守一世寂寞
死守一世寂寞 2021-02-05 20:31

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

ja         


        
3条回答
  •  生来不讨喜
    2021-02-05 21:11


    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:

        
            jersey
            org.glassfish.jersey.servlet.ServletContainer
            ...
            1
        
    

    In this xml fragment you have to insert after the periods (which stand for other servlet configuration settings) the following:

            
                ExampleApi.implementation
                my.swagger.api.MyExample
            
    

    Good look,
    whatever you currently are!

提交回复
热议问题