[Geoserver-devel] [JIRA] (GEOS-9886) yaml schemas definitions aren't compatible with OpenAPI (Swagger 2.0) definitions. Generated Swagger clients don't work.

mlebihan created an issue

GeoServer / BugGEOS-9886

yaml schemas definitions aren’t compatible with OpenAPI (Swagger 2.0) definitions. Generated Swagger clients don’t work.

Issue Type:

BugBug

Affects Versions:

2.18.2

Assignee:

Unassigned

Attachments:

ConfigurateurIT.java, pom.xml

Components:

REST

Created:

01/Feb/21 9:52 PM

Priority:

MediumMedium

Reporter:

mlebihan

Targeting this postWorkspace method in workspaces.yaml,

post:
operationId: postWorkspaces
tags:

- "Workspaces"
  summary: add a new workspace to GeoServer
  description: Adds a new workspace to the server
  security:
- basic: []
  parameters:
- name: workspaceBody
  description: The layer group body information to upload.
  in: body
  required: true
  schema:
  $ref: "#/definitions/Workspace"
- name: default
  in: query
  description: New workspace will be the used as the default. Allowed values are true or false, The default value is false.
  required: false
  type: boolean
  default: false
  consumes:
- application/json
- application/xml
  produces:
- text/html
- application/json
- application/xml
  responses:
  201:
  description: Created
  schema:
  type: string
  headers:
  Location:
  description: URL where the newly created workspace can be found
  type: string
  401:
  description: Unable to add workspace as it already exists

That has this definition (schema) for the Workspace :

definitions:
Workspace:
title: Workspace
xml:
name: workspace
type: object
properties:
name:
type: string
description: name of the workspace

I asked Swagger 2.0 to generate for me a REST API Client. A simple test allow to run it, then.

public void createWorkspace()

{ Workspace workspace = new Workspace(); workspace.setName("ecoemploi"); WorkspacesApi workspacesApi = new WorkspacesApi(apiClient()); String response = workspacesApi.postWorkspaces(workspace, true); }

This client sends a JSON body to the GeoServer REST API that is similar to this curl :
`curl -v -u admin:geoserver -XPOST -H “Content-type:text/json” -d "

{ name: ‘ecoemploi’ }

" http://localhost:8080/geoserver/rest/workspaces`
and makes it fail :

