swagger and cxf... some problems at the invocation of web services and using swagger ui

960 views
Skip to first unread message

dott...@gmail.com

unread,
Jun 5, 2013, 2:17:17 AM6/5/13
to swagger-sw...@googlegroups.com
Hi all,
I'm trying to publish a cxf rest endPoint adding annotations required to use swagger.
I'm trying to follow the guidelines at
https://github.com/wordnik/swagger-core/tree/master/samples/java-jaxrs-cxf/src/main/java/com/wordnik/swagger/sample
with some differences: I must publish the endPoint directly from java code.
My situation is the following...

I have an endPoint with a simple interface like this:

    @WebService(targetNamespace = http://com.prova.pubdocs/)
    public interface IPublic extends IPublishable{
              
        @GET
        @Path("/isReady")
        @ApiOperation(value = "Check the instance is ready or not", notes = "Returns a boolean corresponding to the instance state.", responseClass = "boolean")
        boolean isReady();

    }
(the interface IPublishable specifies only the methods to publish and unpublish the endPoints),

and an implementor like this:
    @WebService("
RestServicePubDocs", "PubDocs")
    public class RestPublicDocs implements IPublic, IPlat1Service {
  
    @Override
        public boolean isReady() {
                return true;
        }
    ....
    }

Following the example I've added the swagger annotations  and also declared the class:

    @Path("/PubDocs.json")
    @Api(value = "/PubDocs", description = "Operations about pubDocs")
    @Produces({"application/json"})
    public class RestPublicDocsJSON extends RestPublicDocs{}

...then I've published the end point in a similar way:

        private Server publishRestServerSwagger(String addr,
                        List<Interceptor<? extends Message>> inInterceptors,
                        List<Interceptor<? extends Message>> outInterceptors){
                Server simpl=null;
                try {
                        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
                        sf.setServiceBean(new RestPublicDocsJSON()); //the implementor
                        sf.setServiceBean(new ApiListingResourceJSON()); //required from swagger
                        sf.setAddress(addr);
                        sf.setProvider(new JacksonJsonProvider()); //required from swagger
            BasicApplication ba = new BasicApplication();
            ba.setResourcePackage("com.prova.restPubDocs");
            sf.setApplication(ba); //required from swagger
                        sf.setProvider(new RestExceptionHandler()); //my exception mapper
                      
                        if (inInterceptors != null) {
                                for (Interceptor<? extends Message> interceptor : inInterceptors) {
                                        sf.getInInterceptors().add(interceptor);
                                }
                        }
                        if (outInterceptors != null) {
                                for (Interceptor<? extends Message> interceptor : outInterceptors) {
                                        sf.getOutInterceptors().add(interceptor);
                                }
                        }
                      
                        //add new rest fault interceptor
                        sf.getOutFaultInterceptors().add(new RestFaultInterceptor());
                        //new management end
                        simpl = sf.create();
                        log.info("Endpoint has been published on " + addr);
                } catch (Exception e) {
                        log.warn("Error publishing endpoint: " + e.toString(), e);
                }
              
                return simpl;
        }


The publication seems to be successful and no exception occurs but two different problems occur:

1) when I call the ws, a javax.ws.rs.WebApplicationException with status 404 and all values null occurs.
   If I remove the annotations @Path("/PubDocs.json") from the RestPublicDocsJSON class the api works properly and no exception occurs.
   Why this happens?
   I can skip this problem removing the annotation @Path("/PubDocs.json")?
   Or this is is mandatory for swagger right behavior?

2) Continuing the test I have also another problem using swagger ui:
   I open the swagger-ui-master/dist/index.html and replace the url with my url
   "http://localhost:8162/PubDocs/api-docs.json"
   then I click the "Explore" button...
   but a NULL Pointer Exception occurs because the
   param array that arrives in the ApiListing class has the ServletConfig null.
   This the param array in input to ApiListing class:
   [com.wordnik.swagger.sample.util.BasicApplication@cb9a647, null, org.apache.cxf.jaxrs.impl.HttpHeadersImpl@705385d7, org.apache.cxf.jaxrs.impl.UriInfoImpl@7b781fdd]
   Why this is happens? And how cai I solve this?

Someone can help me?
Thanks a lot,

Andrea
Message has been deleted

dott...@gmail.com

unread,
Jun 5, 2013, 3:57:08 PM6/5/13
to swagger-sw...@googlegroups.com
Hi all,
I've tried to follow the new example at
https://github.com/wordnik/swagger-core/tree/develop-1.3/samples/java-jaxrs-cxf
but the problems are the same:
- if I put the @Path(PubDocs) on the implementor class the endPoint are are no longer accessible
- from swagger ui, calling the http://10.0.3.39:8162/PubDocs/api-docs
a "No message body writer has been found for response class ResourceListing" is printed and no response is shown
(this both with anotation @Path(..) on the implementor and without)
Someone knows why it happens?
Thanks a lot,

