Skip to content

Commit 5b88c1c

Browse files
committed
Changes report: parameter of type com.querydsl.core.types.Predicate ignored when unique. Fixes springdoc#1522.
1 parent 104ee94 commit 5b88c1c

File tree

12 files changed

+261
-53
lines changed

12 files changed

+261
-53
lines changed

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/customizers/QuerydslPredicateOperationCustomizer.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import org.springframework.data.util.CastUtils;
5555
import org.springframework.data.util.ClassTypeInformation;
5656
import org.springframework.data.util.TypeInformation;
57+
import org.springframework.util.CollectionUtils;
5758
import org.springframework.web.method.HandlerMethod;
5859

5960
/**
@@ -84,10 +85,6 @@ public QuerydslPredicateOperationCustomizer(QuerydslBindingsFactory querydslBind
8485

8586
@Override
8687
public Operation customize(Operation operation, HandlerMethod handlerMethod) {
87-
if (operation.getParameters() == null) {
88-
return operation;
89-
}
90-
9188
MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
9289

9390
int parametersLength = methodParameters.length;
@@ -127,7 +124,14 @@ public Operation customize(Operation operation, HandlerMethod handlerMethod) {
127124
}
128125
}
129126
}
130-
operation.getParameters().addAll(parametersToAddToOperation);
127+
128+
if(!CollectionUtils.isEmpty(parametersToAddToOperation)){
129+
if (operation.getParameters() == null)
130+
operation.setParameters(parametersToAddToOperation);
131+
else
132+
operation.getParameters().addAll(parametersToAddToOperation);
133+
}
134+
131135
return operation;
132136
}
133137

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package test.org.springdoc.api.app30;
2+
3+
import com.querydsl.core.types.Predicate;
4+
5+
import org.springframework.data.querydsl.binding.QuerydslPredicate;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RestController;
8+
9+
10+
@RestController
11+
public class HelloController {
12+
13+
@GetMapping("/")
14+
public User testQueryDslAndSpringDoc(@QuerydslPredicate(root = User.class, bindings = UserPredicate.class) Predicate predicate) {
15+
return null;
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package test.org.springdoc.api.app30;
2+
3+
4+
import com.querydsl.core.types.Path;
5+
import com.querydsl.core.types.PathMetadata;
6+
import com.querydsl.core.types.dsl.EntityPathBase;
7+
import com.querydsl.core.types.dsl.NumberPath;
8+
import com.querydsl.core.types.dsl.StringPath;
9+
10+
import static com.querydsl.core.types.PathMetadataFactory.forVariable;
11+
12+
13+
/**
14+
* QUser is a Querydsl query type for User
15+
*/
16+
public class QUser extends EntityPathBase<User> {
17+
18+
private static final long serialVersionUID = 222331676L;
19+
20+
public static final QUser user = new QUser("user");
21+
22+
public final StringPath email = createString("email");
23+
24+
public final StringPath firstName = createString("firstName");
25+
26+
public final NumberPath<Long> id = createNumber("id", Long.class);
27+
28+
public final StringPath lastName = createString("lastName");
29+
30+
public QUser(String variable) {
31+
super(User.class, forVariable(variable));
32+
}
33+
34+
public QUser(Path<? extends User> path) {
35+
super(path.getType(), path.getMetadata());
36+
}
37+
38+
public QUser(PathMetadata metadata) {
39+
super(User.class, metadata);
40+
}
41+
42+
}

springdoc-openapi-tests/springdoc-openapi-data-rest-tests/src/test/java/test/org/springdoc/api/app30/SpringDocApp30Test.java

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,55 +23,13 @@
2323

2424
package test.org.springdoc.api.app30;
2525

26-
import java.lang.reflect.Field;
27-
import java.util.HashMap;
28-
import java.util.Iterator;
29-
import java.util.Map;
30-
import java.util.Map.Entry;
31-
32-
import com.fasterxml.jackson.databind.ObjectMapper;
33-
import com.fasterxml.jackson.databind.introspect.SimpleMixInResolver;
34-
import com.fasterxml.jackson.databind.type.ClassKey;
35-
import io.swagger.v3.core.util.Json;
36-
import org.apache.commons.lang3.reflect.FieldUtils;
37-
import org.junit.jupiter.api.AfterEach;
38-
import org.junit.jupiter.api.BeforeEach;
3926
import test.org.springdoc.api.AbstractSpringDocTest;
4027

4128
import org.springframework.boot.autoconfigure.SpringBootApplication;
42-
import org.springframework.test.context.TestPropertySource;
4329

