Manuel Waltschek
Manuel Waltschek

Reputation: 555

Swagger 2.x JaxrsAnnotationScanner does not find resource classes located in ear

I am currently trying to document an existing API with swagger core. I use swagger core 2.7 and resteasy 3 since I am deploying on wildfly 10. I have a war containing my rest servlet and some model classes located in an ear which also contains the war. The model classes are annoted with @Schema and therefore need a dependency on swagger-annotations. I followed the tutorial on https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-configuration

So I added the dependency to my war's pom.xml and the annotation module dependency to my module containing the model classes. It compiles and deploys, but when I browse to /myapp/openapi.yaml I see following warnings in the wildfly console for each resource which I defined in web.xml (except the ones contained in the war)

12:52:22,058 WARN [io.swagger.v3.jaxrs2.integration.JaxrsAnnotationScanner] (default task-5) error loading class from resourceClasses: at.prismasolutions.test.render.RPlotFormatParam from [Module "deployment.rserve-test.ear.at.prismasolutions.test.rserve.web-0.0.1-wildfly-SNAPSHOT.war:main" from Service Module Loader]: java.lang.ClassNotFoundException: at.prismasolutions.test.render.RPlotFormatParam from [Module "deployment.rserve-test.ear.at.prismasolutions.test.rserve.web-0.0.1-wildfly-SNAPSHOT.war:main" from Service Module Loader] at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:198) at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:363) at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:351) at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:93) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:264) at io.swagger.v3.jaxrs2.integration.JaxrsAnnotationScanner.classes(JaxrsAnnotationScanner.java:68) at io.swagger.v3.oas.integration.GenericOpenApiContext.read(GenericOpenApiContext.java:470) at io.swagger.v3.jaxrs2.integration.resources.BaseOpenApiResource.getOpenApi(BaseOpenApiResource.java:49) at io.swagger.v3.jaxrs2.integration.resources.OpenApiResource.getOpenApi(OpenApiResource.java:32) at io.swagger.v3.jaxrs2.integration.resources.OpenApiResource$Proxy$_$$_WeldClientProxy.getOpenApi(Unknown Source) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:139) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:295) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:249) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:236) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:402) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:209) at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:221) at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56) at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131) at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:53) at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:59) at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50) at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292) at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135) at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272) at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81) at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202) at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:805) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)

my configuration of web.xml:

    <servlet>
    <servlet-name>rserve-resteasy-servlet</servlet-name>
    <servlet-class>
        org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
    </servlet-class>
    <init-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/</param-value>
    </init-param>
    <!-- specify scanner implementation -->
    <init-param>
        <param-name>openApi.configuration.scannerClass</param-name>
        <param-value>io.swagger.v3.jaxrs2.integration.JaxrsAnnotationScanner</param-value>
    </init-param>
    <!-- pretty print -->
    <init-param>
        <param-name>openApi.configuration.prettyPrint</param-name>
        <param-value>true</param-value>
    </init-param>
    <!-- specify resource classes to scan -->
    <init-param>
        <param-name>openApi.configuration.resourceClasses</param-name>
        <param-value>
        rserve.web.RService,
        at.prismasolutions.test.RServeBean.evaluation.REvaluationObject,
        at.prismasolutions.test.RServeBean.evaluation.optima.REvaluationObservationObject,
        at.prismasolutions.test.render.RPlotFormatParam
        </param-value>
    </init-param>
</servlet>

Only rserve.web.RService is found which is located in the war file. Has anyone experience with setting up swagger using resources from a containing ear?

Upvotes: 7

Views: 2591

Answers (1)

Manuel Waltschek
Manuel Waltschek

Reputation: 555

Sadly I cannot remember which steps actually led to resolving this issue, but I ended up with removing the resourceClasses from the web.xml (except the service endpoint class resource RService which was contained in the war)

I am not using any derivate of javax.ws.rs.Application but instead register resources with the param resteasy.scan

my web.xml configuration contains

<context-param>
    <param-name>resteasy.scan</param-name>
    <param-value>true</param-value>
</context-param>

    <listener>
    <listener-class>
        org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<servlet>
    <servlet-name>rserve-resteasy-servlet</servlet-name>
    <servlet-class>
        org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    <init-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/</param-value>
    </init-param>
    <!-- specify scanner implementation -->
    <init-param>
        <param-name>openApi.configuration.scannerClass</param-name>
        <param-value>io.swagger.v3.jaxrs2.integration.JaxrsAnnotationScanner</param-value>
    </init-param>
    <!-- pretty print -->
    <init-param>
        <param-name>openApi.configuration.prettyPrint</param-name>
        <param-value>true</param-value>
    </init-param>
    <!-- specify resource classes to scan -->
    <init-param>
        <param-name>openApi.configuration.resourceClasses</param-name>
        <param-value> rweb.RService </param-value>
    </init-param>
</servlet>

Take a look at:

resteasy swagger core example

Also consider checking common mistakes with poor dependency management which might have been my problem back then:

e.g. jboss classloading: classes in ear cannot reference classes that were loaded by the war classloader

class dependencies reference different classes since they were registered twice (war classloader, ear classloader)

Upvotes: 1

Related Questions