Hi Jean, You may run into Swagger JAX-RS scanner limitations, as far as I can tell - it checks class annotations for SwaggerDefinition, does not traverse the hierarchy [1].
[1] https://github.com/swagger-api/swagger-core/blob/1.5/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/Reader.java#L194 Best Regards, Andriy Redko JPU> RE: How to setup multiple JAXRS server endpoints JPU> Still one question ); JPU> The generated swagger file doesn’t take into account the @SwaggerDefintion JPU> on my interface classes? JPU> As a test I looked at JPU> *https://github.com/apache/cxf/tree/3.6.x-fixes/distribution/src/main/release/samples/jax_rs/description_swagger2_web** JPU> and** modified** sample2* JPU> <https://github.com/apache/cxf/tree/3.6.x-fixes/distribution/src/main/release/samples/jax_rs/description_swagger2_web JPU> and modified sample2> as follows: JPU> @Path("/sample2") JPU> @Api(value = "/sample2",authorizations= JPU> {@Authorization(value="bearer")},description = "Sample2 (modified) JAX-RS JPU> service with Swagger documentation") JPU> @SwaggerDefinition( JPU> info = @Info( JPU> description = "Sample2 server", JPU> version="1.0", JPU> title = "Test2", JPU> contact = @Contact(name = "J.P. Urkens",email = " JPU> *jean-pierre.urk...@devoteam.com* <jean-pierre.urk...@devoteam.com> JPU> ")), JPU> securityDefinition = JPU> @SecurityDefinition(apiKeyAuthDefinitions= JPU> *{@ApiKeyAuthDefinition(key="bearer",in=ApiKeyLocation.HEADER,name="Authorization",description="Use* JPU> <{@ApiKeyAuthDefinition(key=> the format 'Bearer JPU> <accessToken>'")}) JPU> ) JPU> public class Sample2 {...} JPU> This correctly generates the ‘securityDefintions’ in the swagger file. JPU> If include the same @SwaggerDefinition and the authorizations on the @Api JPU> annotation as above in my interface classes then the generated swagger JPU> file doesn’t JPU> contain the ‘securityDefintions’ ? JPU> Any idea what I might be missing? JPU> Regards, JPU> J.P. JPU> -----Original Message----- JPU> From: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com> JPU> Sent: dinsdag 23 mei 2023 12:52 JPU> To: 'Andriy Redko' <drr...@gmail.com>; 'dev@cxf.apache.org' < dev@cxf.apache.org>> JPU> Subject: RE: How to setup multiple JAXRS server endpoints JPU> Hi Andriy, JPU> I added the parameter usePathBasedConfig=true to the Swagger2Feature bean JPU> declarations but still it does generate an empty swagger.yaml for JPU> interfaces KmopResources and KmopDienstverlener although I noticed that for JPU> these interfaces the @Path() annotation was commented out (as I included it JPU> in the server declaration). After providing an empty @Path("") declaration JPU> on the API interface classes everything worked. JPU> Thanks for the support. JPU> -----Original Message----- JPU> From: Andriy Redko <drr...@gmail.com> JPU> Sent: dinsdag 23 mei 2023 3:42 JPU> To: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; dev@cxf.apache.org JPU> Subject: Re: How to setup multiple JAXRS server endpoints JPU> Hi Jean, JPU> The main problem to configure Swagger property in your particular case is JPU> that the server address is not "known" or "introspectable" for Swagger. JPU> Intuitively, it has to be set manually using basePath to the, essentially, JPU> the server address JPU> part: JPU> - /op/services/accounts JPU> - /op/services/resources JPU> - /op/services/dienstverlener JPU> You could read more about other Swagger properties you have asked here: JPU> https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-Configuration#configuration-properties JPU> You definitely need to set usePathBasedConfig to "true" otherwise you will JPU> see the same Swagger specs for all servers. We have a sample here which JPU> uses 2 jaxrs:server JPU> instances: JPU> https://github.com/apache/cxf/tree/3.6.x-fixes/distribution/src/main/release/samples/jax_rs/description_swagger2_web JPU> Regarding SwaggerUI, I think the value for each of those should be set to, JPU> respectively: JPU> - /op/services/accounts/swagger.yaml JPU> - /op/services/resources/swagger.yaml JPU> - /op/services/dienstverlener/swagger.yaml JPU> I believe this is matching your settings already, except the JPU> usePathBasedConfig part. The example referred above could be helpful, my JPU> apologies if I missed something, there are quite a lot of questions :-) The JPU> fact that the generated Swagger specification is empty is unexpected - it JPU> should not happen when JAX-RS resources are properly configured. JPU> Thank you. JPU> Best Regards, JPU> Andriy Redko JPU>> RE: How to setup multiple JAXRS server endpoints JPU>> Hi Andriy, JPU>> I am not quite understanding how to correctly configure the JPU> Swagger2Feature. JPU>> Referring to the attached cxf-endpoints configuration I (as a test) JPU>> created JPU>> 3 JAXRS server instances: JPU>> 1. A* KmopApiServer* server for the* JPU>> be.dvtm.aeo.op.sodexo.api.KmopApiService* interface, serving JPU>> requests for URI path: JPU>> * <protocol>**//<host:<port>/op/services/accounts* JPU>> ‘op’ = root path of the web application JPU>> ‘services’ = servlet path of the CXF-servlet JPU>> The address of the server is set to ‘/accounts’ and the @Path(…) JPU>> annotation on the interface class was cleared. JPU>> 2. A* Kmop**Resources**ApiServer* server for the* be.dvtm.aeo.op.* JPU>> *openapi.**api.Kmop**Recources**ApiService* interface, serving JPU>> requests for URI path: JPU>> * <protocol>**//<host:<port>/op/services/**resources* JPU>> The address of the server is set to ‘/resources’ and the @Path(…) JPU>> annotation on the interface class was cleared. JPU>> 3. A* Kmop**Dienstverlener**Server* server for the* JPU> be.dvtm.aeo.op.* JPU>> *openapi**.api.Kmop**Dienstverlener**Service* interface, serving JPU>> requests for URI path: JPU>> * <protocol>**//<host:<port>/op/services/**dienstverlener* JPU>> The address of the server is set to ‘/dienstverlener’ and the JPU>> @Path(…) annotation on the interface class was cleared. JPU>> For each of these server instances I’ve set the Swagger2Feature JPU>> with configuration as indicated in the attached cxf-endpoints.xml. JPU>> With regard to the configurations for the Swagger2Feature I’ve the JPU>> following questions: JPU>> a) Referring to *https://cxf.apache.org/docs/swagger2feature.html* JPU>> <https://cxf.apache.org/docs/swagger2feature.html> could you JPU>> clarify on the following configuration parameters: JPU>> *i. ** basePath* – Is this the path to the CXFServlet context (‘ JPU>> /op/services’) or to the JAX-RS server instance (e.g. JPU>> ‘/op/services/accounts’) or still something else? Is it used to JPU>> resolve service classes or is it just for documentation in the swagger JPU> file? JPU>> *ii. ** resourcePackage* – the description mentions ‘package names’ JPU>> while the default mentions ‘service classes’? Service 2 and 3 above JPU>> are within the same package (generated from the same yaml JPU>> specification that included both interfaces). JPU>> *iii. ** ig**noreRoutes* – is this taken into account when JPU>> scanAllResources=false? JPU>> *iv. ** swaggerUiConfig* – What is the correct ‘url’ parameter value JPU>> (cf. question ‘a’)? JPU>> b) What would be the correct URL to generate a swagger.yaml file JPU> for JPU>> each of the above interfaces? Initially I called: JPU>> *i. ** JPU> <protocol>**//<host:<port>/op/services/accounts**/swagger.yaml* JPU>> *ii. ** JPU> <protocol>**//<host:<port>/op/services/**resources/swagger.yaml* JPU>> *iii. ** <protocol>**//<host:<port>/op/services/**dienstver* JPU>> *lener/swagger.yaml* JPU>> All three requests delivered the same yaml specification, namely JPU> the one JPU>> for interface* KmopApiServer*? JPU>> c) I tried to debug the processing of the requests under ‘b)’ and JPU> this JPU>> is done by the class JAXRSInterceptor#processRequest where the JPU>> MessageImpl object for request “ii.” looks like the one attached. JPU>> It finds 3 resource JPU>> classes: JPU>> be.dvtm.aeo.op.openapi.api.impl.KmopResourcesApiServiceImpl JPU>> org.apache.cxf.jaxrs.swagger.Swagger2ApiListingResource JPU>> org.apache.cxf.jaxrs.swagger.ui.SwaggerUiService JPU>> è It matches the request to resource* JPU> Swagger2ApiListingResource* with JPU>> UriInfo={type=[yaml], FINAL_MATCH_GROUP=[/]}} and calling its* JPU>> process(…)* method. JPU>> è Here it seems to go wrong. It generates a SwaggerContextService JPU>> having basePath=/op/services/resources/,swaggerConfig=null, JPU>> usePathBasedConfig=null and then calls JPU>> SwaggerContextService.getSwagger() JPU>> which returns the Swagger definition for interface KmopApiServer? JPU>> It looks like it caches generated swagger definitions based on a JPU>> configIdKey with prefix ’swagger.config.id.xxx’. This key is the JPU>> same for all 3 interfaces as usePathBasedConfig=null JPU>> and maps to ‘swagger.config.id.default’. The usePathBasedConfig is JPU>> derived from the ServletConfig parameter JPU>> ‘swagger.use.path.based.config’.* So should this be set on the JPU>> declaration of the CXFServlet** in web.xml?* JPU>> è Actually the SwaggerConfig, the JaxrsScanner and the generated JPU> Swagger JPU>> are cached using keys like JPU>> ‘swagger.config.id.[default|baseUriPath]’, ‘ JPU>> scanner.config.id.[default|baseUriPath]’. Caching with ‘baseUriPath’ JPU> is only done when usePathBasedconfig=true. JPU>> è If I patch this to true then configIdKey=’ JPU>> swagger.config.id./op/services/resources/’ and no swagger entry is JPU>> cached for this key so it will generate a new one. Again by JPU>> patching JPU>> SwaggerContextService.isUsePathBasedConfigInitParamDefined(sc)=true JPU>> it will call: “swagger = scan(app, servletContext, sc, uriInfo);” JPU>> è Again Scanners are cached and if usePathBasedConfig=null it JPU> will use JPU>> the one cached under ‘swagger.scanner.id.default’ and this again JPU>> returns the swagger definition for the KmopApiService interface. JPU>> è So patching usePathBasedConfig=true will return a new one JPU>> (DefaultJaxrsScanner). The classes to scan for in this new scanner JPU>> are ‘ be.dvtm.aeo.op.openapi.api.impl.KmopResourcesApiServiceImpl‘ JPU>> which is correct. It will generate a new (but empty) Swagger object. JPU>> è Next Swagger2ApiListingResource will call the JPU>> customizer.customize(s), which still isn’t putting anything new in JPU>> the Swagger object. Should it or should the next step do this? JPU>> è Next BaseApiListingResource#getListing(…) is called which on JPU> its JPU>> turn calls getListingYamlResponse(..) JPU>> è The final result is a swagger.yaml document with following JPU> content: JPU>> swagger: "2.0" JPU>> info: JPU>> license: JPU>> name: "Apache 2.0 License" JPU>> url: http://www.apache.org/licenses/LICENSE-2.0.html JPU>> basePath: "/op/services/resources" JPU>> So basically an empty swagger file. JPU>> d) The usePathBasedConfig is derived from the ServletConfig JPU> parameter ‘ JPU>> swagger.use.path.based.config’. Without this parameter set to true JPU>> there will be only one Swaggerconfig, JaxrsScanner and Swagger JPU>> object.* So should this be set on the declaration of the JPU>> CXFServlet** in web.xml?* JPU>> The majority in this processing happens in the library JPU>> swagger-jaxrs-v1.6.10 which is included as a dependency on JPU> cxf-rt-rs-service-description-swagger. JPU>> Even if I patch usePathBasedConfig=true about everywhere where I JPU>> met this it still doesn’t generate a correct swagger.yaml. Am I JPU>> still missing some configuration parameter? JPU>> Any suggestions on how to resolve this would be welcome. JPU>> Regards, JPU>> J.P. Urkens JPU>> <<...>> <<...>> JPU>> -----Original Message----- JPU>> From: Andriy Redko <drr...@gmail.com> JPU>> Sent: maandag 8 mei 2023 23:15 JPU>> To: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; CXF Dev JPU>> List < dev@cxf.apache.org>>> JPU>> Subject: Re: How to setup multiple JAXRS server endpoints JPU>> Hi Jean, JPU>> Indeed the way you would like to do that is somewhat tricky. >>> So I tried to keep the @Path declaration on the interface classes but JPU>> changed them to @Path(“”). That does seems to work except the JPU>> swagger stuff no longer correctly works. JPU>> This is one of the possible options but OpenAPI/Swagger gets JPU>> confused for a JPU>> reason: the path is now implicit (not in the spec). JPU>> So how about this option: JPU>> - use only one JAX-RS server (address "/") JPU>> - host both resources but use @Path("accounts") and JPU>> @Path("resources") on them respectively JPU>> I see that for @Path("accounts") you need to apply the JPU>> "kmopApiAuthorizationFilter", that could be done using JPU>> DynamicFeature [1], [2]. If this is not the option and you would JPU>> prefer to use 2 separate JAX-RS servers, you may need to provide JPU>> your own instance of Swagger2Customizer [3], [4] which allows to JPU>> transform the OpenAPI/Swagger on the fly. Please let me know if that JPU> would it work for you, thank you. JPU>> [1] JPU>> https://docs.oracle.com/javaee/7/api/javax/ws/rs/container/DynamicF JPU>> eature.html JPU>> [2] JPU>> https://aredko.blogspot.com/2016/02/your-jax-rs-apis-were-not-born- JPU>> equal.html JPU>> [3] JPU>> https://cxf.apache.org/javadoc/latest/org/apache/cxf/jaxrs/swagger/ JPU>> Swagger2Customizer.html JPU>> [4] https://cxf.apache.org/docs/swagger2feature.html (has JPU>> customizer JPU>> property) JPU>> Best Regards, JPU>> Andriy Redko >>> Hi Andriy, >>> I am again getting into trouble with server endpoint declarations. >>> Now JPU>> because I am adding additional JAX-RS endpoints. >>> The issue is with: >>> 1. The 'address' attribute on the <jaxrs:server> declaration in JPU>> combination with >>> 2. The 'url-pattern' for the CXFServlet declaration in the web.xml JPU>> in combination with >>> 3. The @Path declaration in the interface class in combination with >>> 4. The @Path declaration on the interface method in combination with >>> So what I had is that my web application deployed under baseUlr 'op' >>> had JPU>> one JAXRS server endpoint with declarations like: >>> 1. <jaxrs:server id="restServer" JPU>> basePackages="be.dvtm.aeo.op.sodexo" address="/"> >>> 2. <url-pattern>/services/*</url-pattern> >>> 3. @Path("accounts") on the public interface class >>> 4. @Path("/{authorisationId}/customerFund") on the customerFund JPU>> interface method >>> A valid API call would thus be e.g.: >>> https://<hostname>:<port>/op/services/accounts/{authorizationId}/cust >>> o >>> merFund >>> And this works correctly. >>> We're now introducing additional JAX-RS service endpoints and now I >>> am JPU>> running into problems. This second endpoint was declared with: >>> 1. <jaxrs:server id="resourceServer" JPU>> basePackages="be.dvtm.aeo.op.resources" address="/"> >>> 2. <url-pattern>/services/*</url-pattern> >>> 3. @Path("resources") on the public interface class >>> 4. @Path("/NACE") on the NACE interface method >>> So here a valid API call woud be: JPU>> https://<hostname>:<port>/op/services/resources/NACE. >>> The problem is that I can not declare two <jaxrs:server> entries with >>> the JPU>> same ‘address’ as it throws the exception: >>> Caused by: org.apache.cxf.service.factory.ServiceConstructionException: JPU>> There is an endpoint already running on /. >>> So I tried changing the addresses to: >>> · address=”accounts” for the restServer >>> · address=”resources” for the resourceServer >>> But to keep the API-call URLs the same I removed the @Path >>> declaration on JPU>> the interface classes. By doing so the <jaxrs:server> bean JPU>> declarations no longer loads successfully. >>> So I tried to keep the @Path declaration on the interface classes but JPU>> changed them to @Path(“”). That does seems to work except the JPU>> swagger stuff no longer correctly works. >>> So what is the decent way to setup multiple JAX-RS server endpoints >>> where JPU>> each server has its own configuration regarding supported features: >>> · own validation >>> · own object and exception mappings >>> · own swagger file generation >>> · own logging (in separate file if possible) >>> I am using Apache CXF-3.5.2 which uses swagger-core v1.6.6 in >>> cooperation JPU>> with swager-ui v4.5.0. >>> Below the declarations of my endpoints <<...>> Thanks for any advice. >>> Regards, >>> J.P. Urkens >>> -----Original Message----- >>> From: Andriy Redko <drr...@gmail.com> >>> Sent: zaterdag 18 juni 2022 1:12 >>> To: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; >>> iss...@cxf.apache.org; dev@cxf.apache.org >>> Subject: Re: JAXRS server endpoint not gracefully shutdown Hi Jean, >>>> 1. a jaxrs server on url: '/<basePath>/services/service1' >>> Correct, so in the relative form like address="/<something>", the >>> JAX-RS JPU>> endpoint path would be: >>> <baseUrl>/<servlet path >>> mapping>/<address>/[@ApplicationPath]/[@Path] >>> The @ApplicationPath is optional in this case. >>>> 2. a jaxws service endpoint on '/<basePath>/services/service2' >>> The JAX-WS is very different from JAX-RS, essentially the action >>> comes JPU>> inside the SOAP message behind <baseUrl>/<servlet path mapping>/ JPU>> (@Path / @ApplicationPath are not relevant there). >>>> Question: Because now address="/" is set for the jaxrs:server will >>>> it >>>> also inspect requests targeted for the jaxws service as those >>>> requests have start with the same path '/<basePath>/services/... >>> This is a good question, I have not done it myself but I think it >>> should JPU>> work: >>> the servlet dispatches according to registered services, in this >>> regard JPU>> JAX-RS and JAX-WS should not conflict. Does it work in your case? JPU> Thank you. >>> Best Regards, >>> Andriy Redko >>>> Hi Andriy, >>>> Using address="/" seems to work but still I don't understand how the >>>> following work together: >>>> - path specification in servlet mapping for the CXF servlet >>>> (org.apache.cxf.transport.servlet.CXFServlet) >>>> - the 'address' attribute on the jaxrs:server bean declaration >>>> - the javax.ws.rs.Path or javax.jws.WebService annotation on the >>>> service API description Say I've two services with (relateive to the >>>> host) url's: >>>> 1. a jaxrs server on url: '/<basePath>/services/service1' >>>> 2. a jaxws service endpoint on '/<basePath>/services/service2' >>>> How do I configure above 3 aspects? Currently I have (working): >>>> 1.for the jaxrs:server endpoint: >>>> - servlet path mapping: '/services/*' >>>> - jaxrs-server address attribute: address="/" >>>> - @Path annotation: @Path("service1") 2.For the jaxws >>>> service endpoint: >>>> - servlet path mapping: '/services/*' (JAXWS and JAXRS >>>> requests are handleb by the same CXF servle) >>>> - jaxws:endpoint server address attribute: >>>> address="/service2" >>>> - @WebService(name="service2") A correct request for >>>> '1' would be '/basePath>/services/service1/<ID>'. >>>> A correct request for '2' would be '/basePath>/services/service2'. >>>> The jaxrs/jaxws configuration behavior seem to differ with respect to: >>>> - the server address attribute >>>> - The API annotation (@Path or @Webservice) The JAXWS server >>>> address attribute doesn't seem to interfere with the @Webservice >>>> annotation. While the jaxrs server address attribute does seem to >>>> interfere with the @Path annotation. I would have expected the jaxrs >>>> server aspects to be configured as: >>>> - servlet path mapping: '/services/*' >>>> - jaxrs-server address attribute: address="/service1" >>>> - @Path annotation: @Path("service1") but then a >>>> valid >>>> request would be >>>>> /services/service1/service1/<ID>'. >>>> For both the 'address' attribute is relative to the servlet path. >>>> The @Path Javadoc mentions that this path is relative to the >>>> ApplicationPath which thus seems to be relative to the jaxrs-server >>>> address attribute. As for @Webservice it doesnn't seem to be >>>> url-path JPU>> related. >>>> Question: Because now address="/" is set for the jaxrs:server will >>>> it >>>> also inspect requests targeted for the jaxws service as those >>>> requests have start with the same path '/<basePath>/services/...'. >>>> Albeit somewhat confusing. >>>> J.P. >>>> -----Original Message----- >>>> From: Andriy Redko <drr...@gmail.com> >>>> Sent: dinsdag 14 juni 2022 1:08 >>>> To: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; >>>> iss...@cxf.apache.org; dev@cxf.apache.org >>>> Subject: Re: JAXRS server endpoint not gracefully shutdown Hi Jean, >>>> Indeed, the jaxrs:server does not expect address to be omitted, you >>>> could use the "/" (and I believe an empty string would also make it): >>>> <jaxrs:server id="restServer" basePackages="xxx" address="/"> ... >>>> </jaxrs:server> >>>> Thank you. >>>> Hope it helps. >>>> Best Regards, >>>> Andriy Redko >>>>> I create a JAXRS server endpoint (CXF 3.5.2) using spring bean >>>>> declarations >>>>> like: >>>>> <jaxrs:server id="restServer" basePackages="xxx"> >>>>> <jaxrs:serviceBeans> >>>>> <ref bean="TestApi" /> >>>>> </jaxrs:serviceBeans> >>>>> <jaxrs:providers> >>>>> <…/> >>>>> </jaxrs:providers> >>>>> <jaxrs:features> >>>>> <… /> >>>>> </jaxrs:features> >>>>> <jaxrs:inInterceptors> >>>>> <… /> >>>>> </jaxrs:inInterceptors> >>>>> <jaxrs:outInterceptors>* >>>>> <**…**/>* >>>>> </jaxrs:outInterceptors>* >>>>> </jaxrs:server> >>>>> Here my “TestApi” bean interface is declared like: >>>>> @Path("accounts") >>>>> @Consumes(MediaType.*APPLICATION_JSON*) >>>>> @Produces(MediaType.*APPLICATION_JSON*) >>>>> public interface TestApi { >>>>> … >>>>> } >>>>> And CXF is triggered via a servlet configuration like: >>>>> <servlet> >>>>> <display-name>CXF Servlet</display-name> >>>>> <servlet-name>CXFServlet</servlet-name> >>>>> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servle >>>>> t -class>>>>>> >>>>> </servlet> >>>>> <servlet-mapping> >>>>> <servlet-name>CXFServlet</servlet-name> >>>>> <url-pattern>/services/*</url-pattern> >>>>> </servlet-mapping> >>>>> Because I’ve got the @Path declaration on the interface type I’ve >>>>> omitted >>>>> the address=”accounts” attribute on the jaxrs:server declaration >>>>> since otherwise >>>>> I noticed that the server would be listening to >>>>> /basepath/services/ accounts/accounts/…). >>>>> Now this configuration works perfectly, only when shutting down >>>>> the application server cxf calls >>>>> ServerImpl#destroy() >>>>> which delegates (via Obeservable) to >>>>> AbstractHTTPDestination#deactivate() >>>>> which calls >>>>> registry.removeDestination(path). >>>>> This path is null (no ‘address’ specified on jaxrs:server >>>>> declaration) and results in a NPE on the registry Map. >>>>> This causes an unclean shutdown of my server. >>>>> Is this an error in cxf or is my jaxrs:server configured incorrectly? >>>>> How does the ‘address’ attribute on the jaxrs:server declaration >>>>> correctly interact with the @Path parameter on the API interface? JPU>> <<...>>