44-
@TestPropertySource(properties = "springdoc.enable-data-rest=false")
4530
public class SpringDocApp30Test extends AbstractSpringDocTest {
4631

4732
@SpringBootApplication
4833
static class SpringDocTestApp {}
4934

50-
private Map<ClassKey, Class<?>> springMixins = new HashMap<>();
51-
52-
@BeforeEach
53-
void init() throws IllegalAccessException {
54-
Field convertersField2 = FieldUtils.getDeclaredField(ObjectMapper.class, "_mixIns", true);
55-
SimpleMixInResolver _mixIns = (SimpleMixInResolver) convertersField2.get(Json.mapper());
56-
Field convertersField3 = FieldUtils.getDeclaredField(SimpleMixInResolver.class, "_localMixIns", true);
57-
Map<ClassKey, Class<?>> _localMixIns = (Map<ClassKey, Class<?>>) convertersField3.get(_mixIns);
58-
Iterator<Entry<ClassKey, Class<?>>> it = _localMixIns.entrySet().iterator();
59-
while (it.hasNext()) {
60-
Map.Entry<ClassKey, Class<?>> entry = it.next();
61-
if (entry.getKey().toString().startsWith("org.springframework")) {
62-
springMixins.put(entry.getKey(), entry.getValue());
63-
it.remove();
64-
}
65-
}
66-
67-
}
68-
69-
@AfterEach
70-
private void clean() throws IllegalAccessException {
71-
Field convertersField2 = FieldUtils.getDeclaredField(ObjectMapper.class, "_mixIns", true);
72-
SimpleMixInResolver _mixIns = (SimpleMixInResolver) convertersField2.get(Json.mapper());
73-
Field convertersField3 = FieldUtils.getDeclaredField(SimpleMixInResolver.class, "_localMixIns", true);
74-
Map<ClassKey, Class<?>> _localMixIns = (Map<ClassKey, Class<?>>) convertersField3.get(_mixIns);
75-
_localMixIns.putAll(springMixins);
76-
}
7735
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package test.org.springdoc.api.app30;
2+
3+
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.GeneratedValue;
6+
import jakarta.persistence.GenerationType;
7+
import jakarta.persistence.Id;
8+
import lombok.Getter;
9+
import lombok.Setter;
10+
11+
@Entity
12+
@Getter
13+
@Setter
14+
public class User {
15+
@Id
16+
@GeneratedValue(strategy = GenerationType.IDENTITY)
17+
private Long id;
18+
private String firstName;
19+
private String lastName;
20+
private String email;
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package test.org.springdoc.api.app30;
2+
3+
4+
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
5+
import org.springframework.data.querydsl.binding.QuerydslBindings;
6+
7+
public class UserPredicate implements QuerydslBinderCustomizer<QUser> {
8+
9+
10+
@Override
11+
public void customize(QuerydslBindings bindings, QUser user) {
12+
bindings.excludeUnlistedProperties(true);
13+
bindings.including(user.email);
14+
bindings.bind(user.firstName).as("name").withDefaultBinding();
15+
}
16+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
*
2222
*/
2323

24-
package test.org.springdoc.api.app30;
24+
package test.org.springdoc.api.app301;
2525

2626
import jakarta.persistence.Entity;
2727
import jakarta.persistence.GeneratedValue;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
*
2222
*/
2323

24-
package test.org.springdoc.api.app30;
24+
package test.org.springdoc.api.app301;
2525

2626
import org.springframework.data.rest.webmvc.BasePathAwareController;
2727
import org.springframework.web.bind.annotation.GetMapping;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
*
2222
*/
2323

24-
package test.org.springdoc.api.app30;
24+
package test.org.springdoc.api.app301;
2525

2626
import org.springframework.data.repository.PagingAndSortingRepository;
2727
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * * Copyright 2019-2020 the original author or authors.
6+
* * * *
7+
* * * * Licensed under the Apache License, Version 2.0 (the "License");
8+
* * * * you may not use this file except in compliance with the License.
9+
* * * * You may obtain a copy of the License at
10+
* * * *
11+
* * * * https://www.apache.org/licenses/LICENSE-2.0
12+
* * * *
13+
* * * * Unless required by applicable law or agreed to in writing, software
14+
* * * * distributed under the License is distributed on an "AS IS" BASIS,
15+
* * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* * * * See the License for the specific language governing permissions and
17+
* * * * limitations under the License.
18+
* * *
19+
* *
20+
*
21+
*
22+
*/
23+
24+
package test.org.springdoc.api.app301;
25+
26+
import java.lang.reflect.Field;
27+
import java.util.HashMap;
28+
import java.util.Iterator;
29+
import java.util.Map;
30+
import java.util.Map.Entry;
31+
32+
import com.fasterxml.jackson.databind.ObjectMapper;
33+
import com.fasterxml.jackson.databind.introspect.SimpleMixInResolver;
34+
import com.fasterxml.jackson.databind.type.ClassKey;
35+
import io.swagger.v3.core.util.Json;
36+
import org.apache.commons.lang3.reflect.FieldUtils;
37+
import org.junit.jupiter.api.AfterEach;
38+
import org.junit.jupiter.api.BeforeEach;
39+
import test.org.springdoc.api.AbstractSpringDocTest;
40+
41+
import org.springframework.boot.autoconfigure.SpringBootApplication;
42+
import org.springframework.test.context.TestPropertySource;
43+
44+
@TestPropertySource(properties = "springdoc.enable-data-rest=false")
45+
public class SpringDocApp301Test extends AbstractSpringDocTest {
46+
47+
@SpringBootApplication
48+
static class SpringDocTestApp {}
49+
50+
private Map<ClassKey, Class<?>> springMixins = new HashMap<>();
51+
52+
@BeforeEach
53+
void init() throws IllegalAccessException {
54+
Field convertersField2 = FieldUtils.getDeclaredField(ObjectMapper.class, "_mixIns", true);
55+
SimpleMixInResolver _mixIns = (SimpleMixInResolver) convertersField2.get(Json.mapper());
56+
Field convertersField3 = FieldUtils.getDeclaredField(SimpleMixInResolver.class, "_localMixIns", true);
57+
Map<ClassKey, Class<?>> _localMixIns = (Map<ClassKey, Class<?>>) convertersField3.get(_mixIns);
58+
Iterator<Entry<ClassKey, Class<?>>> it = _localMixIns.entrySet().iterator();
59+
while (it.hasNext()) {
60+
Map.Entry<ClassKey, Class<?>> entry = it.next();
61+
if (entry.getKey().toString().startsWith("org.springframework")) {
62+
springMixins.put(entry.getKey(), entry.getValue());
63+
it.remove();
64+
}
65+
}
66+
67+
}
68+
69+
@AfterEach
70+
private void clean() throws IllegalAccessException {
71+
Field convertersField2 = FieldUtils.getDeclaredField(ObjectMapper.class, "_mixIns", true);
72+
SimpleMixInResolver _mixIns = (SimpleMixInResolver) convertersField2.get(Json.mapper());
73+
Field convertersField3 = FieldUtils.getDeclaredField(SimpleMixInResolver.class, "_localMixIns", true);
74+
Map<ClassKey, Class<?>> _localMixIns = (Map<ClassKey, Class<?>>) convertersField3.get(_mixIns);
75+
_localMixIns.putAll(springMixins);
76+
}
77+
}

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

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,64 @@
1010
"description": "Generated server url"
1111
}
1212
],
13-
"paths": {},
13+
"paths": {
14+
"/": {
15+
"get": {
16+
"tags": [
17+
"hello-controller"
18+
],
19+
"operationId": "testQueryDslAndSpringDoc",
20+
"parameters": [
21+
{
22+
"name": "name",
23+
"in": "query",
24+
"schema": {
25+
"type": "string"
26+
}
27+
},
28+
{
29+
"name": "email",
30+
"in": "query",
31+
"schema": {
32+
"type": "string"
33+
}
34+
}
35+
],
36+
"responses": {
37+
"200": {
38+
"description": "OK",
39+
"content": {
40+
"application/hal+json": {
41+
"schema": {
42+
"$ref": "#/components/schemas/User"
43+
}
44+
}
45+
}
46+
}
47+
}
48+
}
49+
}
50+
},
1451
"components": {
15-
"schemas": {}
52+
"schemas": {
53+
"User": {
54+
"type": "object",
55+
"properties": {
56+
"id": {
57+
"type": "integer",
58+
"format": "int64"
59+
},
60+
"firstName": {
61+
"type": "string"
62+
},
63+
"lastName": {
64+
"type": "string"
65+
},
66+
"email": {
67+
"type": "string"
68+
}
69+
}
70+
}
71+
}
1672
}
17-
}
73+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"paths": {},
14+
"components": {
15+
"schemas": {}
16+
}
17+
}

0 commit comments

Comments
 (0)