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 #2176 Original pull request #2401
This commit is contained in:
committed by
Jens Schauder
parent
2f13a5eb92
commit
a7fd176643
@@ -56,6 +56,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Gierke
|
||||
* @author Jens Schauder
|
||||
* @author Greg Turnquist
|
||||
* @since 1.10
|
||||
*/
|
||||
public class QueryByExamplePredicateBuilder {
|
||||
@@ -146,6 +147,10 @@ public class QueryByExamplePredicateBuilder {
|
||||
|
||||
Object attributeValue = optionalValue.get();
|
||||
|
||||
if (attributeValue == Optional.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attribute.getPersistentAttributeType().equals(PersistentAttributeType.EMBEDDED)
|
||||
|| (isAssociation(attribute) && !(from instanceof From))) {
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2008-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.domain.sample;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@Entity
|
||||
@Data
|
||||
public class UserWithOptionalField {
|
||||
|
||||
@Id @GeneratedValue private Long id;
|
||||
private String name;
|
||||
private String role;
|
||||
|
||||
public UserWithOptionalField() {
|
||||
|
||||
this.id = null;
|
||||
this.name = null;
|
||||
this.role = null;
|
||||
}
|
||||
|
||||
public UserWithOptionalField(String name, @Nullable String role) {
|
||||
|
||||
this();
|
||||
this.name = name;
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public Optional<String> getRole() {
|
||||
return Optional.ofNullable(this.role);
|
||||
}
|
||||
|
||||
public void setRole(Optional<String> role) {
|
||||
this.role = role.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2008-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.domain.sample;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public interface UserWithOptionalFieldRepository extends JpaRepository<UserWithOptionalField, Long> {}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2008-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.domain.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.jpa.domain.sample.UserWithOptionalField;
|
||||
import org.springframework.data.jpa.domain.sample.UserWithOptionalFieldRepository;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
/**
|
||||
* Integration test for {@link org.springframework.data.repository.query.QueryByExampleExecutor} involving
|
||||
* {@link Optional#empty()}.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration
|
||||
public class QueryByExampleWithOptionalEmptyTests {
|
||||
|
||||
@Autowired UserWithOptionalFieldRepository repository;
|
||||
UserWithOptionalField user;
|
||||
|
||||
@Test
|
||||
void queryByExampleTreatsEmptyOptionalsLikeNulls() {
|
||||
|
||||
// given
|
||||
UserWithOptionalField user = new UserWithOptionalField();
|
||||
user.setName("Greg");
|
||||
repository.saveAndFlush(user);
|
||||
|
||||
// when
|
||||
UserWithOptionalField probe = new UserWithOptionalField();
|
||||
probe.setName("Greg");
|
||||
Example<UserWithOptionalField> example = Example.of(probe);
|
||||
|
||||
// then
|
||||
List<UserWithOptionalField> results = repository.findAll(example);
|
||||
|
||||
assertThat(results).hasSize(1);
|
||||
assertThat(results).extracting(UserWithOptionalField::getName).containsExactly("Greg");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories(basePackageClasses = UserWithOptionalFieldRepository.class)
|
||||
@ImportResource("classpath:infrastructure.xml")
|
||||
static class JpaRepositoryConfig {}
|
||||
|
||||
}
|
||||
@@ -45,6 +45,7 @@
|
||||
<class>org.springframework.data.jpa.domain.sample.Site</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.SpecialUser</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.User</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.UserWithOptionalField</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.VersionedUser</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.Dummy</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.SampleWithIdClassIncludingEntity</class>
|
||||
|
||||
Reference in New Issue
Block a user