Andrea

tony tam

unread,
Jun 5, 2013, 4:03:11 PM6/5/13
to swagger-sw...@googlegroups.com
You are missing the @provider classes which marshal the swagger objects to JSON.

dott...@gmail.com

unread,
Jun 6, 2013, 2:53:45 AM6/6/13
to swagger-sw...@googlegroups.com
Hi Tony,
I've put the @Provider annotation only on the JacksonJsonProvider class, following the example. Is this correct?
Unlike the example however I do not know if I have properly initialized the BeanConfig object.....
If you have five minutes, I created a simple java project that should public the endPoint in a similar way with the example, but via java source code and without using the .xml configuration file.
I attach the zip folder to this forum...the entry point is "SwaggerTest.java" main method (it can be launched as a simple java application), the RestPublicDocs.java class is the implementor: this class contains both the static method to publish the endPoint ("publishEndpoint()" method called from the main), with address and port info (you can change them in this class), both the endPoints annotation and other info required by swagger.
It seems to publish the ws succesful but testing via swagger ui the two problems I've descriveb occur.
Any suggestion is welcome :-)
Thanks a lot,

Andrea

tony tam

unread,
Jun 6, 2013, 2:59:19 AM6/6/13
to swagger-sw...@googlegroups.com
Your sample didn't come through--the provider is already in the swagger-jaxrs project, and can be added to the cxf context as follows:


  <bean id="resourceWriter" class="com.wordnik.swagger.jaxrs.listing.ResourceListingProvider" />
  <bean id="apiWriter" class="com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider" />

and

    <property name="providers">
      <list>
...
        <!-- required for writing swagger classes -->
        <ref bean="resourceWriter" />
        <ref bean="apiWriter" />
      </list>
    </property>

dott...@gmail.com

unread,
Jun 6, 2013, 3:09:58 AM6/6/13
to swagger-sw...@googlegroups.com
The project without its required jar,


Andrea
SwaggerTEST.rar
Message has been deleted

dott...@gmail.com

unread,
Jun 6, 2013, 3:25:55 AM6/6/13
to swagger-sw...@googlegroups.com
The list of jar I've added...

Note that when I've posted the first mail in the forum I've followed the first lik to the example, latest project attached contains files that follow the example of the develop 1.3 version (if I was not wrong).
Thanks,

Andrea
jarList.txt
Message has been deleted

dott...@gmail.com

