Bael 7281 (#15494)
* BAEL-7281: When use getOne and findOne methods Spring Data JPA * BAEL-7281: Cleanup * BAEL-7281: Test rename * BAEL-7281: Fix not updated name
This commit is contained in:
parent
cf80b7c3d4
commit
e316c193a0
|
@ -0,0 +1,8 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ApplicationConfig {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget.entity;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "users")
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
private Long id;
|
||||||
|
@Column(name = "first_name")
|
||||||
|
private String firstName;
|
||||||
|
@Column(name = "second_name")
|
||||||
|
private String secondName;
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(final Long id, final String firstName, final String secondName) {
|
||||||
|
this.id = id;
|
||||||
|
this.firstName = firstName;
|
||||||
|
this.secondName = secondName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(final Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstName(final String firstName) {
|
||||||
|
this.firstName = firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSecondName() {
|
||||||
|
return secondName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecondName(final String secondName) {
|
||||||
|
this.secondName = secondName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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(secondName, user.secondName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = id != null ? id.hashCode() : 0;
|
||||||
|
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
|
||||||
|
result = 31 * result + (secondName != null ? secondName.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"id=" + id +
|
||||||
|
", firstName='" + firstName + '\'' +
|
||||||
|
", secondName='" + secondName + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget.repository;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface NewTransactionUserRepository extends JpaRepository<User, Long> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
User getReferenceById(Long id);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Optional<User> findById(Long id);
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget.repository;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SimpleUserRepository extends JpaRepository<User, Long> {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget.service;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class NonTransactionalUserReferenceService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(NonTransactionalUserReferenceService.class);
|
||||||
|
private SimpleUserRepository repository;
|
||||||
|
|
||||||
|
public User findUserReference(final long id) {
|
||||||
|
log.info("Before requesting a user");
|
||||||
|
final User user = repository.getReferenceById(id);
|
||||||
|
log.info("After requesting a user");
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User findAndUseUserReference(final long id) {
|
||||||
|
final User user = repository.getReferenceById(id);
|
||||||
|
log.info("Before accessing a username");
|
||||||
|
final String firstName = user.getFirstName();
|
||||||
|
log.info("This message shouldn't be displayed because of the thrown exception: {}", firstName);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRepository(final SimpleUserRepository repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget.service;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SimpleUserService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SimpleUserService.class);
|
||||||
|
private final SimpleUserRepository repository;
|
||||||
|
|
||||||
|
public SimpleUserService(final SimpleUserRepository repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User findUser(final long id) {
|
||||||
|
log.info("Before requesting a user in a findUser method");
|
||||||
|
final Optional<User> optionalUser = repository.findById(id);
|
||||||
|
log.info("After requesting a user in a findUser method");
|
||||||
|
final User user = optionalUser.orElse(null);
|
||||||
|
log.info("After unwrapping an optional in a findUser method");
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget.service;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TransactionalUserReferenceService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TransactionalUserReferenceService.class);
|
||||||
|
private JpaRepository<User, Long> repository;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public User findUserReference(final long id) {
|
||||||
|
log.info("Before requesting a user");
|
||||||
|
final User user = repository.getReferenceById(id);
|
||||||
|
log.info("After requesting a user");
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public User findAndUseUserReference(final long id) {
|
||||||
|
final User user = repository.getReferenceById(id);
|
||||||
|
log.info("Before accessing a username");
|
||||||
|
final String firstName = user.getFirstName();
|
||||||
|
log.info("After accessing a username: {}", firstName);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRepository(final JpaRepository<User, Long> repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget;
|
||||||
|
|
||||||
|
import static com.baeldung.spring.data.persistence.findvsget.UserProvider.userSource;
|
||||||
|
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = ApplicationConfig.class, properties = {
|
||||||
|
"spring.jpa.generate-ddl=true",
|
||||||
|
"spring.jpa.show-sql=false"
|
||||||
|
})
|
||||||
|
abstract class DatabaseConfigurationBaseIntegrationTest {
|
||||||
|
|
||||||
|
private static final int NUMBER_OF_USERS = 10;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SimpleUserRepository repository;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void populateDatabase() {
|
||||||
|
final List<User> users = userSource()
|
||||||
|
.map(Arguments::get)
|
||||||
|
.map(s -> new User(((Long) s[0]), s[1].toString(), s[2].toString()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
repository.saveAll(users);
|
||||||
|
assumeThat(repository.findAll()).hasSize(NUMBER_OF_USERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void clearDatabase() {
|
||||||
|
repository.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.service.SimpleUserService;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
@DisplayName("findBy test:")
|
||||||
|
class FindUserIntegrationIntegrationTest extends DatabaseConfigurationBaseIntegrationTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SimpleUserService service;
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ArgumentsSource(UserProvider.class)
|
||||||
|
@DisplayName("when looking for a user by an existing ID returns a user")
|
||||||
|
void whenGettingUserByCorrectIdThenReturnUser(Long id, String firstName, String lastName) {
|
||||||
|
final User expected = new User(id, firstName, lastName);
|
||||||
|
final User actual = service.findUser(id);
|
||||||
|
assertThat(actual).isEqualTo(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@DisplayName("when looking for a user by a non-existing ID returns null")
|
||||||
|
@ValueSource(longs = {11, 12, 13})
|
||||||
|
void whenGettingUserByIncorrectIdThenReturnNull(Long id) {
|
||||||
|
assertThat(service.findUser(id)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.repository.NewTransactionUserRepository;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.service.NonTransactionalUserReferenceService;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.service.TransactionalUserReferenceService;
|
||||||
|
import org.hibernate.LazyInitializationException;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
|
||||||
|
@DisplayName("getReferenceBy test:")
|
||||||
|
class GetReferenceIntegrationIntegrationTest extends DatabaseConfigurationBaseIntegrationTest {
|
||||||
|
|
||||||
|
private static final long EXISTING_ID = 1L;
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("given non-transactional service, even if user exists")
|
||||||
|
class GivenNonTransactionalService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private NonTransactionalUserReferenceService nonTransactionalService;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void configureService(@Autowired SimpleUserRepository repository) {
|
||||||
|
nonTransactionalService.setRepository(repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenFindUserReferenceUsingOutsideServiceThenThrowsException() {
|
||||||
|
final User user = nonTransactionalService.findUserReference(EXISTING_ID);
|
||||||
|
assertThatExceptionOfType(LazyInitializationException.class)
|
||||||
|
.isThrownBy(user::getFirstName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenFindUserReferenceNotUsingOutsideServiceThenDontThrowException() {
|
||||||
|
final User user = nonTransactionalService.findUserReference(EXISTING_ID);
|
||||||
|
assertThat(user).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenFindUserReferenceUsingInsideServiceThenThrowsException() {
|
||||||
|
assertThatExceptionOfType(LazyInitializationException.class)
|
||||||
|
.isThrownBy(() -> nonTransactionalService.findAndUseUserReference(EXISTING_ID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("given transactional service with simple repository, even if user exists")
|
||||||
|
class GivenTransactionalService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TransactionalUserReferenceService transactionalService;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void configureService(@Autowired SimpleUserRepository repository) {
|
||||||
|
transactionalService.setRepository(repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenFindUserReferenceUsingOutsideServiceThenThrowsException() {
|
||||||
|
final User user = transactionalService.findUserReference(EXISTING_ID);
|
||||||
|
assertThatExceptionOfType(LazyInitializationException.class)
|
||||||
|
.isThrownBy(user::getFirstName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenFindUserReferenceNotUsingOutsideServiceThenDontThrowException() {
|
||||||
|
final User user = transactionalService.findUserReference(EXISTING_ID);
|
||||||
|
assertThat(user).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ArgumentsSource(UserProvider.class)
|
||||||
|
void whenFindUserReferenceUsingInsideServiceThenReturnsUser(Long id, String firstName, String lastName) {
|
||||||
|
final User expected = new User(id, firstName, lastName);
|
||||||
|
final User actual = transactionalService.findAndUseUserReference(id);
|
||||||
|
assertThat(actual).isEqualTo(expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@DisplayName("given transactional service with new transaction repository, even if user exists")
|
||||||
|
class GivenTransactionalServiceWithNewTransactionRepository {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TransactionalUserReferenceService transactionalServiceWithNewTransactionRepository;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void configureService(@Autowired NewTransactionUserRepository repository) {
|
||||||
|
transactionalServiceWithNewTransactionRepository.setRepository(repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenFindUserReferenceUsingOutsideServiceThenThrowsException() {
|
||||||
|
final User user = transactionalServiceWithNewTransactionRepository
|
||||||
|
.findUserReference(EXISTING_ID);
|
||||||
|
assertThatExceptionOfType(LazyInitializationException.class)
|
||||||
|
.isThrownBy(user::getFirstName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenFindUserReferenceNotUsingOutsideServiceThenDontThrowException() {
|
||||||
|
final User user = transactionalServiceWithNewTransactionRepository.findUserReference(EXISTING_ID);
|
||||||
|
assertThat(user).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenFindUserReferenceUsingInsideServiceThenThrowsExceptionDueToSeparateTransactions() {
|
||||||
|
assertThatExceptionOfType(LazyInitializationException.class)
|
||||||
|
.isThrownBy(() -> transactionalServiceWithNewTransactionRepository
|
||||||
|
.findAndUseUserReference(EXISTING_ID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.baeldung.spring.data.persistence.findvsget;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.ArgumentsProvider;
|
||||||
|
|
||||||
|
public class UserProvider implements ArgumentsProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<? extends Arguments> provideArguments(final ExtensionContext context) {
|
||||||
|
return userSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream<Arguments> userSource() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of(1L, "Saundra", "Krystek"),
|
||||||
|
Arguments.of(2L, "Korey", "Venners"),
|
||||||
|
Arguments.of(3L, "Lory", "Daffey"),
|
||||||
|
Arguments.of(4L, "Michail", "Spinella"),
|
||||||
|
Arguments.of(5L, "Emanuel", "Geertje"),
|
||||||
|
Arguments.of(6L, "Jervis", "Waugh"),
|
||||||
|
Arguments.of(7L, "Chantal", "Soldan"),
|
||||||
|
Arguments.of(8L, "Darnall", "Fanner"),
|
||||||
|
Arguments.of(9L, "Cordelia", "Hindge"),
|
||||||
|
Arguments.of(10L, "Lem", "Pitcock")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue