Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resources not listed : Jersey 2.5 + Swagger on Websphere 7 #829

Closed
engrun opened this issue Jan 22, 2015 · 49 comments
Closed

Resources not listed : Jersey 2.5 + Swagger on Websphere 7 #829

engrun opened this issue Jan 22, 2015 · 49 comments
Labels
Milestone

Comments

@engrun
Copy link

engrun commented Jan 22, 2015

Hi

I have successfully configured Swagger with our Jax-rs/Jersey 2 application.
Works fine with maven jetty plugin and on Tomcat test server

However, when deploying to Websphere 7, no resources are listed.
The /api-docs resources returns

{"apiVersion":"1.0","swaggerVersion":"1.2"}

My BeanConfig looks like this

 BeanConfig beanConfig = new BeanConfig();
 beanConfig.setVersion(apiVersion);
 beanConfig.setResourcePackage(resourcePackage);
 beanConfig.setBasePath(basePath);
 beanConfig.setDescription("EK resources");
 beanConfig.setTitle("EK API");
 beanConfig.setScan(true);

(apiVersion, resourcePackage and basePath are defined in a properties file and injected by Spring)

Not sure how to get past this.
We would like to have our APIs documented when running in our production and qa environments

Dependency in pom.xml

<groupId>com.wordnik</groupId>
<artifactId>swagger-jersey2-jaxrs_2.10</artifactId>
<version>1.3.12</version>
@webron
Copy link
Contributor

webron commented Jan 22, 2015

The beanConfig.setScan(true); line is the one kicking off the scanning.

I realize it works on Jetty/Tomcat, but obviously something is slightly different in the WebSphere environment.