unread,
Jun 6, 2013, 12:25:32 PM6/6/13
to swagger-sw...@googlegroups.com
Hi Tony,
another question (always related to the example I've added).
Having to publish the endPoint via java code and without the applicationContext.xml file, I've added these statements in the method that publish the endPoints:

    com.wordnik.swagger.jaxrs.config.BeanConfig bcnf = new BeanConfig();;
    bcnf.setBasePath(base_address_Swagger);
    bcnf.setResourcePackage("com.wordnik.swagger.sample.resource");
    bcnf.setVersion("1.0.0");

are they equivalent to the configuration:

  <bean id="swaggerConfig" class="com.wordnik.swagger.jaxrs.config.BeanConfig">
    <property name="resourcePackage" value="com.wordnik.swagger.sample.resource"/>
    <property name="version" value="1.0.0"/>
    <property name="basePath" value="http://localhost:8002/api"/>
  </bean>

of the ApplicationContext.xml file? Or it is a wrong behavior?
I should also translate the statement:
<context:component-scan base-package="com.wordnik.swagger.sample" />
of the applicationContext.xml file into java code...do you know how can I do?
Thanks a lot and sorry for the trouble,

tony tam

unread,
Jun 6, 2013, 7:35:02 PM6/6/13
to swagger-sw...@googlegroups.com
Hi, yes, that's the same thing.  I don't think you need to set the <context:compent-scan... for the purposes of swagger.

dott...@gmail.com

unread,
Jun 7, 2013, 2:32:03 AM6/7/13
to swagger-sw...@googlegroups.com
Then I should have done all the necessary, some othert idea about the failure?
I can use swagger u.i. without any change, only replacing the original address and port with mine, right?

Another question: what is the link between the "basePath" of the BeanConfig and the property name="address" value="/"
of the JAXRSServerFactoryBean ?


<bean id="swaggerConfig" class="com.wordnik.swagger.jaxrs.config.BeanConfig">
    <property name="resourcePackage" value="com.wordnik.swagger.sample.resource"/>
    <property name="version" value="1.0.0"/>
    <property name="basePath" value="http://localhost:8002/api"/>
</bean>

<bean class="org.apache.cxf.jaxrs.JAXRSServerFactoryBean" init-method="create">
    <property name="address" value="/" />
....

Via java code to publish the endPoint with address and port that I want I've to set the address in the JAXRSServerFactoryBean

    JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
    sf.setServiceBean(implementor);
    sf.setServiceBean(new ApiListingResourceJSON());
    sf.setAddress("http://localhost:8002"); //for example


while in the .xml file the address of the JAXRSServerFactoryBean is "/" ...
so it seems that publishing the endPoint with configuration .xml file the two object (BeanConfig and JAXRSServerFactoryBean) are
linked, while publishing endPoint via java code, there isn't a visible link between them...
Any suggestion about our project?
Thanks a lot,


Andrea

dott...@gmail.com

unread,
Jun 7, 2013, 4:29:34 AM6/7/13
to swagger-sw...@googlegroups.com
Hi Tony,
debugging the code I've seen that when I call the "http://...../api-docs" from the swagger u.i.,
I arrive in the ApiListing but before returning the response to the caller the error:

    "No message body writer has been found for response class ResourceListing"
occurs.
It seems that no writer is present, even if it should be the
    com.wordnik.swagger.jaxrs.listing.ResourceListingProvider
added at pubblication time.
Do you know why this problem can occur?
Regards,

Andrea

dott...@gmail.com

unread,
Jun 7, 2013, 9:09:16 AM6/7/13
to swagger-sw...@googlegroups.com
Ok, I've solved with the help of cxf forum:
the problem was that when I published the endPoint from java code I used:

  
    JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
    ....
    sf.setProvider(new JacksonJsonProvider());
    sf.setProvider(new com.wordnik.swagger.sample.resource.SampleExceptionMapper());
    sf.setProvider(new ResourceListingProvider());
    sf.setProvider(new ApiDeclarationProvider());

but the setProvider method actually does not accumulate them, and so with more calls, only the last provider gets added.
So using setProviders method accepting a List the problem is fixed.
Cheers,

Andrea

tony tam

unread,
Jun 7, 2013, 10:41:47 AM6/7/13
to swagger-sw...@googlegroups.com
OK Great, and that's really weird that our sample is working :)

I'll update the sample and thanks for posting back.  So you're good now?

dott...@gmail.com

unread,
Jun 11, 2013, 9:57:02 AM6/11/13
to swagger-sw...@googlegroups.com
Hi Tony,
now the project works good!
However, now that I have to use swagger inside a more complex osgi project I've encountered another problem ( I hope this will be easier :-) ):
invoking the http://10.0.3.39:8161/api-docs from a web browser I receive this response without api documentation:

    {"apiVersion":"1.0.0","swaggerVersion":null,"basePath":"http://10.0.3.39:8161"}
even if I've annotated the endpoint with swagger annoattions and the log on the console show
    11-giu-2013 15.42.39 org.reflections.Reflections scan
    INFO: Reflections took 277 ms to scan 2 urls, producing 35 keys and 91 values
as always was good and the basePath set in
com.wordnik.swagger.jaxrs.config.BeanConfig object was right.
Any idea?
Thanks,

Andrea

Message has been deleted

dott...@gmail.com

unread,
Jun 11, 2013, 11:18:41 AM6/11/13
to swagger-sw...@googlegroups.com
Another question:
if I've to add more BeanConfig objects, each corresponding to a different BasePath (I've a lot of endPoints on different ports) how can I do?
I've seen that if I build more BeanConfig objects from java cose, only the latest seems to be used, in fact when I call the classic
http://10.0.3.39:8161/api-docs
I've this response:
{"apiVersion":"1.0.0","swaggerVersion":null,"basePath":"http://10.0.3.39:8162/PubDocs"}
in which the basePath is that corresponding to the latest BeanConfig I've created at publication time.
Regards,

Andrea

dott...@gmail.com

unread,
Jun 12, 2013, 2:06:20 AM6/12/13
to swagger-sw...@googlegroups.com
The problem of the empty API list was due to a reflection problem. In osgi bundles management you must specify the bundle containing swagger annotations to allow the right management of the API list.
So at publication time I've added the bundle to the reflection management using
    org.reflections.vfs.Vfs.addDefaultURLTypes(new BundleUrlType(bundleXYZ))
On the other hand for the problem of more BeanConfig objects (in that case only the latest one seems be registered), I still have not found the solution.
Any suggestion will be appreciated :-)
Best regards,

Andrea
Reply all
Reply to author
Forward
Message has been deleted
0 new messages