Adding Swagger to a JavaEE Project – JavaEE Series 2 Part 2
In this article, we’ll add Swagger to our JavaEE project.
If you aren’t already familiar with Swagger, it’s an OpenAPI implementation that allows us to document our APIs. We do this using annotations on our endpoints and our services. This information will end up in a generated JSON file that describes our API. Another component, Swagger-UI, will read this JSON file and render an interactive document to the end user.
We’ll cover the basics of all of this in this article.
Getting Started
The first thing we have to do, of course, is to add the necessary dependencies to our project. We will be adding an older version of Swagger as the new one, in my experience, isn’t as flexible or as easy to use.
In your pom.xml file, add the following dependency:
... <dependencies> ... <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-jaxrs</artifactId> <version>1.5.22</version> </dependency> ... </dependencies>
We’ll also need to add a few plugins as well to your pom.xml:
<build> <finalName>todo</finalName> <plugins> <plugin> <groupId>com.googlecode.maven-download-plugin</groupId> <artifactId>download-maven-plugin</artifactId> <version>1.2.1</version> <executions> <execution> <id>swagger-ui</id> <phase>prepare-package</phase> <goals> <goal>wget</goal> </goals> <configuration> <skipCache>false</skipCache> <url>https://github.com/swagger-api/swagger-ui/archive/master.tar.gz</url> <unpack>true</unpack> <outputDirectory>${project.build.directory}</outputDirectory> </configuration> </execution> </executions> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>copy-resources</id> <phase>prepare-package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>target/${build.finalName}/docs</outputDirectory> <resources> <resource> <directory>${project.build.directory}/swagger-ui-master/dist</directory> </resource> </resources> </configuration> </execution> </executions> </plugin> <plugin> <groupId>com.google.code.maven-replacer-plugin</groupId> <artifactId>replacer</artifactId> <executions> <execution> <id>replace-swagger-json-location</id> <phase>prepare-package</phase> <goals> <goal>replace</goal> </goals> </execution> </executions> <configuration> <file>${project.build.directory}/todo/docs/index.html</file> <replacements> <replacement> <token>https://petstore.swagger.io/v2/swagger.json</token> <value>/todo/api/swagger.json</value> </replacement> </replacements> </configuration> </plugin> </plugins>
I know that’s a lot of stuff we’re adding, but we do need all of it. The first plug-in block downloads the latest swagger-ui release from https://github.com/swagger-api/swagger-ui/ and unpacks it to our target/ folder.
The second plug-in will copy that folder into our war file’s “docs/” folder. Meaning, when we deploy our application to Wildfly, we’ll be able to access Swagger-UI by accessing http://localhost:8080/todo/docs.
The third, and final, plug-in will do a token substitution in Swagger-UI’s index.html file so that it points to our own swagger.json which will be hosted at http://localhost:8080/todo/api/swagger.json.
Hosting swagger.json
The next step we have to do is add some code to our MyApplication.java file to enable Swagger and set some stuff up. Go ahead and open up your MyApplication.java file and add the following constructor to it:
public MyApplication(@Context ServletConfig servletConfig) { super(); BeanConfig beanConfig = new BeanConfig(); beanConfig.setVersion("1.0.0"); beanConfig.setTitle("Todo API"); beanConfig.setBasePath("/todo/api"); beanConfig.setResourcePackage("com.synaptik.javaee"); beanConfig.setScan(true); }
BeanConfig is a Swagger class that holds its configuration. Once we’ve set these values, Swagger will be enabled and auto-generate a “swagger.json” at the basePath we have configured above. As I mentioned before, swagger.json will be read by Swagger-UI to generate the interactive documentation. We want to set the resourcePackage to the root Java package of our project so it knows what to pick up.
Finally, we have to change the @ApplicationPath annotation to:
@ApplicationPath("/api")
The reason we need to do this is so JAX-RS doesn’t get in the way of sending back the docs/ folder. If we didn’t do this, then when we make the request to http://localhost:8080/todo/docs, our application would think docs/ was an API endpoint and try to handle it. And since it isn’t an API endpoint, the call would fail.
This also means that we will need to go back to the UI project and change its code to point to this new path if we want to continue to use it.
Adding Annotations
Now, we can add annotations to our project. We’ll start by opening our TodoService.java file and adding annotations to our class and our methods. Open up TodoService.java and add the following before the class definition:
@Path("/") @Api(tags={"todo"}) public class TodoService { ...
The @Api annotation enables Swagger for this class. If you don’t want an API to be listed in the documentation, then you can just leave that annotation off and it won’t be picked up by Swagger’s scanner.
Next, we have to go to each of our methods and add some annotations to them:
... @GET @Produces(MediaType.APPLICATION_JSON) @ApiOperation(value = "Fetch all to dos") @ApiResponses({ @ApiResponse(code=200, message="Success") }) public List<Todo> getAll() { return ejb.findAll(); } @PUT @Path("{id}") @Consumes(MediaType.APPLICATION_JSON) @ApiOperation(value = "Updates existing to do") @ApiResponses({ @ApiResponse(code=200, message="Updated"), @ApiResponse(code=404, message="Not found") }) public void update( @ApiParam(required=true) @PathParam("id") Long id, @ApiParam(required=true) Todo incoming) { ejb.update(id, incoming); } @POST @Consumes(MediaType.APPLICATION_JSON) @ApiOperation(value = "Create a new to do") @ApiResponses({ @ApiResponse(code=200, message="Created") }) public void create(@ApiParam(required=true) Todo incoming) { ejb.create(incoming); } @DELETE @Path("{id}") @ApiOperation(value = "Remove existing to do") @ApiResponses({ @ApiResponse(code=200, message="Removed") }) public void remove(@ApiParam(required=true) @PathParam("id") Long id) { ejb.remove(id); }
You’ll notice here several new annotations, all prefixed with “@Api”. The @ApiOperation is pretty straight forward in that it just simply describes what the endpoint is going to do. The @ApiResponses annotation describes the list of expected responses and their meaning. Generally, I don’t document 5xx internal server errors as those are implied and can happen at any time for any reason. But if you want to be explicit about it, you can add it. Finally, for every parameter you pass in to a method, you will need to add an @ApiParam annotation.
There are several other fields for each of these that allow you to further tailor the verbage within the generated documentation, but this is fine for now.
With this out of the way, we’re ready to build and deploy!
Building and Deploying
The last thing we need to do is build it up, deploy it, and try it out! Go ahead and type the following into your command prompt (and use the correct WildFly folder):
mvn clean package && copy /y target\todo.war \devtools\wildfly-15.0.1.Final\standalone\deployments
Once you’ve done that and it’s deployed, you can open http://localhost:8080/todo/docs/. You should see something similar to this:

Swagger UI
You can click on each of the endpoints to see more information about them and even interact with each API as well.
You might also notice that the POST API shows an example where you pass the “id” field in on the body of the request. This doesn’t really reflect what is expected. If you’re curious about how to fix this, I’d encourage you to watch my video above otherwise feel free to do this on your own.
If you run into any problems or have any comments, please leave them in the comment section below.
Source code to the entire series is available here:
what is MyApplication.java and where is it?
This is the JavaEE “configuration” file. The only annotation you need to put into it is the @ApplicationPath which tells the container where clients will access your APIs.
You can view the source for the application on GitHub: https://github.com/synaptik-labs/javaee-series/tree/master/src/main/java/com/synaptik/javaee
Hello, I am trying to implement swagger in my app as you have explained but doing mvn clean package && copy / and target \ todo.war \ devtools \ wildfly-15.0.1.Final \ standalone \ deployments returns the following error.
MyApplication.java:[8,31] package io.swagger.jaxrs.config does not exist
Thanx Bro!
I’d make sure you defined your maven dependencies accurately in your pom file. It sounds like Swagger isn’t being deployed within your jar file.
good day,
In the MyApplication class constructor we wiring ‘servletConfig’ but we not using it anywhere and in the same method ‘beanConfig’ is created but not assigned to anything, is something missing there?
I get the following error:
[ERROR] Error resolving version for plugin ‘com.google.code.maven-replacer-plugin:replacer’ from the repositories [local (/Users/richardmarais/.m2/repository), central (https://repo.maven.apache.org/maven2)]: Plugin not found in any plugin repository -> [Help 1]
Fixed with this: https://stackoverflow.com/questions/40002459/error-resolving-version-for-plugin-org-apache-maven-pluginsmaven-jar-plugin-f/46926317
Hello
I follow step by step you tutorial but when I launch my application the file /myApp/api/swagger.json is not created.
If I put it manually everithing is working.
I use a Tomcat server in Java 11, can it change something ?
Thank you for your help and your tutorial !
Sorry, I find what was wrong.
If someone has this error it was due to the version of jackson-databind which doesn’t contain com.fasterxml.jackson.databind.ObjectMapper.addMixIn (be back on version 2.9.8)
Very good tutorial !
Hello,
I am using a web.xml file.
which configurations should be made for swagger to work?
Or is it mandatory to have the class annotated with @ApplicationPath(“/api”)