Closed
Description
Describe the bug
When I add inheritance to my data model, a call to /v3/api-docs.yaml
throw the following exception:
java.lang.NullPointerException: Cannot invoke "String.substring(int)" because the return value of "io.swagger.v3.oas.models.media.Schema.get$ref()" is null] with root cause
java.lang.NullPointerException: Cannot invoke "String.substring(int)" because the return value of "io.swagger.v3.oas.models.media.Schema.get$ref()" is null
at org.springdoc.data.rest.utils.SpringDocDataRestUtils.updateResponseSchema(SpringDocDataRestUtils.java:217) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.data.rest.utils.SpringDocDataRestUtils.lambda$enhanceResponseContent$0(SpringDocDataRestUtils.java:83) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:723) ~[na:na]
at org.springdoc.data.rest.utils.SpringDocDataRestUtils.lambda$enhanceResponseContent$1(SpringDocDataRestUtils.java:83) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at java.base/java.util.LinkedHashMap$LinkedValues.forEach(LinkedHashMap.java:647) ~[na:na]
at org.springdoc.data.rest.utils.SpringDocDataRestUtils.enhanceResponseContent(SpringDocDataRestUtils.java:72) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.data.rest.core.DataRestResponseService.buildEntityResponse(DataRestResponseService.java:151) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.data.rest.core.DataRestOperationService.buildEntityOperation(DataRestOperationService.java:159) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.data.rest.core.DataRestOperationService.buildOperation(DataRestOperationService.java:129) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.data.rest.core.DataRestRouterOperationService.buildRouterOperation(DataRestRouterOperationService.java:239) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.data.rest.core.DataRestRouterOperationService.buildRouterOperationList(DataRestRouterOperationService.java:186) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.data.rest.core.DataRestRouterOperationService.buildEntityRouterOperationList(DataRestRouterOperationService.java:120) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.data.rest.SpringRepositoryRestResourceProvider.findControllers(SpringRepositoryRestResourceProvider.java:365) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.data.rest.SpringRepositoryRestResourceProvider.lambda$getRouterOperations$6(SpringRepositoryRestResourceProvider.java:215) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:400) ~[spring-data-commons-2.4.5.jar:2.4.5]
at org.springdoc.data.rest.SpringRepositoryRestResourceProvider.getRouterOperations(SpringRepositoryRestResourceProvider.java:207) ~[springdoc-openapi-data-rest-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.webmvc.api.OpenApiResource.getPaths(OpenApiResource.java:221) ~[springdoc-openapi-webmvc-core-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.api.AbstractOpenApiResource.getOpenApi(AbstractOpenApiResource.java:287) ~[springdoc-openapi-common-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.webmvc.api.OpenApiResource.openapiYaml(OpenApiResource.java:192) ~[springdoc-openapi-webmvc-core-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at org.springdoc.webmvc.api.OpenApiWebMvcResource.openapiYaml(OpenApiWebMvcResource.java:132) ~[springdoc-openapi-webmvc-core-1.5.6-SNAPSHOT.jar:1.5.6-SNAPSHOT]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.4.jar:5.3.4]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.4.jar:5.3.4]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.4.jar:5.3.4]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.4.jar:5.3.4]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060) ~[spring-webmvc-5.3.4.jar:5.3.4]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962) ~[spring-webmvc-5.3.4.jar:5.3.4]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.4.jar:5.3.4]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.4.jar:5.3.4]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.43.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.4.jar:5.3.4]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.43.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.43.jar:9.0.43]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.4.jar:5.3.4]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.4.jar:5.3.4]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.4.jar:5.3.4]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:346) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:887) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1684) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.43.jar:9.0.43]
at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]
To Reproduce
Springboot: 2.4.3
Springdoc: 1.5.6-SNAPSHOT
@Entity
@EqualsAndHashCode(callSuper=false)
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Data
@NoArgsConstructor
@RequiredArgsConstructor
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "_type")
@JsonSubTypes({
@Type(value = Dog.class, name = "dog"),
@Type(value = Cat.class, name = "cat")
})
public class Pet extends BaseEntity {
@NonNull
@NotNull
private String name;
@NonNull
@ManyToOne
private Owner owner;
}
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class Dog extends Pet {
public static enum CoatType { SMOOTH, SHORT, COMBINATION, DOUBLE, HEAVY, SILKY, LONG, CURLY, WIRE, HAIRLESS }
@Enumerated(EnumType.STRING)
private CoatType coat;
@Builder
public Dog(String name, Owner owner, CoatType coat) {
super(name, owner);
this.coat = coat;
}
}
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Cat extends Pet {
public static enum CoatType { TABBY, TOROISE, COLORPOINT, BICOLOR, TRICOLOR, SOLID }
@Enumerated(EnumType.STRING)
private CoatType coat;
@Builder
public Cat(String name, Owner owner, CoatType coat) {
super(name, owner);
this.coat = coat;
}
}
public interface PetRepo extends JpaRepository<Pet, UUID> {
}
The full code to reproduce is available at https://github.com/mathias-ewald/springdoc-data-rest-example/tree/inheritance.
Expected behavior
I expect no exception to show but instead to see a nice and shiny specification of the inheritance model ;)
EDIT
The problem must have been introduced in 1.5.6-SNAPSHOT. When I revert back to 1.5.5 the problem is gone.