3

UPDATED with SOLUTION below!!!
//////////////////////////////////////////////////////////////
Thanks to the advice of Ron below I slightly modified my setup to use BeanConfig instead of SwaggerConfig and got this working. In order to do this I had to modify the servlet and also (and this is where I believe the missing piece was) add the BeanConfig entry into the spring application context file so that spring picks up the resources. I included the updates below with comments in my code showing the old and new/updated code. It's possible I could've continued with the SwaggerConfig (maybe I was just missing something in the spring application context file for that as well?) but the BeanConfig works so I'm going to leave it as is.
//////////////////////////////////////////////////////////////

I'm trying to get Swagger running with my local REST-based Java App and have made quite a bit of progress. However, I seem to be missing something easy when I'm trying to get the Swagger UI working.

Whenever I actually hit this address: http://localhost:9082/mbl/index.html I'm getting the little green swagger header at the top but a blank white body with no content underneath. Shouldn't I be seeing more than this in the body of the page?

My stack is this: Java 6 / Wink / Spring 3.1 / Jackson 2.5 / JAX-RS (JSR-311) and I'm using the following Swagger jars: swagger-annotations-1.3.10.jar / swagger-core_2.10-1.3.10.jar / swagger-jaxrs_2.10-1.3.10.jar.

Now I've managed to get some json displaying that looks like this when i hit http://localhost:9082/mbl/services/api-docs:

{"apiVersion":"1.0","swaggerVersion":"1.2","info":{"title":"Java API","description":"The following documentation contains the REST Service API useful for interacting with web services.","termsOfServiceUrl":"terms of service","contact":"email@test.com","license":"license type","licenseUrl":"license url"}}

I can see that this is being generated from my SwaggerServlet.java which looks like this:

package com.somewhere.mblsvc.web;

import...

