Skip to content

Commit ea5b214

Browse files
gregturnAntonMolganov
authored andcommitted
Ignore fields with Optional.empty when performing Query by Example.
The Auditable interface introduces Optional getters, which when combined with Query by Example results in cryptic errors. By ignoring a probe's field that contains an Optional.empty, Query by Example works properly. NOTE: This fix actually tests outside the originally detected scope of Auditable, verifying that ALL Optional.empty() fields are properly handled. Closes spring-projects#2176 Original pull request spring-projects#2401
1 parent bd85e9b commit ea5b214

File tree

3 files changed

+156
-0
lines changed

3 files changed

+156
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2008-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.domain.sample;
17+
18+
import lombok.Data;
19+
20+
import java.util.Optional;
21+
22+
import javax.persistence.Entity;
23+
import javax.persistence.GeneratedValue;
24+
import javax.persistence.Id;
25+
26+
import org.springframework.lang.Nullable;
27+
28+
/**
29+
* @author Greg Turnquist
30+
*/
31+
@Entity
32+
@Data
33+
public class UserWithOptionalField {
34+
35+
@Id @GeneratedValue private Long id;
36+
private String name;
37+
private String role;
38+
39+
public UserWithOptionalField() {
40+
41+
this.id = null;
42+
this.name = null;
43+
this.role = null;
44+
}
45+
46+
public UserWithOptionalField(String name, @Nullable String role) {
47+
48+
this();
49+
this.name = name;
50+
this.role = role;
51+
}
52+
53+
public Optional<String> getRole() {
54+
return Optional.ofNullable(this.role);
55+
}
56+
57+
public void setRole(Optional<String> role) {
58+
this.role = role.orElse(null);
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2008-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.domain.sample;
17+
18+
import org.springframework.data.jpa.repository.JpaRepository;
19+
20+
/**
21+
* @author Greg Turnquist
22+
*/
23+
public interface UserWithOptionalFieldRepository extends JpaRepository<UserWithOptionalField, Long> {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2008-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.domain.support;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
20+
import java.util.List;
21+
import java.util.Optional;
22+
23+
import org.junit.jupiter.api.Test;
24+
import org.junit.jupiter.api.extension.ExtendWith;
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.context.annotation.ImportResource;
28+
import org.springframework.data.domain.Example;
29+
import org.springframework.data.jpa.domain.sample.UserWithOptionalField;
30+
import org.springframework.data.jpa.domain.sample.UserWithOptionalFieldRepository;
31+
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
32+
import org.springframework.test.context.ContextConfiguration;
33+
import org.springframework.test.context.junit.jupiter.SpringExtension;
34+
35+
/**
36+
* Integration test for {@link org.springframework.data.repository.query.QueryByExampleExecutor} involving
37+
* {@link Optional#empty()}.
38+
*
39+
* @author Greg Turnquist
40+
*/
41+
@ExtendWith(SpringExtension.class)
42+
@ContextConfiguration
43+
public class QueryByExampleWithOptionalEmptyTests {
44+
45+
@Autowired UserWithOptionalFieldRepository repository;
46+
UserWithOptionalField user;
47+
48+
@Test
49+
void queryByExampleTreatsEmptyOptionalsLikeNulls() {
50+
51+
// given
52+
UserWithOptionalField user = new UserWithOptionalField();
53+
user.setName("Greg");
54+
repository.saveAndFlush(user);
55+
56+
// when
57+
UserWithOptionalField probe = new UserWithOptionalField();
58+
probe.setName("Greg");
59+
Example<UserWithOptionalField> example = Example.of(probe);
60+
61+
// then
62+
List<UserWithOptionalField> results = repository.findAll(example);
63+
64+
assertThat(results).hasSize(1);
65+
assertThat(results).extracting(UserWithOptionalField::getName).containsExactly("Greg");
66+
}
67+
68+
@Configuration
69+
@EnableJpaRepositories(basePackageClasses = UserWithOptionalFieldRepository.class)
70+
@ImportResource("classpath:infrastructure.xml")
71+
static class JpaRepositoryConfig {}
72+
73+
}

0 commit comments

Comments
 (0)