29 janv. 15:09:55 TRACE [org.geoserver.platform.resource] - polling contents of /home/marc/geoserver-2.18.2-bin/data_dir/gwc-layers
29 janv. 15:09:55 TRACE [org.geoserver.platform.resource] - delta computed in 329us for /home/marc/geoserver-2.18.2-bin/data_dir/gwc-layers
29 janv. 15:09:59 DEBUG [org.geoserver.security.IncludeQueryStringAntPathRequestMatcher] - Checking match of request : 'Path: /rest/workspaces, QueryString: default=true'; against '/web/**'
29 janv. 15:09:59 DEBUG [org.geoserver.security.IncludeQueryStringAntPathRequestMatcher] - Checking match of request : 'Path: /rest/workspaces, QueryString: default=true'; against '/gwc/rest/web/**'
29 janv. 15:09:59 DEBUG [org.geoserver.security.IncludeQueryStringAntPathRequestMatcher] - Checking match of request : 'Path: /rest/workspaces, QueryString: default=true'; against '/'
29 janv. 15:09:59 DEBUG [org.geoserver.security.IncludeQueryStringAntPathRequestMatcher] - Checking match of request : 'Path: /rest/workspaces, QueryString: default=true'; against '/j_spring_security_check'
29 janv. 15:09:59 DEBUG [org.geoserver.security.IncludeQueryStringAntPathRequestMatcher] - Checking match of request : 'Path: /rest/workspaces, QueryString: default=true'; against '/j_spring_security_check/'
29 janv. 15:09:59 DEBUG [org.geoserver.security.IncludeQueryStringAntPathRequestMatcher] - Checking match of request : 'Path: /rest/workspaces, QueryString: default=true'; against '/j_spring_security_logout'
29 janv. 15:09:59 DEBUG [org.geoserver.security.IncludeQueryStringAntPathRequestMatcher] - Checking match of request : 'Path: /rest/workspaces, QueryString: default=true'; against '/j_spring_security_logout/'
29 janv. 15:09:59 DEBUG [org.geoserver.security.IncludeQueryStringAntPathRequestMatcher] - Checking match of request : 'Path: /rest/workspaces, QueryString: default=true'; against '/rest/**'
29 janv. 15:09:59 DEBUG [org.geoserver.security.IncludeQueryStringAntPathRequestMatcher] - Matched Path: /rest/workspaces, QueryString: default=true with /rest/**
29 janv. 15:09:59 DEBUG [org.geoserver.security] - AuthenticationCache has no entry for basic, admin:bfa584f5598433a3c1fe16b00acc9c43
29 janv. 15:09:59 DEBUG [org.geoserver.security.rememberme.GeoServerTokenBasedRememberMeServices] - Did not send remember-me cookie (principal did not set parameter '_spring_security_remember_me')
29 janv. 15:09:59 DEBUG [org.geoserver.security.rememberme.GeoServerTokenBasedRememberMeServices] - Remember-me login not requested.
29 janv. 15:09:59 DEBUG [org.geoserver.security] - AuthenticationCache adding new entry for basic, admin:bfa584f5598433a3c1fe16b00acc9c43
29 janv. 15:09:59 DEBUG [org.geoserver.security] - Cache entries #: 0
29 janv. 15:09:59 DEBUG [org.geoserver.security] - AuthenticationCache added new entry for basic, admin:bfa584f5598433a3c1fe16b00acc9c43
29 janv. 15:09:59 DEBUG [org.geoserver.security] - Cache entries #: 1
29 janv. 15:09:59 DEBUG [org.geoserver.security.RESTfulPathBasedFilterInvocationDefinitionMap] - Converted URL to lowercase, from: '/rest/workspaces'; to: '/rest/workspaces' and httpMethod= POST
29 janv. 15:09:59 DEBUG [org.geoserver.security.RESTfulPathBasedFilterInvocationDefinitionMap] - ~~~~~~~~~~ antPath= /** methodList= [GET]
29 janv. 15:09:59 DEBUG [org.geoserver.security.RESTfulPathBasedFilterInvocationDefinitionMap] - Candidate is: '/rest/workspaces'; antPath is /**; matchedPath=true; matchedMethods=false
29 janv. 15:09:59 DEBUG [org.geoserver.security.RESTfulPathBasedFilterInvocationDefinitionMap] - ~~~~~~~~~~ antPath= /** methodList= [POST, DELETE, PUT]
29 janv. 15:09:59 DEBUG [org.geoserver.security.RESTfulPathBasedFilterInvocationDefinitionMap] - Candidate is: '/rest/workspaces'; antPath is /**; matchedPath=true; matchedMethods=true
29 janv. 15:09:59 DEBUG [org.geoserver.security.RESTfulPathBasedFilterInvocationDefinitionMap] - returning ADMIN
29 janv. 15:09:59 DEBUG [org.geoserver] - Thread 23 locking in mode WRITE
29 janv. 15:09:59 DEBUG [org.geoserver] - Thread 23 got the lock in mode WRITE
29 janv. 15:09:59 ERROR [org.geoserver.rest] - name
com.thoughtworks.xstream.mapper.CannotResolveClassException: name
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:81)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:55)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.PackageAliasingMapper.realClass(PackageAliasingMapper.java:88)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:79)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:74)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.SecurityMapper.realClass(SecurityMapper.java:71)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at org.geoserver.config.util.SecureXStream$DetailedSecurityExceptionWrapper.realClass(SecureXStream.java:490)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:47)
at com.thoughtworks.xstream.core.util.HierarchicalStreams.readClassType(HierarchicalStreams.java:29)
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:133)
at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1487)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1467)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1347)
at org.geoserver.config.util.XStreamPersister.load(XStreamPersister.java:665)
at org.geoserver.rest.converters.XStreamJSONMessageConverter.readInternal(XStreamJSONMessageConverter.java:60)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:199)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:206)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:158)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:131)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:127)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:798)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:873)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1623)
at org.geoserver.filters.ThreadLocalsCleanupFilter.doFilter(ThreadLocalsCleanupFilter.java:26)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.geoserver.filters.SpringDelegatingFilter$Chain.doFilter(SpringDelegatingFilter.java:69)
at org.geoserver.wms.animate.AnimatorFilter.doFilter(AnimatorFilter.java:70)
at org.geoserver.filters.SpringDelegatingFilter$Chain.doFilter(SpringDelegatingFilter.java:66)
at org.geoserver.filters.SpringDelegatingFilter.doFilter(SpringDelegatingFilter.java:41)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.geoserver.platform.AdvancedDispatchFilter.doFilter(AdvancedDispatchFilter.java:37)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:70)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:70)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.geoserver.security.filter.GeoServerAnonymousAuthenticationFilter.doFilter(GeoServerAnonymousAuthenticationFilter.java:51)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:70)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:215)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
at org.geoserver.security.filter.GeoServerBasicAuthenticationFilter.doFilter(GeoServerBasicAuthenticationFilter.java:81)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:70)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.geoserver.security.filter.GeoServerSecurityContextPersistenceFilter$1.doFilter(GeoServerSecurityContextPersistenceFilter.java:52)
at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.geoserver.security.GeoServerSecurityFilterChainProxy.doFilter(GeoServerSecurityFilterChainProxy.java:142)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.geoserver.filters.LoggingFilter.doFilter(LoggingFilter.java:101)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.geoserver.filters.XFrameOptionsFilter.doFilter(XFrameOptionsFilter.java:77)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.geoserver.filters.GZIPFilter.doFilter(GZIPFilter.java:53)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.geoserver.filters.SessionDebugFilter.doFilter(SessionDebugFilter.java:46)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.geoserver.filters.FlushSafeFilter.doFilter(FlushSafeFilter.java:42)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1602)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:540)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1700)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1667)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:220)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:152)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:505)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:698)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:804)
at java.base/java.lang.Thread.run(Thread.java:834)
29 janv. 15:09:59 DEBUG [org.geoserver] - Thread 23 locking in mode WRITE
29 janv. 15:09:59 DEBUG [org.geoserver] - Thread 23 releasing the lock in mode WRITE
29 janv. 15:09:59 DEBUG [org.geoserver.security.filter.GeoServerSecurityContextPersistenceFilter$1] - SecurityContextHolder now cleared, as request processing completed
29 janv. 15:10:00 TRACE [org.geoserver.platform.resource] - polling contents of /home/marc/geoserver-2.18.2-bin/data_dir/gwc-layers

I noticed that GeoServer built a special receiver for REST request, based on XStream.
But it expect a customized JSON body where another imbrication of json is added with a “workspace:” attribute :
This curl will work :
curl -v -u admin:geoserver -XPOST -H "Content-type:text/json" -d "{workspace:{name:'ecoemploi' }} " [http://localhost:8080/geoserver/rest/workspaces](http://localhost:8080/geoserver/rest/workspaces)

and there’s an "xml:attribute in theyaml` file that is giving indication about that to a human reader.

definitions:
Workspace:
title: Workspace
xml:
name: workspace
type: object
properties:
name:
type: string
description: name of the workspace

xml:
name: workspace

But this xml attribute isn’t a part of the OpenAPI (Swagger) 2.0 schema definition. Swagger generator won’t take it into account, and the yaml description of GeoServer seems ineffective to generate by this tool a working client.

Joined : test case, and a pom.xml to help setting the swagger client generator.

Add Comment

Add Comment

Get Jira notifications on your phone! Download the Jira Cloud app for Android or iOS


This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100154-sha1:b8f7bbe)

Atlassian logo