public class SwaggerServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    /* additional working code */
    BeanConfig beanConfig;

    public void setBeanConfig(BeanConfig beanConfig) {
        this.beanConfig = beanConfig;
    }
    /* end additional working code */    

    @Override
    public void init(ServletConfig servletConfig) {
        try {
        /* code from original post*/
        //  SwaggerConfig swaggerConfig = new SwaggerConfig();
        //  ConfigFactory.setConfig(swaggerConfig);
        //  swaggerConfig.setBasePath("/mbl/services");
        //  swaggerConfig.setApiVersion("1.0");
        //  swaggerConfig.setApiInfo(new ApiInfo("Java API", "The following //documentation contains the REST Service API useful for interacting with web //services.", "terms of service", "email@test.com", "license type", "license //url"));
        //  ScannerFactory.setScanner(new DefaultJaxrsScanner());
        //  ClassReaders.setReader(new DefaultJaxrsApiReader());
        /* end code from original post*/

        /* updated working code */
        beanConfig.setBasePath("/mbl/x-services");
        beanConfig.setVersion("1.0");
        beanConfig.setResourcePackage("com.somewhere.mblsvc.resources");
        beanConfig.setScan(true);
        /* end updated working code */

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Also, I have the following in my spring application context xml file:

<bean class="org.apache.wink.spring.Registrar">
    <property name="classes">
        <set value-type="java.lang.Class">
        </set>
    </property>
    <property name="instances">
        <set>
            <ref local="jaxbProvider" />
            <ref local="apiDeclarationProvider" />
            <ref local="apiListingResourceJson" />
            <ref local="resourceListingProvider" />
        </set>
    </property>

<!-- Jackson Providers -->
<bean id="jaxbProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider" >
    <property name="mapper" ref="jacksonObjectMapper"/>
</bean>

<bean id="jacksonObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" >
    <property name="annotationIntrospector" ref="jacksonAnnotationIntrospector" />
</bean>

<bean id="jacksonAnnotationIntrospector" class="com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair" >
    <constructor-arg ref="primaryAnnotationIntrospector" />
    <constructor-arg ref="secondaryAnnotationIntrospector" />
</bean>

<bean id="primaryAnnotationIntrospector" class="com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector" />
<bean id="secondaryAnnotationIntrospector" class="com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector" />

<!-- Swagger Configuration and Providers -->

<!-- additional working code -->
<bean id="beanConfig" class="com.wordnik.swagger.jaxrs.config.BeanConfig">
    <property name="title" value="Java API"/>
    <property name="version" value="1.0" />
    <property name="basePath" value="/mbl/services"/>
    <property name="resourcePackage" value="com.somewhere.mblsvc.resources"/>
    <property name="scan" value="true"/>
</bean>
<!-- end additional working code -->

<bean id="apiDeclarationProvider" class="com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider" />
<bean id="apiListingResourceJson" class="com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON" />
<bean id="resourceListingProvider" class="com.wordnik.swagger.jaxrs.listing.ResourceListingProvider" />

My web.xml looks like this:

<!-- REST servlet that dispatches to the App (resource class). Remove Init params entry containing application file -->
<servlet>
    <servlet-name>Wink Servlet</servlet-name>
    <servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Wink Servlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
</servlet-mapping>

<!-- Enabling Swagger servlet -->
<servlet>
    <servlet-name>Swagger Servlet</servlet-name>
    <servlet-class>com.somewhere.mblsvc.web.SwaggerServlet</servlet-class>
    <load-on-startup>-1</load-on-startup> 
</servlet>
<servlet-mapping>
    <servlet-name>Swagger Servlet</servlet-name>
    <url-pattern>/api-docs</url-pattern>
</servlet-mapping>

Here's a snippet of my Resource class:

@Path("test")
@Api(value ="test", description="Test Services")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class TestResource {

.
.
.

    @GET
    @Path("testInfo")
    @ApiParam(defaultValue="you would put test case input here for a post")  
    @ApiOperation(value="Composite service returning extensive test information", response=com.somewhere.mblsvc.messages.test.testinfo.pojo.UserResponseMessage.class)
    @ApiResponses(value={
            @ApiResponse(code=200, message="OK"),
            @ApiResponse(code=500, message="Internal Error")
    })
    @JsonSerialize(include=JsonSerialize.Inclusion.ALWAYS)
    public Response getTestInfo(@Context HttpHeaders headers, 
            @CookieParam(value = "testBrand") String testBrand) {
.
.
.

And, finally, the only important part of my index.html (that I can tell) looks like this:

  <script type="text/javascript">
    $(function () {
      var url = window.location.search.match(/url=([^&]+)/);
      if (url && url.length > 1) {
        url = url[1];
      } else {
        url = "http://" + window.location.hostname + (window.location.port ? ':'+ window.location.port: '') + "/mbl/services/api-docs";
      }
      .
      .
      .

I will gladly supply any more information as needed. Does anyone have any idea what I might be missing?

Thanks a lot!

risingTide
  • 1,754
  • 7
  • 31
  • 60

1 Answers1

2

The core problem is that your resources are not really scanned. You do get the right now is the basic Swagger response, but if you look at the content, it has no API definitions in it.

As a result, swagger-ui is unable to show anything, because there's nothing to show.

While I'm curious as to how you got to the configuration above, the truth is that the integration can be simpler. We don't have specific documentation for Wink (we should), but the idea is very similar to any of the JAX-RS integrations.

I'd recommend the following steps:

  1. Migrate to swagger-core 1.5. It's obvious this is a new integration and there's no reason not to use it.
  2. Check out the wink sample - should be really easy to follow.
  3. Read the guides for 1.5 - they are not for wink, but they are all similar and you can infer to wink.
  4. Check the migration guide as it also contains details that may help you out.

I realize this doesn't solve the question at-hand exactly, but I'd rather promote the right overall solution in this case.

Ron
  • 14,160
  • 3
  • 52
  • 39
  • Thanks for the response Ron. Unfortunately I don't have the option to move to 1.5...my organization hasn't approved that version yet and the politics of that are out my control. So for now I need to implement with 1.3. I edited my question above with some of the annotations I have on a resource class a well to try to complete my example. Could you help with the issue at hand? As to how I got to this point...I basically searched the net for examples using my technology stack and wound up here. I think I'm close... – risingTide May 20 '15 at 14:36
  • 1
    That's fine, you can still use 1.3, there's a sample for it and guidelines just as well. I'd recommend going over the BeanConfig path rather than SwaggerConfig. Follow those and it should be fine. – Ron May 20 '15 at 15:50
  • Hmm...your "wink sample" link above gives me a 404. :/ – risingTide May 20 '15 at 19:19
  • 1
    Sorry, we just moved the samples yesterday (first time ever). For 1.3, you can find the sample here - https://github.com/swagger-api/swagger-core/tree/v1.3.12/samples/java-jaxrs-wink – Ron May 20 '15 at 19:33
  • Ha. Impeccable timing. Thanks. – risingTide May 20 '15 at 19:38
  • Forgot to mention I updated the link in the answer :) – Ron May 20 '15 at 19:51
  • Got pulled away from this for a month, but I got it working with your advice of switching to `BeanConfig` yesterday. The missing piece, so it seems, was the lack of the bean existing in the spring application configuration context file. This was the kicker that led me to the right solution is here: https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-RESTEasy-2.X-Project-Setup#using-springs-bean-declaration. For the updated code take a look at the original post above; I commented accordingly. I wanted to keep this answer as the accepted one though; thanks again Ron. – risingTide Jun 16 '15 at 17:31