Skip to content

Commit 7fa2f34

Browse files
author
bnasslahsen
committed
Merge branch 'valentinabojan-springdoc-data-rest-embedded-child-name'
2 parents 28e4555 + bdb4073 commit 7fa2f34

File tree

15 files changed

+200
-99
lines changed

15 files changed

+200
-99
lines changed

springdoc-openapi-data-rest/pom.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
35
<parent>
46
<artifactId>springdoc-openapi</artifactId>
57
<groupId>org.springdoc</groupId>

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/HalProvider.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,30 @@
2222

2323
import javax.annotation.PostConstruct;
2424

25-
import io.swagger.v3.core.converter.ModelConverters;
2625
import io.swagger.v3.core.util.Json;
27-
import org.springdoc.data.rest.converters.CollectionModelContentConverter;
2826

2927
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
3028
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
3129

3230
public class HalProvider {
3331

34-
private RepositoryRestConfiguration repositoryRestConfiguration;
32+
private Optional<RepositoryRestConfiguration> repositoryRestConfigurationOptional;
3533

36-
public HalProvider(Optional<RepositoryRestConfiguration> optionalRepositoryRestConfiguration) {
37-
optionalRepositoryRestConfiguration.ifPresent(repoRestConfiguration -> this.repositoryRestConfiguration =repoRestConfiguration);
34+
public HalProvider(Optional<RepositoryRestConfiguration> repositoryRestConfigurationOptional) {
35+
this.repositoryRestConfigurationOptional = repositoryRestConfigurationOptional;
3836
}
3937

4038
@PostConstruct
4139
private void init() {
42-
if (repositoryRestConfiguration == null || repositoryRestConfiguration.useHalAsDefaultJsonMediaType()) {
43-
if (!Jackson2HalModule.isAlreadyRegisteredIn(Json.mapper()))
44-
Json.mapper().registerModule(new Jackson2HalModule());
45-
ModelConverters.getInstance()
46-
.addConverter(CollectionModelContentConverter.getConverter());
47-
}
40+
if (!isHalEnabled())
41+
return;
42+
if (!Jackson2HalModule.isAlreadyRegisteredIn(Json.mapper()))
43+
Json.mapper().registerModule(new Jackson2HalModule());
44+
}
45+
46+
public boolean isHalEnabled() {
47+
return repositoryRestConfigurationOptional
48+
.map(RepositoryRestConfiguration::useHalAsDefaultJsonMediaType)
49+
.orElse(true);
4850
}
4951
}

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/SpringDocDataRestConfiguration.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.swagger.v3.oas.models.media.ObjectSchema;
3232
import io.swagger.v3.oas.models.media.StringSchema;
3333
import org.springdoc.core.customizers.OpenApiCustomiser;
34+
import org.springdoc.data.rest.converters.CollectionModelContentConverter;
3435
import org.springdoc.data.rest.converters.Pageable;
3536
import org.springdoc.data.rest.converters.RepresentationModelLinksOASMixin;
3637
import org.springdoc.data.rest.customisers.QuerydslPredicateOperationCustomizer;
@@ -46,6 +47,7 @@
4647
import org.springframework.hateoas.Link;
4748
import org.springframework.hateoas.Links;
4849
import org.springframework.hateoas.RepresentationModel;
50+
import org.springframework.hateoas.server.LinkRelationProvider;
4951

5052
import static org.springdoc.core.Constants.SPRINGDOC_ENABLED;
5153
import static org.springdoc.core.SpringDocUtils.getConfig;
@@ -82,6 +84,13 @@ HalProvider halProvider(Optional<RepositoryRestConfiguration> repositoryRestConf
8284
return new HalProvider(repositoryRestConfiguration);
8385
}
8486

87+
@Bean
88+
@ConditionalOnMissingBean
89+
@Lazy(false)
90+
CollectionModelContentConverter collectionModelContentConverter(HalProvider halProvider, LinkRelationProvider linkRelationProvider) {
91+
return halProvider.isHalEnabled() ? new CollectionModelContentConverter(linkRelationProvider) : null;
92+
}
93+
8594
/**
8695
* Registers an OpenApiCustomiser and a jackson mixin to ensure the definition of `Links` matches the serialized
8796
* output. This is done because the customer serializer converts the data to a map before serializing it.
@@ -90,8 +99,8 @@ HalProvider halProvider(Optional<RepositoryRestConfiguration> repositoryRestConf
9099
*/
91100
@Bean
92101
@Lazy(false)
93-
OpenApiCustomiser linksSchemaCustomiser(Optional<RepositoryRestConfiguration> repositoryRestConfiguration) {
94-
if (!repositoryRestConfiguration.isPresent() || !repositoryRestConfiguration.get().useHalAsDefaultJsonMediaType()) {
102+
OpenApiCustomiser linksSchemaCustomiser(HalProvider halProvider) {
103+
if (!halProvider.isHalEnabled()) {
95104
return openApi -> {
96105
};
97106
}

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/converters/CollectionModelContentConverter.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@
2828
import io.swagger.v3.core.converter.ModelConverter;
2929
import io.swagger.v3.core.converter.ModelConverterContext;
3030
import io.swagger.v3.oas.models.media.ArraySchema;
31-
import io.swagger.v3.oas.models.media.MapSchema;
31+
import io.swagger.v3.oas.models.media.ObjectSchema;
3232
import io.swagger.v3.oas.models.media.Schema;
33-
import io.swagger.v3.oas.models.media.StringSchema;
33+
import org.springframework.hateoas.EntityModel;
34+
import org.springframework.hateoas.server.LinkRelationProvider;
3435

3536
/**
3637
* Override resolved schema as there is a custom serializer that converts the data to a map before serializing it.
@@ -40,13 +41,10 @@
4041
*/
4142
public class CollectionModelContentConverter implements ModelConverter {
4243

43-
private static final CollectionModelContentConverter collectionModelContentConverter = new CollectionModelContentConverter();
44+
private LinkRelationProvider linkRelationProvider;
4445

45-
private CollectionModelContentConverter() {
46-
}
47-
48-
public static CollectionModelContentConverter getConverter() {
49-
return collectionModelContentConverter;
46+
public CollectionModelContentConverter(LinkRelationProvider linkRelationProvider) {
47+
this.linkRelationProvider = linkRelationProvider;
5048
}
5149

5250
@Override
@@ -55,12 +53,23 @@ public Schema<?> resolve(AnnotatedType type, ModelConverterContext context, Iter
5553
&& "_embedded".equalsIgnoreCase(type.getPropertyName())) {
5654
Schema<?> schema = chain.next().resolve(type, context, chain);
5755
if (schema instanceof ArraySchema) {
58-
return new MapSchema()
56+
Class<?> entityType = getEntityType(type);
57+
String entityClassName = linkRelationProvider.getCollectionResourceRelFor(entityType).value();
58+
59+
return new ObjectSchema()
5960
.name("_embedded")
60-
.additionalProperties(new StringSchema())
61-
.additionalProperties(schema);
61+
.addProperties(entityClassName, schema);
6262
}
6363
}
6464
return chain.hasNext() ? chain.next().resolve(type, context, chain) : null;
6565
}
66+
67+
private Class<?> getEntityType(AnnotatedType type) {
68+
Class<?> containerEntityType = ((CollectionType) (type.getType())).getContentType().getRawClass();
69+
70+
if (containerEntityType.isAssignableFrom(EntityModel.class)) {
71+
return ((CollectionType) type.getType()).getContentType().getBindings().getBoundType(0).getRawClass();
72+
}
73+
return containerEntityType;
74+
}
6675
}

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/converters/Pageable.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,17 @@
3232
public class Pageable {
3333

3434
@Min(0)
35-
@Parameter(description = "Zero-based page index (0..N)",schema = @Schema(type = "integer", defaultValue = "0"))
35+
@Parameter(description = "Zero-based page index (0..N)", schema = @Schema(type = "integer", defaultValue = "0"))
3636
private Integer page;
3737

3838
@Min(1)
39-
@Parameter(description = "The size of the page to be returned",schema = @Schema(type = "integer", defaultValue = "20"))
39+
@Parameter(description = "The size of the page to be returned", schema = @Schema(type = "integer", defaultValue = "20"))
4040
private Integer size;
4141

4242
@Parameter(description = "Sorting criteria in the format: property(,asc|desc). "
4343
+ "Default sort order is ascending. " + "Multiple sort criteria are supported."
4444
, name = "sort"
45-
,array = @ArraySchema(schema = @Schema(type = "string")))
45+
, array = @ArraySchema(schema = @Schema(type = "string")))
4646
private List<String> sort;
4747

4848
public Pageable(int page, int size, List<String> sort) {
@@ -74,7 +74,8 @@ public List<String> getSort() {
7474
public void setSort(List<String> sort) {
7575
if (sort == null) {
7676
this.sort.clear();
77-
} else {
77+
}
78+
else {
7879
this.sort = sort;
7980
}
8081
}

springdoc-openapi-data-rest/src/main/java/org/springdoc/data/rest/converters/PageableAsQueryParam.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import io.swagger.v3.oas.annotations.media.Content;
3030
import io.swagger.v3.oas.annotations.media.Schema;
3131

32-
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
32+
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
3333
@Retention(RetentionPolicy.RUNTIME)
3434
@Parameter(in = ParameterIn.QUERY
3535
, description = "Zero-based page index (0..N)"

springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/AbstractSpringDocTest.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,16 @@
2222
import java.nio.file.Files;
2323
import java.nio.file.Path;
2424
import java.nio.file.Paths;
25+
import java.util.List;
2526

27+
import io.swagger.v3.core.converter.ModelConverter;
2628
import io.swagger.v3.core.converter.ModelConverters;
2729
import nonapi.io.github.classgraph.utils.FileUtils;
2830
import org.junit.jupiter.api.AfterAll;
2931
import org.junit.jupiter.api.Test;
3032
import org.slf4j.Logger;
3133
import org.slf4j.LoggerFactory;
3234
import org.springdoc.core.Constants;
33-
import org.springdoc.data.rest.converters.CollectionModelContentConverter;
3435

3536
import org.springframework.beans.factory.annotation.Autowired;
3637
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@@ -54,6 +55,8 @@ public abstract class AbstractSpringDocTest {
5455

5556
public static String className;
5657

58+
private static List<ModelConverter> modelConverters;
59+
5760
@Autowired
5861
protected MockMvc mockMvc;
5962

@@ -70,10 +73,15 @@ public static String getContent(String fileName) throws Exception {
7073

7174
@AfterAll
7275
public static void afterClass() {
73-
ModelConverters.getInstance().removeConverter(CollectionModelContentConverter.getConverter());
76+
modelConverters.forEach(ModelConverters.getInstance()::removeConverter);
7477
System.clearProperty("spring.hateoas.use-hal-as-default-json-media-type");
7578
}
7679

80+
@Autowired
81+
private void setModelConverters(List<ModelConverter> modelConverters) {
82+
AbstractSpringDocTest.modelConverters = modelConverters;
83+
}
84+
7785
@Test
7886
public void testApp() throws Exception {
7987
className = getClass().getSimpleName();

springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app8/Album.java

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,28 @@
22

33
public class Album {
44

5-
private String title;
6-
private String description;
7-
private String releaseDate;
8-
9-
public Album(String title, String description, String releaseDate) {
10-
this.title = title;
11-
this.description = description;
12-
this.releaseDate = releaseDate;
13-
}
14-
15-
public String getTitle() {
16-
return title;
17-
}
18-
19-
public String getDescription() {
20-
return description;
21-
}
22-
23-
public String getReleaseDate() {
24-
return releaseDate;
25-
}
5+
private String title;
6+
7+
private String description;
8+
9+
private String releaseDate;
10+
11+
public Album(String title, String description, String releaseDate) {
12+
this.title = title;
13+
this.description = description;
14+
this.releaseDate = releaseDate;
15+
}
16+
17+
public String getTitle() {
18+
return title;
19+
}
20+
21+
public String getDescription() {
22+
return description;
23+
}
24+
25+
public String getReleaseDate() {
26+
return releaseDate;
27+
}
2628

2729
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package test.org.springdoc.api.app8;
2+
3+
import java.util.Arrays;
4+
5+
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.data.domain.Page;
7+
import org.springframework.data.domain.PageImpl;
8+
import org.springframework.data.web.PagedResourcesAssembler;
9+
import org.springframework.hateoas.PagedModel;
10+
import org.springframework.web.bind.annotation.GetMapping;
11+
import org.springframework.web.bind.annotation.RestController;
12+
13+
@RestController
14+
public class AlbumController {
15+
16+
@Autowired
17+
private AlbumModelAssembler albumModelAssembler;
18+
19+
@Autowired
20+
private PagedResourcesAssembler pagedResourcesAssembler;
21+
22+
@GetMapping("/api/albums")
23+
public PagedModel<Album> getAllAlbums() {
24+
Album album1 = new Album("album-title-1", "album-description-1", "album-release-date-1");
25+
Album album2 = new Album("album-title-2", "album-description-2", "album-release-date-2");
26+
Page<Album> albumPage = new PageImpl<>(Arrays.asList(album1, album2));
27+
28+
return pagedResourcesAssembler.toModel(albumPage, albumModelAssembler);
29+
}
30+
31+
}

springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app8/AlbumModelAssembler.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
@Component
1212
public class AlbumModelAssembler implements RepresentationModelAssembler<Album, EntityModel<Album>> {
1313

14-
@Override
15-
public EntityModel<Album> toModel(Album entity) {
16-
List<Link> links = new ArrayList<>();
17-
return new EntityModel<>(entity, links);
18-
}
14+
@Override
15+
public EntityModel<Album> toModel(Album entity) {
16+
List<Link> links = new ArrayList<>();
17+
return new EntityModel<>(entity, links);
18+
}
1919

2020
}

springdoc-openapi-data-rest/src/test/java/test/org/springdoc/api/app8/WebController.java

Lines changed: 0 additions & 30 deletions
This file was deleted.

springdoc-openapi-data-rest/src/test/resources/application-test.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
# * limitations under the License.
1616
# */
1717
#
18-
spring.main.banner-mode:"off"
18+
spring.main.banner-mode="off"
1919
logging.level.root=ERROR
2020
logging.level.test.org.springdoc.api=ERROR

springdoc-openapi-data-rest/src/test/resources/results/app4.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,12 @@
130130
"properties": {
131131
"_embedded": {
132132
"type": "object",
133-
"additionalProperties": {
134-
"type": "array",
135-
"items": {
136-
"$ref": "#/components/schemas/EntityModelEmployee"
133+
"properties": {
134+
"employees": {
135+
"type": "array",
136+
"items": {
137+
"$ref": "#/components/schemas/EntityModelEmployee"
138+
}
137139
}
138140
}
139141
},

0 commit comments

Comments
 (0)