BAEL 7300: Return Map instead of List in Spring Data JPA (#15482)

* BAEL-7300: Return Map instead of List in Spring Data JPA

* BAEL-7300: Change the naming for the tests

* BAEL-7300: Fix formatting
This commit is contained in:
Eugene Kovko 2023-12-27 18:48:40 +01:00 committed by GitHub
parent a347c74e04
commit be84fd1b62
6 changed files with 342 additions and 0 deletions

View File

@ -0,0 +1,8 @@
package com.baeldung.spring.data.jpa.querymap;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AppConfig {
}

View File

@ -0,0 +1,93 @@
package com.baeldung.spring.data.jpa.querymap;
import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue
private Long id;
private String firstName;
private String lastName;
public User() {
}
public User(final String firstName, final String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public User(final Long id, final String firstName, final String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(final String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(final String lastName) {
this.lastName = lastName;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final User user = (User) o;
if (!Objects.equals(id, user.id)) {
return false;
}
if (!Objects.equals(firstName, user.firstName)) {
return false;
}
return Objects.equals(lastName, user.lastName);
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}

View File

@ -0,0 +1,37 @@
package com.baeldung.spring.data.jpa.querymap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.util.Streamable;
public interface UserRepository extends JpaRepository<User, Long> {
String FIND_ALL_USERS = "select u from User u";
@Query(FIND_ALL_USERS)
Streamable<User> findAllAsStreamable();
@Query(FIND_ALL_USERS)
Stream<User> findAllAsStream();
@Query(FIND_ALL_USERS)
Users findAllUsers();
default Map<Long, User> findAllAsMapUsingCollection() {
return findAll().stream().collect(Collectors.toMap(User::getId, Function.identity()));
}
default Map<Long, User> findAllAsMapUsingStreamable() {
return findAllAsStreamable().stream().collect(Collectors.toMap(User::getId, Function.identity()));
}
@Transactional
default Map<Long, User> findAllAsMapUsingStream() {
return findAllAsStream().collect(Collectors.toMap(User::getId, Function.identity()));
}
}

View File

@ -0,0 +1,40 @@
package com.baeldung.spring.data.jpa.querymap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.data.util.Streamable;
public class Users implements Streamable<User> {
private final Streamable<User> userStreamable;
public Users(Streamable<User> userStreamable) {
this.userStreamable = userStreamable;
}
@Override
public Iterator<User> iterator() {
return userStreamable.iterator();
}
public Map<Long, User> getUserIdToUserMap() {
return stream().collect(Collectors.toMap(User::getId, Function.identity()));
}
public List<User> getAllUsersWithShortNames(int maxNameLength) {
return stream()
.filter(s -> s.getFirstName().length() <= maxNameLength)
.collect(Collectors.toList());
}
public Map<Character, List<User>> groupUsersAlphabetically() {
return stream().collect(Collectors.groupingBy(s -> getFristCharacter(s.getFirstName())));
}
private Character getFristCharacter(final String string) {
return string.substring(0, 1).toUpperCase().charAt(0);
}
}

View File

@ -0,0 +1,114 @@
package com.baeldung.spring.data.jpa.querymap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(classes = AppConfig.class, properties = {
"spring.jpa.defer-datasource-initialization=true",
"spring.sql.init.data-locations=classpath:user-map-query-dml.sql"
})
@DisplayName("Given: ")
class UserRepositoryIntegrationTest {
public static final int NUMBER_OF_USERS = 50;
@Autowired
private UserRepository repository;
@Test
@DisplayName("repository is present")
void whenContextStartsRepositoryIsPresent() {
assumeThat(repository).isNotNull();
}
@Test
@DisplayName("data is loaded")
void whenUserPersistedUserCanBeFetched() {
final List<User> users = repository.findAll();
assumeThat(users).hasSize(NUMBER_OF_USERS);
}
@Nested
@DisplayName("When: ")
class When {
@Test
@DisplayName("fetch all users in a Map with Collection all of them are present")
void fetchUsersInMapUsingCollectionsThenAllOfThemPresent() {
final Map<Long, User> users = repository.findAllAsMapUsingCollection();
validateUserIdToUserMap(users);
}
@Test
@DisplayName("fetch all users in a Map with Streamable all of them are present")
void fetchUsersInMapUsingStreamableThenAllOfThemPresent() {
final Map<Long, User> users = repository.findAllAsMapUsingStreamable();
validateUserIdToUserMap(users);
}
@Test
@DisplayName("fetch all users in a Map with Stream all of them are present")
void fetchUsersInMapUsingStreamThenAllOfThemPresent() {
final Map<Long, User> users = repository.findAllAsMapUsingStream();
validateUserIdToUserMap(users);
}
@Test
@DisplayName("fetch all users in a Map with Streamable wrapper all of them are present")
void fetchUsersInMapUsingStreamableWrapperThenAllOfThemPresent() {
final Users streamableWrapper = repository.findAllUsers();
final Map<Long, User> users = streamableWrapper.getUserIdToUserMap();
validateUserIdToUserMap(users);
}
@Test
@DisplayName("fetch all users in a Map with Streamable wrapper "
+ "with a filter, all of them are present")
void fetchUsersInMapUsingStreamableWrapperWithFilterThenAllOfThemPresent() {
final Users users = repository.findAllUsers();
final int maxNameLength = 4;
final List<User> actual = users.getAllUsersWithShortNames(maxNameLength);
User[] expected = {
new User(9L, "Moe", "Oddy"),
new User(25L, "Lane", "Endricci"),
new User(26L, "Doro", "Kinforth"),
new User(34L, "Otho", "Rowan"),
new User(39L, "Mel", "Moffet")
};
assertThat(actual).containsExactly(expected);
}
@Test
@DisplayName("fetch all users in a Map with Streamable wrapper "
+ "and grouping all of them are present")
void fetchUsersInMapUsingStreamableWrapperAndGroupingThenAllOfThemPresent() {
final Users users = repository.findAllUsers();
final Map<Character, List<User>> alphabeticalGrouping = users.groupUsersAlphabetically();
final List<User> actual = alphabeticalGrouping.get('A');
User[] expected = {
new User(2L, "Auroora", "Oats"),
new User(4L, "Alika", "Capin"),
new User(20L, "Artus", "Rickards"),
new User(27L, "Antonina", "Vivian")};
assertThat(actual).containsExactly(expected);
}
}
private static void validateUserIdToUserMap(final Map<Long, User> users) {
assertThat(users.values()).hasSize(NUMBER_OF_USERS);
users.forEach((id, user) -> {
assertThat(user.getId()).isEqualTo(id);
});
}
}

View File

@ -0,0 +1,50 @@
INSERT INTO users (id, first_name, last_name) VALUES (1, 'Findlay', 'MacCafferty');
INSERT INTO users (id, first_name, last_name) VALUES (2, 'Auroora', 'Oats');
INSERT INTO users (id, first_name, last_name) VALUES (3, 'Shaylah', 'Coleson');
INSERT INTO users (id, first_name, last_name) VALUES (4, 'Alika', 'Capin');
INSERT INTO users (id, first_name, last_name) VALUES (5, 'Caressa', 'Caldicot');
INSERT INTO users (id, first_name, last_name) VALUES (6, 'Bonny', 'Kilday');
INSERT INTO users (id, first_name, last_name) VALUES (7, 'Carmina', 'Stopp');
INSERT INTO users (id, first_name, last_name) VALUES (8, 'Tiebout', 'Gamlyn');
INSERT INTO users (id, first_name, last_name) VALUES (9, 'Moe', 'Oddy');
INSERT INTO users (id, first_name, last_name) VALUES (10, 'Edita', 'Kenyon');
INSERT INTO users (id, first_name, last_name) VALUES (11, 'Melany', 'Blaylock');
INSERT INTO users (id, first_name, last_name) VALUES (12, 'Sigvard', 'Storrier');
INSERT INTO users (id, first_name, last_name) VALUES (13, 'Ogdon', 'Labitt');
INSERT INTO users (id, first_name, last_name) VALUES (14, 'Stacia', 'Waleworke');
INSERT INTO users (id, first_name, last_name) VALUES (15, 'Tiffi', 'Pearsey');
INSERT INTO users (id, first_name, last_name) VALUES (16, 'Nefen', 'Roddick');
INSERT INTO users (id, first_name, last_name) VALUES (17, 'Danie', 'Silman');
INSERT INTO users (id, first_name, last_name) VALUES (18, 'Giacobo', 'Slowey');
INSERT INTO users (id, first_name, last_name) VALUES (19, 'Robbie', 'McGillicuddy');
INSERT INTO users (id, first_name, last_name) VALUES (20, 'Artus', 'Rickards');
INSERT INTO users (id, first_name, last_name) VALUES (21, 'Pauline', 'Furnival');
INSERT INTO users (id, first_name, last_name) VALUES (22, 'Bella', 'Crittal');
INSERT INTO users (id, first_name, last_name) VALUES (23, 'Melicent', 'Lowe');
INSERT INTO users (id, first_name, last_name) VALUES (24, 'Delora', 'Leving');
INSERT INTO users (id, first_name, last_name) VALUES (25, 'Lane', 'Endricci');
INSERT INTO users (id, first_name, last_name) VALUES (26, 'Doro', 'Kinforth');
INSERT INTO users (id, first_name, last_name) VALUES (27, 'Antonina', 'Vivian');
INSERT INTO users (id, first_name, last_name) VALUES (28, 'Hanny', 'Challoner');
INSERT INTO users (id, first_name, last_name) VALUES (29, 'Tarrance', 'Beretta');
INSERT INTO users (id, first_name, last_name) VALUES (30, 'Emyle', 'Jaycox');
INSERT INTO users (id, first_name, last_name) VALUES (31, 'Lelah', 'Vesque');
INSERT INTO users (id, first_name, last_name) VALUES (32, 'Kitty', 'Pumphrey');
INSERT INTO users (id, first_name, last_name) VALUES (33, 'Karmen', 'Flaubert');
INSERT INTO users (id, first_name, last_name) VALUES (34, 'Otho', 'Rowan');
INSERT INTO users (id, first_name, last_name) VALUES (35, 'Jacinta', 'Tatlow');
INSERT INTO users (id, first_name, last_name) VALUES (36, 'Jennette', 'Wass');
INSERT INTO users (id, first_name, last_name) VALUES (37, 'Randi', 'Hambridge');
INSERT INTO users (id, first_name, last_name) VALUES (38, 'Filmer', 'Conibere');
INSERT INTO users (id, first_name, last_name) VALUES (39, 'Mel', 'Moffet');
INSERT INTO users (id, first_name, last_name) VALUES (40, 'Clement', 'MacGovern');
INSERT INTO users (id, first_name, last_name) VALUES (41, 'Silvana', 'Couronne');
INSERT INTO users (id, first_name, last_name) VALUES (42, 'Myles', 'Lambersen');
INSERT INTO users (id, first_name, last_name) VALUES (43, 'Sisile', 'Jeskins');
INSERT INTO users (id, first_name, last_name) VALUES (44, 'Jackie', 'Aulsford');
INSERT INTO users (id, first_name, last_name) VALUES (45, 'Duncan', 'Stapford');
INSERT INTO users (id, first_name, last_name) VALUES (46, 'Heddie', 'Wylder');
INSERT INTO users (id, first_name, last_name) VALUES (47, 'Homerus', 'Lyddyard');
INSERT INTO users (id, first_name, last_name) VALUES (48, 'Davis', 'Golson');
INSERT INTO users (id, first_name, last_name) VALUES (49, 'Marjory', 'Wilcock');
INSERT INTO users (id, first_name, last_name) VALUES (50, 'Sheffield', 'Pigford');