Two suggestions:

  1. Can you try setting the resourcePackage explicitly just for the sake of testing (that is, use the string rather than load it from an external resource)? This may not be relevant if your apiVersion is indeed 1.0 in your spring configuration as well (that's another way to test, change the value in the spring config and see if it changes in the /api-docs).
  2. The other option is that the BeanConfig is not being loaded properly or at the right time. How did you set it up to run?

@engrun
Copy link
Author

engrun commented Jan 22, 2015

I have tested setting an explicit path.
And if I change the apiVersion, that is reflected in the json. So the correct values are injected.

Setup is

@Component
public class SwaggerConfiguration {

    @Value("${swagger.resourcePackage}")
    private String resourcePackage;

    @Value("${swagger.basePath}")
    private String basePath;

    @Value("${swagger.apiVersion}")
    private String apiVersion;

    @PostConstruct
    public void init() {

        BeanConfig beanConfig = new BeanConfig();
        beanConfig.setVersion(apiVersion);
        beanConfig.setResourcePackage(resourcePackage);
        beanConfig.setBasePath(basePath);
        beanConfig.setDescription("EK resources");
        beanConfig.setTitle("EK API");
        beanConfig.setScan(true);

        ScannerFactory.setScanner(beanConfig);
    }

}

This class is being component scanned by Spring.
Background info for this can be found here
http://jakubstas.com/spring-jersey-swagger-configuration/

The reason for doing it this way is to set a different basePath for different environments.

My JerseyConfig looks like this

public class RestConfig extends ResourceConfig {

    /**
     * Register JAX-RS application components.
     */
    public RestConfig() {

        //resources
        register(AccountingResource.class);
        register(ConcentrateReconciliationResource.class);
        register(FeedingPeriodResource.class);
        register(FeedStuffResource.class);
        register(HerdGrowthResource.class);
        register(RoughageReconciliationResource.class);
        register(VersionResource.class);

        //filters
        register(ResponseCacheFilter.class);
        register(ResponseCorsFilter.class);
        register(CsrfProtectionFilter.class);
        register(SecurityFilter.class);
        register(new HttpMethodOverrideFilter(HttpMethodOverrideFilter.Source.HEADER));

        //other
        register(JsonFeature.class);

//        //swagger
        register(com.wordnik.swagger.jersey.listing.ApiListingResource.class);
//        register(com.wordnik.swagger.jersey.listing.ApiDeclarationProvider.class);
        register(com.wordnik.swagger.jersey.listing.ApiListingResourceJSON.class);
//        register(com.wordnik.swagger.jersey.listing.ResourceListingProvider.class);
        register(com.wordnik.swagger.jersey.listing.JerseyApiDeclarationProvider.class);
        register(com.wordnik.swagger.jersey.listing.JerseyResourceListingProvider.class);


    }

}

The last block is the interesting one

That's it. No more config

@webron
Copy link
Contributor

webron commented Jan 22, 2015

Looks good, overall.

I doubt this is the problem, but the line ScannerFactory.setScanner(beanConfig); is not really needed. Can you remove it and check again? Just to get it out of the way.

@engrun
Copy link
Author

engrun commented Jan 22, 2015

I have removed ScannerFactory.setScanner(beanConfig); . Same as before

@webron
Copy link
Contributor

webron commented Jan 22, 2015

Is this the commercial version of websphere or the community edition?

@engrun
Copy link
Author

engrun commented Jan 22, 2015

Commercial. version 7.0.0.19

What's interesting is that to get Jersey to work on WAS7, we have to register each resource, as packages('my.package.goes.here') does not work. That is, in the ResourceConfig class.
So might be a related problem with classloaders?

The development team has structured the code like this

  • module1
  • application
  • webapp
  • othermodule

The "application" module contains all resources classes and config, whereas the "webapp" module only contains files under src/main/webapp.
So the resourcesclasses are packaged inside a jar in the lib folder when wrapping up the war file

@webron
Copy link
Contributor

webron commented Jan 22, 2015

Thank you for the additional information. Different classloaders could definitely be the issue.

Are the JAX-RS resources and the beanconfig in the same module?

@engrun
Copy link
Author

engrun commented Jan 22, 2015

No, I'll move the beanconfig, and retest

@engrun
Copy link
Author

engrun commented Jan 22, 2015

Same result I am afraid.

@webron
Copy link
Contributor

webron commented Jan 22, 2015

And to be certain, the ResourceConfig class is also in the same module as the resources, right?

@engrun
Copy link
Author

engrun commented Jan 22, 2015

Yes, Jax-RS resources, ResourceConfig and SwaggerConfiguration classes are now in the same module

@webron
Copy link
Contributor

webron commented Jan 22, 2015

I think the next step would be to enable the logs and try to see if there's anything there that can help us. Can you try that please? The samples have sample configurations for the logs.

@engrun
Copy link
Author

engrun commented Jan 22, 2015

Yes, I'll have a look at it tomorrow!

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Where can I post the log?

@fehguy
Copy link
Contributor

fehguy commented Jan 23, 2015

Best if you put it in a gist and post the link here.

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Ok, this is my log config (taken from samples)

<logger additivity="false" name="com.wordnik">
        <level value="DEBUG"/>
        <appender-ref ref="swaggerLogger"/>
    </logger>
    <logger additivity="false" name="org.atmosphere">
        <level value="DEBUG"/>
        <appender-ref ref="swaggerLogger"/>
    </logger>

the only thing logged when running on websphere is this

2015-01-23 09:01:17,249 DEBUG com.wordnik.swagger.jersey.listing.ApiListingCache$ - loading cache
2015-01-23 09:01:17,296 DEBUG com.wordnik.swagger.jersey.listing.ApiListingCache$ - cache has Set() keys
2015-01-23 09:01:17,530 DEBUG com.wordnik.swagger.jersey.listing.ApiListingCache$ - cache has Set() keys
2015-01-23 09:01:17,561 DEBUG com.wordnik.swagger.jersey.listing.ApiListingCache$ - cache has Set() keys

And this is logged in my regular application log

2015-01-23 09:01:17,264 WARN  org.reflections.Reflections - given scan urls are empty. set urls in the configuration

which is logged before the swagger log statements

Would it make sense to log org.reflections with level debug?

@webron
Copy link
Contributor

webron commented Jan 23, 2015

Tracing the error and looking into Reflection's code, it looks like the only way to get that error is if resourcePackage is empty or null.

I realize it doesn't make a lot of sense, especially since the other parameters seem to load fine.

Do you have an additional web.xml configuration (or applicationContext.xml)?

By the way, you never mentioned what happened when you tried setting the resourcePackage explicitly (you only mentioned you did it).

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Ok, I have tried hardcoded the settings

 BeanConfig beanConfig = new BeanConfig();
        beanConfig.setVersion("1.0");
        beanConfig.setResourcePackage("my.package.goes.here);
        beanConfig.setBasePath("https://mywashost/ekapi/rest");
        beanConfig.setDescription("EK resources");
        beanConfig.setTitle("EK API");
        beanConfig.setScan(true);

Makes no difference

@webron
Copy link
Contributor

webron commented Jan 23, 2015

what about the web.xml/applicationContext (for spring)?

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Here is the web.xml https://gist.github.com/engrun/8c2b6f4fcb7a40372112

The applicationContext is split into several files, and mixing both javaconfig and xml.
Do you really want to see it all? They are basically just wiring up beans and component-scanning packages. In addition, aspects, caching and security are configured in spring xmls.

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Regarding the parameters, this is the json generated
{"apiVersion":"1.0","swaggerVersion":"1.2","info":{"title":"EK API","description":"EK resources"}}

So the other parameters are definitely being picked up

@webron
Copy link
Contributor

webron commented Jan 23, 2015

Thanks for sharing the web.xml. Regarding the applicationContext, I only really need anything that may be related to Swagger (that is, relates to the swagger-core classes). I'm trying to figure out if there's a chance for duplicate definitions that may override each other.

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Ok, there is no reference to com.wordnik or swagger in any spring context files. That is: No other config that what's listed above

@webron
Copy link
Contributor

webron commented Jan 23, 2015

Okay, that's good. Thanks for the patience with this, this is a but uncharted ground and unfortunately I don't have access to WebSphere to do local testing so it requires some back and forth.

And since you say it works with jetty/tomcat, we know it's not a configuration issue. Most likely a class loading / ordering issue.

Do you have any other application on that WebSphere instance that produces a Swagger documentation?

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Yes, we have. However, that is an Jersey 1.x application with an older swagger implementation.

            <artifactId>swagger-jaxrs_2.9.1</artifactId>
            <version>1.2.5</version>

@webron
Copy link
Contributor

webron commented Jan 23, 2015

Do you have means to test the application on an isolated WebSphere instance? I'd rather we rule out any chance for conflict there.

@engrun
Copy link
Author

engrun commented Jan 23, 2015

We don't have an isolated instance unfortunately. If so, I would have to contact operations to install a new clean instance. I'm afraid that's not doable/is out of scope at the moment. An easier path would probably be to request upgrading to the latest fixpack. I'm not sure what the timeframe for that would be though

@webron
Copy link
Contributor

webron commented Jan 23, 2015

It's been a really long time for me since I had used WebSphere, but if I recall correctly, there are ways to control the order of the application loading and the scope of the class loaders.

Can you see if you can ensure that the new application is loaded before the old one for testing purposes?

@engrun
Copy link
Author

engrun commented Jan 23, 2015

I've set class loading to PARENT_LAST and modified startup order to ensure my new appliation loads before the existing jersey1 application. Still a problem

@webron
Copy link
Contributor

webron commented Jan 23, 2015

Another thing that's worth checking is whether you have the reflections.org library in websphere's shared libraries directory and if so, which version is there.

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Found a workaround!
https://code.google.com/p/reflections/issues/detail?id=158

It works now!

@webron
Copy link
Contributor

webron commented Jan 23, 2015

Aha! So it was the com.ibm.ws.classloader.strict parameter?

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Yes.
And thanks for assisting :)

@webron
Copy link
Contributor

webron commented Jan 23, 2015

Thanks for sharing the solution, it may prove helpful to other users as well.

Can we close the issue?

@engrun engrun closed this as completed Jan 23, 2015
@engrun
Copy link
Author

engrun commented Jan 23, 2015

I was a little bit too quick.
Adding this property breaks the Jersey 1.x application, which now logs the following

com.sun.jersey.core.spi.scanning.ScannerException: The URI scheme wsjar of the URI wsjar:file:/E:/Server/WebSphere/AppServer/profiles/AppSrv01/installedApps/APP10061Cell01/QA-reku-api-impl_war.ear/api-impl.war/WEB-INF/lib/api-3.28.0.jar!/no/tine/api/internal is not supported. Package scanning deployment is not supported for such URIs.
Try using a different deployment mechanism such as explicitly declaring root resource and provider classes using an extension of javax.ws.rs.core.Application
    at com.sun.jersey.core.spi.scanning.PackageNamesScanner.scan(PackageNamesScanner.java:227)
    at com.sun.jersey.core.spi.scanning.PackageNamesScanner.scan(PackageNamesScanner.java:141)
    at com.sun.jersey.api.core.ScanningResourceConfig.init(ScanningResourceConfig.java:80)
    at com.sun.jersey.api.core.PackagesResourceConfig.init(PackagesResourceConfig.java:104)
    at com.sun.jersey.api.core.PackagesResourceConfig.<init>(PackagesResourceConfig.java:78)
    at com.sun.jersey.api.core.PackagesResourceConfig.<init>(PackagesResourceConfig.java:89)
    at com.sun.jersey.spi.container.servlet.WebComponent.createResourceConfig(WebComponent.java:696)
    at com.sun.jersey.spi.container.servlet.WebComponent.createResourceConfig(WebComponent.java:674)

I'll revert the com.ibm.ws.classloader.strictproperty, and check with operations if we can run the app on another instance.

@engrun engrun reopened this Jan 23, 2015
@webron
Copy link
Contributor

webron commented Jan 23, 2015

I was going to check the option set it only for a specific application. The last sentence at http://www-01.ibm.com/support/knowledgecenter/api/content/nl/en-us/SSEQTP_7.0.0/com.ibm.websphere.nd.doc/info/ae/ae/xrun_jvm.html#com.ibm.ws.classloader.strict pretty much killed that suggestion.

@engrun
Copy link
Author

engrun commented Jan 23, 2015

The custom property is still a workaround, so I you feel that this issue is not longer a bug, you can of course close the issue again.

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Yeah I know. We were hoping for the same

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Apparently there is a setting in WAS8 (and also the Liberty profile) which looks promising.

useJarUrls  boolean     false   Whether to use jar: or wsjar: URLs for referencing files in archives

which can be set as a global classloading property

http://www-01.ibm.com/support/knowledgecenter/SSEQTP_8.5.5/com.ibm.websphere.wlp.doc/ae/rwlp_feature_servlet-3.0.html

This was introduced in fixpack explicitly mentioning Jersey and Hadoop
http://www-01.ibm.com/support/docview.wss?uid=swg1PM99378

Hopefully others on WAS8 can benefit from this if encountering this problem

@webron
Copy link
Contributor

webron commented Jan 23, 2015

Okay, just looked into the GitHub issues for reflections.org and it looks like some fixes were add (though one was rejected) that may help with resolving this issue.

This would require some further testing on your end.

First step would be to exclude the reflections.org dependency from swagger-core. This is to ensure that maven picks the right version.

The second step is to add the reflections.org dependency explicitly, with version 0.10-SNAPSHOT. It should be available from Sonatype and not central.

@engrun
Copy link
Author

engrun commented Jan 23, 2015

I'll try it. Do you have the url to the correct snapshot repo? Can't find it at https://repository.sonatype.org or https://oss.sonatype.org/content/repositories/snapshots/

@engrun
Copy link
Author

engrun commented Jan 23, 2015

I'll clone the repo and build it locally

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Argh.
0.10-SNAPSHOT requires java7, Websphere runs on jdk6 only.
Caused by: java.lang.UnsupportedClassVersionError: JVMCFRE003 bad major version; class=org/reflections/Configuration, offset=6

I'll have a last look at it on Monday.

@webron
Copy link
Contributor

webron commented Jan 23, 2015

Since you're already compiling it yourself, try modifying the pom.xml and set the target version - https://github.com/ronmamo/reflections/blob/master/pom.xml#L250 - to 1.6.

Another option is to use the jdk 1.5 profile - https://github.com/ronmamo/reflections/blob/master/pom.xml#L147-L157

@engrun
Copy link
Author

engrun commented Jan 23, 2015

Hmm there is a reason for target being set to 1.7

[ERROR] /Users/tine/Development/git-repos/reflections/src/main/java/org/reflections/util/ClasspathHelper.java:[392,49] diamond operator is not supported in -source 1.6
[ERROR] (use -source 7 or higher to enable diamond operator)

There is a profile called jdk1.5 in the pom.xml. However, building with that profile results in the exact same error.

It looks like we have to resort to one of two

  1. Deploy the application on an instance with the custom property set, and ensure that it does not break other applications
  2. Install a new instance

Again, thanks for assisting

@webron
Copy link
Contributor

webron commented Jan 23, 2015

That's an odd error. I'd expect it to work with source 1.7 and target 1.6. I'll try reaching out the reflections.org developer and see if he can provide any insight (at least regarding the websphere fixes).

@engrun
Copy link
Author

engrun commented Jan 26, 2015

Ok, let my know when you have any news. For now we will setup a new WAS instans as a workaround

@fehguy
Copy link
Contributor

fehguy commented Feb 1, 2015

we can't move to java 6 for swagger, so this is going to be a problem. I'll move to m2 just in case there's hope for some sort of resolution.

@fehguy fehguy added this to the v1.5.0-M2 milestone Feb 1, 2015
@webron webron added the P3 label Mar 10, 2015
@fehguy
Copy link
Contributor

fehguy commented Mar 29, 2015

hi, support for java6 is not possible.

@fehguy fehguy closed this as completed Mar 29, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants