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