JavaEE and Swagger: TomEE example

More and more applications are composed of REST services. In JavaEE land it means you develop and expose JAX-RS services.

Once developped and well tested with TomEE the first thing you will realize is that to make an API useful you need to document it. There are a lot of ways to do it but Swagger seems to be the trendy one and it is indeed a nice solution as we’ll see in this post.

For the purpose of this article we’ll start from this simple service:

public class UserResource {
    public UserPage getUsers(@QueryParam("number")
                             final int number,

                             final int offset) {

        // ...

    public UserModel get(@PathParam("id") final long userId) {
        // ...

This is a fully JavaEE (7 in this case) service returning user(s). To “expose” it with swagger we need to decorate it with @Api and we can document a bit more each method and parameters with a set of dedicated annotations like @ApiOperatoin or @ApiParam::

@Api("user") // swagger tag
public class UserResource {
    @ApiOperation(value = "Find users.") //swagger method description/comment
    public UserPage getUsers(@QueryParam("number")
                             @ApiParam(value = "page size", defaultValue = "20") // swagger param doc
                             final int number,

                             @ApiParam(value = "item offset", defaultValue = "0")
                             final int offset) {
        // ...

    @ApiOperation(value = "Find a user by id.")
    public UserModel get(@PathParam("id") @ApiParam(value = "user id", required = true) final long userId) {
        // ...

Sure it adds several annotations but then swagger will be able to generate either at build time with jaxrs-analyzer or at runtime like we’ll see the corresponding model.

Tip: of course you can also just write your model in YAML or JSON manually before having developped the service and just expose it with the same technique we’ll see now.

Once the model is computed swagger is able to expose it as JSON or YAML. Until here it is cool for machine to machine API validation but not very useful for API documentation which is intended for users first.

For that purpose you need to use another part of swagger which is swagger-ui which just reads the previous model and creates a GUI from it.

Let’s see how to set it up in a EE server – TomEE for us.


You only need swagger-jaxrs and swagger-ui to set it up:

    <!-- API are useless since in javaee-api -->
    <!-- not useful for the GUI -> only json for us -->
    <!-- we don't use reflections so no need of javassist -->
    <!-- we'll reuse the container one or add an impl as well to your app -->

Swagger-ui is a webjars containing the UI and you can of course use any other frontend solution to get the javascript/css but webjars are a fast solution which fits very well a blog post :).

Swagger-jaxrs is the module bringing the stack needed to introspect the swagger annotations and create the model the UI needs. As you can see you can exclude a bunch of transitive dependencies we’ll not use and which can conflict with your application or container – or even just leak.

API metadata

We already saw you can add metadata (annotations) on your services but you can also add a title, version, … to your API and you need to add a base path (JAX-RS mapping) to let swagger be able to create correct URLs for your endpoints (keep in mind if you are exposed behind a proxy swagger can sometimes not guess the external endpoint).

To do so the easiest solution is to add the swagger servlet in your web.xml and set it up as init parameters:

<web-app version="3.1"          xmlns=""          xmlns:xsi=""          xsi:schemaLocation="  ">

      <param-value>My Awesome API</param-value>



  • swagger basepath can be a full URL or partial one.
  • here we used maven version for the API version and added the web.xml to be filtered thanks to the maven war plugin configuration. In practise the API version rarely follows the project version but it was mainly to remind you the build tool can still be central and used even if the configuration is in web.xml file.

Note: no need of any servlet mapping, servlet API is just used to initialized swagger internals – there are alternatives but they need code compared to this one.

JAX-RS integration

Once swagger-jaxrs is added to your project you can use the provided swagger ApiListingResource JAX-RS resource to expose the swagger model at /swagger URL. If your container and JAXRS application is configured to use scanning nothing needed to get it otherwise keep in mind to add it to the resources you expose.

Now adding swagger dependencies also adds jackson and its jaxrs providers. This means you can get conflicts if it is not the one you want. To avoid that – and for TomEE case – we’ll add a WEB-INF/openejb-jar.xml specifying we want to use Apache Johnzon as JAX-RS JSON provider:

<?xml version="1.0" encoding="UTF-8"?>
  <pojo-deployment class-name="jaxrs-application">
      # swagger brings back jackson*, maybe not what you want in your app so let's take the control over providers
      cxf.jaxrs.skip-provider-scanning = true

      # let's keep the default TomEE JSON provider (johnzon)
      cxf.jaxrs.providers = org.apache.johnzon.jaxrs.JohnzonProvider

Of course we could use jackson but if your application already uses johnzon specific features this allows to keep it and it doesn’t break swagger :).

Note: using JAX-RS integration supposes you use an Application subclass. if not you need to set up swagger to scan for resources or use CXF (Swagger2Feature) / Jersey / Spring integration.

Set it up the Swagger GUI

Finally to setup the swagger GUI we just need to add an index.jsp (or any other location if swagger will not be your home page) containing:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
    <title>Java WordPress API</title>
    	<link href='webjars/swagger-ui/2.1.8-M1/css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
    	<link href='webjars/swagger-ui/2.1.8-M1/css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
    	<link href='webjars/swagger-ui/2.1.8-M1/css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
    	<link href='webjars/swagger-ui/2.1.8-M1/css/reset.css' media='print' rel='stylesheet' type='text/css'/>
    	<link href='webjars/swagger-ui/2.1.8-M1/css/screen.css' media='print' rel='stylesheet' type='text/css'/>
    <script src="webjars/swagger-ui/2.1.8-M1/lib/shred.bundle.js" type="text/javascript"></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/jquery-1.8.0.min.js' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/jquery.slideto.min.js' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/jquery.wiggle.min.js' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/handlebars-2.0.0.js' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/underscore-min.js' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/backbone-min.js' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/swagger-client.js' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/swagger-ui.min.js' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/highlight.7.3.pack.js' type='text/javascript'></script>
    <script src='webjars/swagger-ui/2.1.8-M1/lib/marked.js' type='text/javascript'></script>

<body class="swagger-section">
<div id="message-bar" class="swagger-ui-wrap">&nbsp;</div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
<script type="text/javascript">
    $(function () {
        new SwaggerUi({
            url: '<%= application.getContextPath() %>/api/swagger',
            dom_id: 'swagger-ui-container',
            swaggerRequstHeaders: 'application/json', // if you don't want to use it add .json to the url
            sorter: 'alpha'

All the work is done by SwaggerUi class provided by swagger-ui module. You see however we rely on JSP to set the context path dynamically which is a nice feature for web applications.

Side note: we suppose our JAX-RS application has an @ApplicationPath set to “api”.

Test Swagger UI

To test it I personally used tomee embedded maven plugin:

<plugin> <!-- mvn tomee-embedded:run to start testing against a real MySQL -->

And just run:

mvn tomee-embedded:run

Then you can go in http://localhost:8080/app/ and you should see something like:


Want more content ? Keep up-to-date on my new blog

Or stay in touch on twitter @rmannibucau

20 thoughts on “JavaEE and Swagger: TomEE example

  1. Juan Llado (@jllado)

    Hi Romain,

    It not works for me :S.

    Have you dealed with the following error when you added ApiListingResource to your Rest Application?

    java.lang.NullPointerException: null
    at io.swagger.jaxrs.config.SwaggerContextService.isScannerIdInitParamDefined( ~[swagger-jaxrs-1.5.7.jar:1.5.7]
    at io.swagger.jaxrs.listing.ApiListingResource.process( ~[swagger-jaxrs-1.5.7.jar:1.5.7]
    at io.swagger.jaxrs.listing.ApiListingResource.getListingYaml( ~[swagger-jaxrs-1.5.7.jar:1.5.7]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_72]
    at sun.reflect.NativeMethodAccessorImpl.invoke( ~[na:1.8.0_72]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke( ~[na:1.8.0_72]
    at java.lang.reflect.Method.invoke( ~[na:1.8.0_72]
    at ~[openejb-cxf-rs-7.0.0-M1.jar:7.0.0-M1]
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke( ~[cxf-core-3.1.3.jar:3.1.3]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke( ~[cxf-rt-frontend-jaxrs-3.1.3.jar:3.1.3]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke( ~[cxf-rt-frontend-jaxrs-3.1.3.jar:3.1.3]
    at ~[openejb-cxf-rs-7.0.0-M1.jar:7.0.0-M1]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor$ ~[cxf-core-3.1.3.jar:3.1.3]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage( ~[cxf-core-3.1.3.jar:3.1.3]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept( ~[cxf-core-3.1.3.jar:3.1.3]
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage( ~[cxf-core-3.1.3.jar:3.1.3]
    at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke( ~[cxf-rt-transports-http-3.1.3.jar:3.1.3]
    at ~[openejb-cxf-rs-7.0.0-M1.jar:7.0.0-M1]
    at org.apache.tomee.webservices.CXFJAXRSFilter.doFilter( ~[tomee-jaxrs-7.0.0-M1.jar:7.0.0-M1]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( ~[catalina.jar:8.0.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter( ~[catalina.jar:8.0.29]


  2. Juan Llado (@jllado)

    Mmmm, I’ve changed the version and now I’m gettign this error:
    16:37:50.395 [http-nio-7070-exec-2] ERROR o.a.c.i.AbstractFaultChainInitiatorObserver – Error occurred during error handling, give up!
    org.apache.cxf.interceptor.Fault: io/swagger/jaxrs/ext/AbstractSwaggerExtension
    at org.apache.cxf.service.invoker.AbstractInvoker.createFault( ~[cxf-core-3.1.5.jar:3.1.5]
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke( ~[cxf-core-3.1.5.jar:3.1.5]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke( ~[cxf-rt-frontend-jaxrs-3.1.5.jar:3.1.5]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke( ~[cxf-rt-frontend-jaxrs-3.1.5.jar:3.1.5]
    at ~[openejb-cxf-rs-7.0.0-M2.jar:7.0.0-M2]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor$ ~[cxf-core-3.1.5.jar:3.1.5]
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage( ~[cxf-core-3.1.5.jar:3.1.5]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept( ~[cxf-core-3.1.5.jar:3.1.5]
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage( [cxf-core-3.1.5.jar:3.1.5]
    at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke( [cxf-rt-transports-http-3.1.5.jar:3.1.5]
    at [openejb-cxf-rs-7.0.0-M2.jar:7.0.0-M2]
    at org.apache.tomee.webservices.CXFJAXRSFilter.doFilter( [tomee-jaxrs-7.0.0-M2.jar:7.0.0-M2]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( [catalina.jar:8.0.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter( [catalina.jar:8.0.32]
    at org.apache.openejb.server.httpd.WebBeansFilter.doFilter( [openejb-http-7.0.0-M2.jar:7.0.0-M2]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( [catalina.jar:8.0.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter( [catalina.jar:8.0.32]
    at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter( [rewrite-servlet-2.0.12.Final.jar:2.0.12.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( [catalina.jar:8.0.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter( [catalina.jar:8.0.32]
    at net.bull.javamelody.MonitoringFilter.doFilter( [javamelody-1.59.0.jar:na]
    at net.bull.javamelody.MonitoringFilter.doFilter( [javamelody-1.59.0.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( [catalina.jar:8.0.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter( [catalina.jar:8.0.32]
    at org.omnifaces.filter.CharacterEncodingFilter.doFilter( [omnifaces-2.2.jar:2.2]
    at org.omnifaces.filter.HttpFilter.doFilter( [omnifaces-2.2.jar:2.2]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( [catalina.jar:8.0.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter( [catalina.jar:8.0.32]
    at org.apache.catalina.core.StandardWrapperValve.invoke( [catalina.jar:8.0.32]
    at org.apache.catalina.core.StandardContextValve.invoke( [catalina.jar:8.0.32]
    at org.apache.tomee.catalina.OpenEJBValve.invoke( [tomee-catalina-7.0.0-M2.jar:7.0.0-M2]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke( [catalina.jar:8.0.32]
    at org.apache.catalina.core.StandardHostValve.invoke( [catalina.jar:8.0.32]
    at org.apache.catalina.valves.ErrorReportValve.invoke( [catalina.jar:8.0.32]
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke( [catalina.jar:8.0.32]
    at org.apache.catalina.core.StandardEngineValve.invoke( [catalina.jar:8.0.32]
    at org.apache.catalina.connector.CoyoteAdapter.service( [catalina.jar:8.0.32]
    at org.apache.coyote.http11.AbstractHttp11Processor.process( [tomcat-coyote.jar:8.0.32]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process( [tomcat-coyote.jar:8.0.32]
    at$SocketProcessor.doRun( [tomcat-coyote.jar:8.0.32]
    at$ [tomcat-coyote.jar:8.0.32]
    at java.util.concurrent.ThreadPoolExecutor.runWorker( [na:1.8.0_72]
    at java.util.concurrent.ThreadPoolExecutor$ [na:1.8.0_72]
    at org.apache.tomcat.util.threads.TaskThread$ [tomcat-util.jar:8.0.32]
    at [na:1.8.0_72]
    Caused by: java.lang.NoClassDefFoundError: io/swagger/jaxrs/ext/AbstractSwaggerExtension
    at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_72]
    at java.lang.ClassLoader.defineClass( ~[na:1.8.0_72]
    at ~[na:1.8.0_72]
    at ~[na:1.8.0_72]
    at$100( ~[na:1.8.0_72]
    at$ ~[na:1.8.0_72]
    at$ ~[na:1.8.0_72]
    at Method) ~[na:1.8.0_72]
    at ~[na:1.8.0_72]

    When I check my dependicies I see swagger-core-1.5.3.jar which is the container of that class…

    Any idea? :_(


      1. Juan Llado (@jllado)

        Sorry, I meant swagger-jaxrs :S. My dependency is like this:












  3. Juan Llado (@jllado)

    Hi Romain,

    I have another “issue” with swagger, tomee and cxf.

    I’m using my custom jackson ObjectMapper:

    public class RestServer extends Application {

    private Set singletons = new HashSet();

    public RestServer() {
    singletons.add(new JacksonJsonProvider(JsonParser.defaultJacksonObjectMapper()));
    singletons.add(new JAXRSBeanValidationInInterceptor());

    public Set getSingletons() {
    return singletons;

    public Set<Class> getClasses() {
    Set<Class> classes = new HashSet();
    return classes;


    But when I add swagger to the pom, then the app starts to use the default ObjectMapper.

    Any idea? I’ve seen in the logs the following:
    14:47:30.732 [http-nio-7070-exec-4] INFO – Using writers:
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.johnzon.jaxrs.WadlDocumentMessageBodyWriter@31783b71
    14:47:30.732 [http-nio-7070-exec-4] INFO – io.swagger.jaxrs.listing.SwaggerSerializers@5ee7720e
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.cxf.jaxrs.provider.StringTextProvider@1abfe559
    14:47:30.732 [http-nio-7070-exec-4] INFO – io.swagger.jaxrs.json.JacksonJsonProvider@2da7b325
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.johnzon.jaxrs.JsrProvider@4b445cc5
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.cxf.jaxrs.provider.PrimitiveTextProvider@7fe8bf7
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.cxf.jaxrs.provider.FormEncodingProvider@3e5df1a4
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.cxf.jaxrs.provider.MultipartProvider@5127b417
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.cxf.jaxrs.provider.SourceProvider@38ec6882
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.cxf.jaxrs.provider.JAXBElementProvider@4bbefd5b
    14:47:30.732 [http-nio-7070-exec-4] INFO – com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider@76546d15
    14:47:30.732 [http-nio-7070-exec-4] INFO – com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider@11cfc7ef
    14:47:30.732 [http-nio-7070-exec-4] INFO – com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider@184dc330
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.cxf.jaxrs.provider.BinaryDataProvider@74bf7da2
    14:47:30.732 [http-nio-7070-exec-4] INFO – org.apache.cxf.jaxrs.provider.DataSourceProvider@21569ae5

    So I see that the app has registered the swagger jackson provider:

    how can I avoid the swagger jackson provider?


  4. Guillaume Ch

    Good article !
    I’ve just tried to do it in a EAR-WAR-EJB-JPA project. Swagger is correctly registred but EJB jar is not scanned. When I call swagger API, there is no paths 😦

    My dependency graph:
    EAR contains (EJB, WAR)
    EJB contains (SWAGGER-JAXRS[provided], JPA)

  5. Raj

    Hi rmannibucau How can we restrict swagger in production environment alone? Do you have any suggetions?

  6. Raj

    While configuring swagger I am seeing an error in the bottom of the UI though it has no impact with functionality. While clicking on that error its showing {“schemaValidationMessages”:[{“level”:”error”,”message”:”Can’t read from file“}]}. I didn’t get this error for local environment. But its showing in QA. Any idea about this?


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s