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

_links property schema using Spring Data REST is array instead of object #2359

Closed
clementdenis opened this issue Aug 25, 2023 · 5 comments · Fixed by #2404
Closed

_links property schema using Spring Data REST is array instead of object #2359

clementdenis opened this issue Aug 25, 2023 · 5 comments · Fixed by #2404
Labels
bug Something isn't working

Comments

@clementdenis
Copy link

Describe the bug

When working with Spring Data REST, the generated schema is an array of links, instead of a map of links (object with additionalProperties of type Link).
This bug is similar to #1090, but as it happens on the latest version (2.2.0), I'm opening a new one.

Here is a quick analysis of the problem:

  • Spring Data REST serializes fields of type org.springframework.hateoas.Links as an object using
    org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer
  • But SpringDoc sees org.springframework.hateoas.Links as a collection of org.springframework.hateoas.Link,
    so it generates an array schema of #/components/schemas/Link instead
  • OpenApiHateoasLinksCustomizer should be able to help (needs to be registered though), but as the generated schema references #/components/schemas/Link directly instead of referencing a #/components/schemas/Links schema, it's useless

Workaround

I could customize the generated spec to fix the _links properties with this:

@Bean
GlobalOpenApiCustomizer linksCustomizer(SpringDocConfigProperties springDocConfigProperties) {
    OpenApiHateoasLinksCustomizer linksCustomizer = new OpenApiHateoasLinksCustomizer(springDocConfigProperties);
    return openApi -> {
        //replace generated _links array schema with a reference to Links schema
        openApi.getComponents().getSchemas().forEach((__, schema) -> {
            Map properties = schema.getProperties();
            if (properties != null && properties.containsKey("_links")) {
                properties.put("_links", new ObjectSchema().$ref(AnnotationsUtils.COMPONENTS_REF + "Links"));
            }
        });
       //adds the missing Links schema
        linksCustomizer.customise(openApi);
    };
}

To Reproduce

Generate an OpenAPI spec including entities manages through Spring DATA REST repositories, using latest versions of Spring Boot (3.1.3), Spring Data (2023.0.2), SpringDoc (2.2.0).

The generated schema for "links" properties (in collection or entity models) is like this:

"_links": {
    "type": "array",
    "items": {
      "$ref": "#/components/schemas/Link"
    }
 }

The Link schema in itself is OK:

"Link": {
  "title": "Link",
  "type": "object",
  "properties": {
    "href": {
      "type": "string"
    },
    "hreflang": {
      "type": "string"
    },
    "title": {
      "type": "string"
    },
    "type": {
      "type": "string"
    },
    "deprecation": {
      "type": "string"
    },
    "profile": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "templated": {
      "type": "boolean"
    }
  }
}

Expected behavior

The generated schema for _links properties should be:

"_links" : {
  "$ref" : "#/components/schemas/Links"
}

and the Links schema should exist:

"Links" : {
  "type" : "object",
  "additionalProperties" : {
    "$ref" : "#/components/schemas/Link"
  }
}
@mathieu-amblard
Copy link
Contributor

mathieu-amblard commented Oct 6, 2023

@bnasslahsen I got the same issue without using Spring Data REST but spring-boot-starter-hateoas.

After investigating, it seems that the GlobalOpenApiCustomizer defined in SpringDocHateoasAutoConfiguration (https://github.com/springdoc/springdoc-openapi/blob/main/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocHateoasConfiguration.java#L104) is not registered when using actuator because it already provides a bean of such type (https://github.com/springdoc/springdoc-openapi/blob/main/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java#L493).

Here are my autoconfiguration debugging logs :

   SpringDocHateoasConfiguration#linksSchemaCustomizer:
      Did not match:
         - @ConditionalOnMissingBean (types: org.springdoc.core.customizers.GlobalOpenApiCustomizer; SearchStrategy: all) found beans of type 'org.springdoc.core.customizers.GlobalOpenApiCustomizer' actuatorOpenApiCustomizer (OnBeanCondition)

Therefore, I suggest to change the @ConditionalOnMissingBean like this @ConditionalOnMissingBean(Constants.LINKS_SCHEMA_CUSTOMISER) :

        @Bean(Constants.LINKS_SCHEMA_CUSTOMISER)
	@ConditionalOnMissingBean(name = Constants.LINKS_SCHEMA_CUSTOMISER)
	@Lazy(false)
	GlobalOpenApiCustomizer linksSchemaCustomizer(HateoasHalProvider halProvider, SpringDocConfigProperties springDocConfigProperties,
			ObjectMapperProvider objectMapperProvider) {
...
	}

Or to change the return type, OpenApiHateoasLinksCustomizer instead of GlobalOpenApiCustomizer :

        @Bean(Constants.LINKS_SCHEMA_CUSTOMISER)
	@ConditionalOnMissingBean
	@Lazy(false)
	OpenApiHateoasLinksCustomizer linksSchemaCustomizer(HateoasHalProvider halProvider, SpringDocConfigProperties springDocConfigProperties,
			ObjectMapperProvider objectMapperProvider) {
...
	}

But it will harder for end users to override it.

Thank you in advance for your help.

@uc4w6c
Copy link
Collaborator

uc4w6c commented Oct 13, 2023

@mathieu-amblard
Thank you.
Could you please create a pull request?

@uc4w6c uc4w6c closed this as completed Oct 13, 2023
@uc4w6c uc4w6c reopened this Oct 13, 2023
@mathieu-amblard
Copy link
Contributor

@uc4w6c Sure I will create one.

@petercooperjr-spls
Copy link

petercooperjr-spls commented Nov 15, 2023

Is there an estimate of when this will get released?

In the meantime I've copied that linksSchemaCustomizer bean definition into a @Configuration class (but without the @ConditionalOnMissingBean), which seems to fix it for now, but it'd be nice to know if we should be doing this throughout our projects or if a fixed version is about to get released that we can just update to. Thanks.

@bnasslahsen
Copy link
Collaborator

@petercooperjr-spls,

Should be released, by the end of this week-end.

@bnasslahsen bnasslahsen added the bug Something isn't working label Dec 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants