Skip to content

Commit 9ccb7c7

Browse files
author
bnasslahsen
committed
Merge branch 'zarebski-m-master'
2 parents 2ed0248 + b2225b9 commit 9ccb7c7

File tree

8 files changed

+457
-2
lines changed

8 files changed

+457
-2
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocAnnotationsUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public static Schema resolveSchemaFromType(Class<?> schemaImplementation, Compon
5656
JsonView jsonView, Annotation[] annotations) {
5757
Schema schemaObject = extractSchema(components, schemaImplementation, jsonView, annotations);
5858
if (schemaObject != null && StringUtils.isBlank(schemaObject.get$ref())
59-
&& StringUtils.isBlank(schemaObject.getType())) {
59+
&& StringUtils.isBlank(schemaObject.getType()) && !(schemaObject instanceof ComposedSchema)) {
6060
// default to string
6161
schemaObject.setType("string");
6262
}

springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.springdoc.core.converters.AdditionalModelsConverter;
3636
import org.springdoc.core.converters.FileSupportConverter;
3737
import org.springdoc.core.converters.ModelConverterRegistrar;
38+
import org.springdoc.core.converters.PolymorphicModelConverter;
3839
import org.springdoc.core.converters.PropertyCustomizingConverter;
3940
import org.springdoc.core.converters.ResponseSupportConverter;
4041
import org.springdoc.core.converters.SchemaPropertyDeprecatingConverter;
@@ -84,7 +85,7 @@ LocalVariableTableParameterNameDiscoverer localSpringDocParameterNameDiscoverer(
8485

8586
@Bean
8687
@Lazy(false)
87-
AdditionalModelsConverter pageableSupportConverter() {
88+
AdditionalModelsConverter additionalModelsConverter() {
8889
return new AdditionalModelsConverter();
8990
}
9091

@@ -115,6 +116,13 @@ SchemaPropertyDeprecatingConverter schemaPropertyDeprecatingConverter() {
115116
return new SchemaPropertyDeprecatingConverter();
116117
}
117118

119+
@Bean
120+
@ConditionalOnMissingBean
121+
@Lazy(false)
122+
PolymorphicModelConverter polymorphicModelConverter() {
123+
return new PolymorphicModelConverter();
124+
}
125+
118126
@Bean
119127
@ConditionalOnMissingBean
120128
OpenAPIBuilder openAPIBuilder(Optional<OpenAPI> openAPI, ApplicationContext context,
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
*
3+
* *
4+
* * * Copyright 2019-2020 the original author or authors.
5+
* * *
6+
* * * Licensed under the Apache License, Version 2.0 (the "License");
7+
* * * you may not use this file except in compliance with the License.
8+
* * * You may obtain a copy of the License at
9+
* * *
10+
* * * https://www.apache.org/licenses/LICENSE-2.0
11+
* * *
12+
* * * Unless required by applicable law or agreed to in writing, software
13+
* * * distributed under the License is distributed on an "AS IS" BASIS,
14+
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* * * See the License for the specific language governing permissions and
16+
* * * limitations under the License.
17+
* *
18+
*
19+
*/
20+
21+
package org.springdoc.core.converters;
22+
23+
import java.lang.reflect.Modifier;
24+
import java.util.Collection;
25+
import java.util.Iterator;
26+
import java.util.List;
27+
import java.util.stream.Collectors;
28+
29+
import com.fasterxml.jackson.databind.JavaType;
30+
import io.swagger.v3.core.converter.AnnotatedType;
31+
import io.swagger.v3.core.converter.ModelConverter;
32+
import io.swagger.v3.core.converter.ModelConverterContext;
33+
import io.swagger.v3.core.util.Json;
34+
import io.swagger.v3.oas.models.media.ComposedSchema;
35+
import io.swagger.v3.oas.models.media.Schema;
36+
37+
public class PolymorphicModelConverter implements ModelConverter {
38+
@Override
39+
public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
40+
if (chain.hasNext()) {
41+
Schema<?> resolvedSchema = chain.next().resolve(type, context, chain);
42+
if (resolvedSchema == null || resolvedSchema.get$ref() == null) return resolvedSchema;
43+
return composePolymorphicSchema(type, resolvedSchema, context.getDefinedModels().values());
44+
}
45+
return null;
46+
}
47+
48+
private Schema composePolymorphicSchema(AnnotatedType type, Schema schema, Collection<Schema> schemas) {
49+
String ref = schema.get$ref();
50+
List<Schema> composedSchemas = schemas.stream()
51+
.filter(s -> s instanceof ComposedSchema)
52+
.map(s -> (ComposedSchema) s)
53+
.filter(s -> s.getAllOf() != null)
54+
.filter(s -> s.getAllOf().stream().anyMatch(s2 -> ref.equals(s2.get$ref())))
55+
.map(s -> new Schema().$ref("#/components/schemas/" + s.getName()))
56+
.collect(Collectors.toList());
57+
if (composedSchemas.isEmpty()) return schema;
58+
59+
ComposedSchema result = new ComposedSchema();
60+
if (isConcreteClass(type)) result.addOneOfItem(schema);
61+
composedSchemas.forEach(result::addOneOfItem);
62+
return result;
63+
}
64+
65+
private boolean isConcreteClass(AnnotatedType type) {
66+
JavaType javaType = Json.mapper().constructType(type.getType());
67+
Class<?> clazz = javaType.getRawClass();
68+
return !Modifier.isAbstract(clazz.getModifiers()) && !clazz.isInterface();
69+
}
70+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package test.org.springdoc.api.app118;
2+
3+
import com.fasterxml.jackson.annotation.JsonSubTypes;
4+
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
5+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
6+
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
7+
8+
@JsonTypeInfo(use = Id.NAME, property = "type")
9+
@JsonSubTypes({
10+
@Type(ChildOfAbstract1.class),
11+
@Type(ChildOfAbstract2.class)
12+
})
13+
public abstract class AbstractParent {
14+
private int id;
15+
16+
public int getId() {
17+
return id;
18+
}
19+
20+
public void setId(int id) {
21+
this.id = id;
22+
}
23+
}
24+
25+
class ChildOfAbstract1 extends AbstractParent {
26+
private String abstrachChild1Param;
27+
28+
public String getAbstrachChild1Param() {
29+
return abstrachChild1Param;
30+
}
31+
32+
public void setAbstrachChild1Param(String abstrachChild1Param) {
33+
this.abstrachChild1Param = abstrachChild1Param;
34+
}
35+
}
36+
37+
class ChildOfAbstract2 extends AbstractParent {
38+
private String abstractChild2Param;
39+
40+
public String getAbstractChild2Param() {
41+
return abstractChild2Param;
42+
}
43+
44+
public void setAbstractChild2Param(String abstractChild2Param) {
45+
this.abstractChild2Param = abstractChild2Param;
46+
}
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package test.org.springdoc.api.app118;
2+
3+
import com.fasterxml.jackson.annotation.JsonSubTypes;
4+
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
5+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
6+
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
7+
8+
@JsonTypeInfo(use = Id.NAME, property = "type")
9+
@JsonSubTypes({
10+
@Type(ChildOfConcrete1.class),
11+
@Type(ChildOfConcrete2.class)
12+
})
13+
public class ConcreteParent {
14+
private int id;
15+
16+
public int getId() {
17+
return id;
18+
}
19+
20+
public void setId(int id) {
21+
this.id = id;
22+
}
23+
}
24+
25+
class ChildOfConcrete1 extends ConcreteParent {
26+
private String concreteChild1Param;
27+
28+
public String getConcreteChild1Param() {
29+
return concreteChild1Param;
30+
}
31+
32+
public void setConcreteChild1Param(String concreteChild1Param) {
33+
this.concreteChild1Param = concreteChild1Param;
34+
}
35+
}
36+
37+
class ChildOfConcrete2 extends ConcreteParent {
38+
private String concreteChild2Param;
39+
40+
public String getConcreteChild2Param() {
41+
return concreteChild2Param;
42+
}
43+
44+
public void setConcreteChild2Param(String concreteChild2Param) {
45+
this.concreteChild2Param = concreteChild2Param;
46+
}
47+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package test.org.springdoc.api.app118;
2+
3+
import java.util.List;
4+
5+
import org.springframework.web.bind.annotation.PostMapping;
6+
import org.springframework.web.bind.annotation.RequestBody;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RestController;
9+
10+
@RestController
11+
@RequestMapping("class-hierarchy")
12+
public class Controller {
13+
@PostMapping("abstract-parent")
14+
public Response abstractParent(@RequestBody AbstractParent payload) {
15+
return null;
16+
}
17+
18+
@PostMapping("concrete-parent")
19+
public Response concreteParent(@RequestBody ConcreteParent payload) {
20+
return null;
21+
}
22+
}
23+
24+
class Response {
25+
AbstractParent abstractParent;
26+
27+
List<ConcreteParent> concreteParents;
28+
29+
public AbstractParent getAbstractParent() {
30+
return abstractParent;
31+
}
32+
33+
public void setAbstractParent(AbstractParent abstractParent) {
34+
this.abstractParent = abstractParent;
35+
}
36+
37+
public List<ConcreteParent> getConcreteParents() {
38+
return concreteParents;
39+
}
40+
41+
public void setConcreteParents(List<ConcreteParent> concreteParents) {
42+
this.concreteParents = concreteParents;
43+
}
44+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package test.org.springdoc.api.app118;
2+
3+
import test.org.springdoc.api.AbstractSpringDocTest;
4+
5+
import org.springframework.boot.autoconfigure.SpringBootApplication;
6+
7+
8+
public class SpringDocApp118Test extends AbstractSpringDocTest {
9+
10+
@SpringBootApplication
11+
static class SpringDocTestApp {}
12+
}

0 commit comments

Comments
 (0)