├── .gitignore
├── spring-data-jpa-exercises-model
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── bobocode
│ │ └── model
│ │ ├── Gender.java
│ │ ├── RoleType.java
│ │ ├── Address.java
│ │ ├── Role.java
│ │ └── User.java
└── pom.xml
├── user-service
├── src
│ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── bobocode
│ │ │ ├── exception
│ │ │ └── EntityNotFoundException.java
│ │ │ ├── config
│ │ │ ├── RootConfig.java
│ │ │ └── JpaConfig.java
│ │ │ ├── dao
│ │ │ ├── CustomUserRepository.java
│ │ │ └── UserRepository.java
│ │ │ └── service
│ │ │ └── UserService.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── bobocode
│ │ └── UserServiceAppTest.java
├── pom.xml
└── README.MD
├── hello-jpa-repository
├── src
│ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── bobocode
│ │ │ ├── dao
│ │ │ └── UserRepository.java
│ │ │ └── config
│ │ │ ├── RootConfig.java
│ │ │ └── JpaConfig.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── bobocode
│ │ └── SpringDataJpaConfigTest.java
├── pom.xml
└── README.MD
├── README.md
├── spring-data-jpa-exercises-util
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── bobocode
│ └── util
│ └── TestDataGenerator.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | **/*.iml
3 | **/target
4 |
--------------------------------------------------------------------------------
/spring-data-jpa-exercises-model/src/main/java/com/bobocode/model/Gender.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.model;
2 |
3 | public enum Gender {
4 | MALE,
5 | FEMALE
6 | }
7 |
--------------------------------------------------------------------------------
/spring-data-jpa-exercises-model/src/main/java/com/bobocode/model/RoleType.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.model;
2 |
3 | public enum RoleType {
4 | USER, ADMIN, OPERATOR, CUSTOMER
5 | }
6 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/bobocode/exception/EntityNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.exception;
2 |
3 | public class EntityNotFoundException extends RuntimeException{
4 | public EntityNotFoundException(String message) {
5 | super(message);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/hello-jpa-repository/src/main/java/com/bobocode/dao/UserRepository.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.dao;
2 |
3 | import com.bobocode.model.User;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | /**
7 | * This interface represents a data access object (DAO) for {@link User}.
8 | *
9 | * todo: 1. Configure {@link UserRepository} as {@link JpaRepository} for class User
10 | */
11 | public interface UserRepository extends JpaRepository {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/bobocode/config/RootConfig.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.config;
2 |
3 | import org.springframework.transaction.PlatformTransactionManager;
4 |
5 | /**
6 | * This class is provides root Java config for Spring application.
7 | *
8 | * todo: 0. PLEASE NOTE, THAT SOME REQUIRED STEPS ARE OMITTED IN THE TODO LIST AND YOU HAVE TO DO IT ON YOUR OWN
9 | *
10 | * todo: 1. Configure {@link PlatformTransactionManager} bean with name "transactionManager"
11 | * todo: 2. Enable transaction management
12 | */
13 | public class RootConfig {
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/hello-jpa-repository/src/main/java/com/bobocode/config/RootConfig.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.config;
2 |
3 | import org.springframework.transaction.PlatformTransactionManager;
4 |
5 | /**
6 | * This class is provides root Java config for Spring application.
7 | *
8 | * todo: 1. PLEASE NOTE, THAT SOME REQUIRED STEPS ARE OMITTED IN THE TODO LIST AND YOU HAVE TO DO IT ON YOUR OWN
9 | *
10 | * todo: 2. Configure {@link PlatformTransactionManager} bean with name "transactionManager"
11 | * todo: 3. Enable transaction management
12 | */
13 | public class RootConfig {
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/spring-data-jpa-exercises-model/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | spring-data-jpa-exercises
7 | com.bobocode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | spring-data-jpa-exercises-model
13 |
14 |
15 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/bobocode/dao/CustomUserRepository.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.dao;
2 |
3 | import com.bobocode.model.RoleType;
4 |
5 | /**
6 | * This class declares custom {@link UserRepository} methods
7 | *
8 | * todo: 0. PLEASE NOTE, THAT SOME REQUIRED STEPS ARE OMITTED IN THE TODO LIST AND YOU HAVE TO DO IT ON YOUR OWN
9 | *
10 | * todo: 1. Create class called "CustomUserRepositoryImpl"
11 | * todo: 2. Mark that class {@link org.springframework.stereotype.Repository}
12 | * todo: 3. Mark that class {@link org.springframework.transaction.annotation.Transactional}
13 | * todo: 4. Implement method {@link CustomUserRepository#addRoleToAllUsers(RoleType)}
14 | */
15 | public interface CustomUserRepository {
16 | void addRoleToAllUsers(RoleType roleType);
17 | }
18 |
--------------------------------------------------------------------------------
/user-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | spring-data-jpa-exercises
7 | com.bobocode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | user-service
13 |
14 |
15 |
16 | com.bobocode
17 | spring-data-jpa-exercises-util
18 | 1.0-SNAPSHOT
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/hello-jpa-repository/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | spring-data-jpa-exercises
7 | com.bobocode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | hello-jpa-repository
13 |
14 |
15 |
16 | com.bobocode
17 | spring-data-jpa-exercises-util
18 | 1.0-SNAPSHOT
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/bobocode/dao/UserRepository.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.dao;
2 |
3 | import com.bobocode.model.User;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | /**
7 | * This interface represents a data access object (DAO) for {@link User}.
8 | *
9 | * todo: 0. PLEASE NOTE, THAT SOME REQUIRED STEPS ARE OMITTED IN THE TODO LIST AND YOU HAVE TO DO IT ON YOUR OWN
10 | *
11 | * todo: 1. Configure {@link UserRepository} as {@link JpaRepository} for class User
12 | * todo: 2. Create method that finds a list of Users by address city using Spring Data method name convention
13 | * todo: 3. Create method that finds optional user by email fetching its address and roles using {@link org.springframework.data.jpa.repository.Query}
14 | * todo: 4. Add custom User repository interface
15 | */
16 | public interface UserRepository extends JpaRepository{
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #
Spring Data JPA exercises
2 | The list of exercises dedicated to training your *Spring Data JPA* skills
3 |
4 | ### No pain, No gain :heavy_exclamation_mark:
5 |
6 | > Skill is only developed by hours and hours and hours of beating on your craft
7 |
8 | Working on real problems, you're focused on finding a solution. Learning new things, you're trying to understand how it works.
9 | It is important to have a different type of activities, which purpose is improving your skill
10 |
11 | ***An exercise** is a predefined task that you continuously implement to improve a certain skill* :muscle:
12 | ##
13 | * [Hello JPA Repository](https://github.com/bobocode-projects/spring-data-jpa-exercises/tree/master/hello-jpa-repository)
14 | * [User Service](https://github.com/bobocode-projects/spring-data-jpa-exercises/tree/master/user-service)
--------------------------------------------------------------------------------
/spring-data-jpa-exercises-model/src/main/java/com/bobocode/model/Address.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.model;
2 |
3 |
4 | import lombok.*;
5 |
6 | import javax.persistence.*;
7 | import java.time.LocalDateTime;
8 |
9 | @NoArgsConstructor
10 | @Getter
11 | @Setter
12 | @EqualsAndHashCode(of = "id")
13 | @ToString(exclude = "user")
14 | @Entity
15 | @Table(name = "address")
16 | public class Address {
17 | @Id
18 | @GeneratedValue
19 | private Long id;
20 |
21 | @Column(name = "city")
22 | private String city;
23 |
24 | @Column(name = "street")
25 | private String street;
26 |
27 | @Column(name = "street_number")
28 | private String streetNumber;
29 |
30 | @Column(name = "apartment_number")
31 | private String apartmentNumber;
32 |
33 | @Column(name = "zip_code")
34 | private String zipCode;
35 |
36 | @Column(name = "creation_date")
37 | private LocalDateTime creationDate;
38 |
39 | @OneToOne
40 | @JoinColumn(name = "user_id")
41 | private User user;
42 | }
43 |
--------------------------------------------------------------------------------
/spring-data-jpa-exercises-util/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | spring-data-jpa-exercises
7 | com.bobocode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | spring-data-jpa-exercises-util
13 |
14 |
15 |
16 | com.bobocode
17 | spring-data-jpa-exercises-model
18 | 1.0-SNAPSHOT
19 |
20 |
21 | io.codearte.jfairy
22 | jfairy
23 | 0.5.7
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/bobocode/config/JpaConfig.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.config;
2 |
3 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
4 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
5 | import org.springframework.orm.jpa.JpaVendorAdapter;
6 |
7 | import javax.sql.DataSource;
8 |
9 | /**
10 | * This class provides spring configuration for {@link javax.persistence.EntityManagerFactory} bean.
11 | *
12 | * todo: 0. PLEASE NOTE, THAT SOME REQUIRED STEPS ARE OMITTED IN THE TODO LIST AND YOU HAVE TO DO IT ON YOUR OWN
13 | *
14 | * todo: 1. Configure {@link DataSource} bean
15 | * todo: 2. Configure {@link JpaVendorAdapter} bean
16 | * todo: 3. Configure {@link javax.persistence.EntityManagerFactory} bean with name "entityManagerFactory"
17 | * todo: 4. Enable JPA repository
18 | */
19 | public class JpaConfig {
20 |
21 | public DataSource dataSource() {
22 | return new EmbeddedDatabaseBuilder()
23 | .setType(EmbeddedDatabaseType.H2)
24 | .build();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/user-service/README.MD:
--------------------------------------------------------------------------------
1 | #
User Service exercise :muscle:
2 | Improve your *Spring Data JPA* Java configuration skills
3 | ### Task
4 | The task is to **implement `UserService` using `UserRepository`**. In order to do that, you need to **provide all required
5 | configuration, implement methods, and create custom repository**. Please follow the instructions in the *todo* section.
6 |
7 | To verify your configuration, run `UserServiceAppTest.java`
8 |
9 |
10 | ### Pre-conditions :heavy_exclamation_mark:
11 | You're supposed to be familiar with *Spring IoC* and *Dependency injection*
12 |
13 | ### How to start :question:
14 | * Just clone the repository and start implementing the **todo** section, verify your changes by running tests
15 | * If you don't have enough knowledge about this domain, check out the [links below](#related-materials-information_source)
16 | * Don't worry if you got stuck, checkout the **exercise/completed** branch and see the final implementation
17 |
18 | ### Related materials :information_source:
19 | * [Spring Data JPA basics tutorial](https://github.com/bobocode-projects/spring-data-jpa-tutorial/tree/master/jpa-repository-basics)
20 |
21 |
--------------------------------------------------------------------------------
/spring-data-jpa-exercises-model/src/main/java/com/bobocode/model/Role.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.model;
2 |
3 | import lombok.Getter;
4 | import lombok.NoArgsConstructor;
5 | import lombok.Setter;
6 | import lombok.ToString;
7 |
8 | import javax.persistence.*;
9 | import java.time.LocalDateTime;
10 | import java.util.Objects;
11 |
12 | @NoArgsConstructor
13 | @Getter
14 | @Setter
15 | @ToString(exclude = "user")
16 | @Entity
17 | @Table(name = "role")
18 | public class Role {
19 | @Id
20 | @GeneratedValue
21 | private Long id;
22 |
23 | @Enumerated(EnumType.STRING)
24 | @Column(name = "role_type")
25 | private RoleType roleType;
26 |
27 | @Column(name = "creation_date")
28 | private LocalDateTime creationDate = LocalDateTime.now();
29 |
30 | @ManyToOne
31 | @JoinColumn(name = "user_id")
32 | private User user;
33 |
34 | public static Role valueOf(RoleType roleType) {
35 | return new Role(roleType);
36 | }
37 |
38 | private Role(RoleType roleType) {
39 | this.roleType = roleType;
40 | }
41 |
42 | @Override
43 | public boolean equals(Object o) {
44 | if (this == o) return true;
45 | if (!(o instanceof Role)) return false;
46 |
47 | Role role = (Role) o;
48 | return id != null && id.equals(role.id);
49 | }
50 |
51 | @Override
52 | public int hashCode() {
53 | return 31;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/hello-jpa-repository/README.MD:
--------------------------------------------------------------------------------
1 | #
Hello JpaRepository exercise :muscle:
2 | Improve your *Spring Data JPA* Java configuration skills
3 | ### Task
4 | The task is to **configure Spring Data JPA repository** for `User`. In order to do that you need to **configure
5 | `EntityManagerFactory`**, **enable transaction management** and **create a JPA repository**. Please follow
6 | the instruction in the *todo* sections.
7 |
8 | To verify your configuration, run `SpringDataJpaConfigTest.java`
9 |
10 |
11 | ### Pre-conditions :heavy_exclamation_mark:
12 | You're supposed to be familiar with *Spring IoC* and *Dependency injection*
13 |
14 | ### How to start :question:
15 | * Just clone the repository and start implementing the **todo** section, verify your changes by running tests
16 | * If you don't have enough knowledge about this domain, check out the [links below](#related-materials-information_source)
17 | * Don't worry if you got stuck, checkout the **exercise/completed** branch and see the final implementation
18 |
19 | ### Related materials :information_source:
20 | * [Spring Data JPA basics tutorial](https://github.com/bobocode-projects/spring-data-jpa-tutorial/tree/master/jpa-repository-basics)
21 |
22 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/bobocode/service/UserService.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.service;
2 |
3 | import com.bobocode.dao.UserRepository;
4 | import com.bobocode.exception.EntityNotFoundException;
5 | import com.bobocode.model.RoleType;
6 | import com.bobocode.model.User;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * This class provides service logic for {@link User}.
12 | *
13 | * todo: 0. PLEASE NOTE, THAT SOME REQUIRED STEPS ARE OMITTED IN THE TODO LIST AND YOU HAVE TO DO IT ON YOUR OWN
14 | *
15 | * todo: 1. Implement {@link UserService#findByCity(String)} using {@link UserRepository}, make method read only
16 | * todo: 2. Implement {@link UserService#getByEmail(String)} using {@link UserRepository}, make method read only
17 | * todo: 3. In case user is not found by email, throw {@link EntityNotFoundException} with message "Cannot find user by email ${email}"
18 | * todo: 4. Implement {@link UserService#addRoleToAllUsers(RoleType)} using {@link UserRepository}
19 | */
20 | public class UserService {
21 | public List findByCity(String city) {
22 | throw new UnsupportedOperationException("Do your best and implement this method!");
23 | }
24 |
25 | public User getByEmail(String email) {
26 | throw new UnsupportedOperationException("Do your best and implement this method!");
27 | }
28 |
29 | public void addRoleToAllUsers(RoleType roleType) {
30 | throw new UnsupportedOperationException("Do your best and implement this method!");
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/hello-jpa-repository/src/main/java/com/bobocode/config/JpaConfig.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.config;
2 |
3 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
4 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
5 | import org.springframework.orm.jpa.JpaVendorAdapter;
6 | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
7 |
8 | import javax.sql.DataSource;
9 |
10 | /**
11 | * This class provides spring configuration for {@link javax.persistence.EntityManagerFactory} bean.
12 | *
13 | * todo: 1. PLEASE NOTE, THAT SOME REQUIRED STEPS ARE OMITTED IN THE TODO LIST AND YOU HAVE TO DO IT ON YOUR OWN
14 | *
15 | * todo: 2. Configure {@link DataSource} bean
16 | * todo: 3. Configure {@link JpaVendorAdapter} bean
17 | * todo: 3. Configure {@link javax.persistence.EntityManagerFactory} bean with name "entityManagerFactory"
18 | * todo: 4. Enable JPA repository, set appropriate package using annotation property "basePackages"
19 | */
20 | public class JpaConfig {
21 |
22 | public DataSource dataSource() {
23 | return new EmbeddedDatabaseBuilder()
24 | .setType(EmbeddedDatabaseType.H2)
25 | .build();
26 | }
27 |
28 | public JpaVendorAdapter jpaVendorAdapter() {
29 | // todo: create HibernateJpaVendorAdapter
30 | // todo: set H2 database
31 | // todo: enable DDL generation
32 | throw new UnsupportedOperationException("Application won't start until you provide configs");
33 | }
34 |
35 | public LocalContainerEntityManagerFactoryBean localContainerEMF() {
36 | // todo: create and configure required bean
37 | // todo: set package "com.bobocode.model" to scan for JPA entities
38 | throw new UnsupportedOperationException("Application won't start until you provide configs");
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/spring-data-jpa-exercises-model/src/main/java/com/bobocode/model/User.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.model;
2 |
3 | import lombok.*;
4 |
5 | import javax.persistence.*;
6 | import java.time.LocalDate;
7 | import java.util.HashSet;
8 | import java.util.List;
9 | import java.util.Set;
10 |
11 |
12 | @NoArgsConstructor
13 | @Getter
14 | @Setter
15 | @ToString
16 | @EqualsAndHashCode(of = "id")
17 | @Entity
18 | @Table(name = "user")
19 | public class User {
20 | @Id
21 | @GeneratedValue
22 | private Long id;
23 |
24 | @Column(name = "first_name")
25 | private String firstName;
26 |
27 | @Column(name = "last_name")
28 | private String lastName;
29 |
30 | @Column(name = "email")
31 | private String email;
32 |
33 | @Column(name = "birthday")
34 | private LocalDate birthday;
35 |
36 | @Column(name = "creation_date")
37 | private LocalDate creationDate;
38 |
39 | @OneToOne(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
40 | private Address address;
41 |
42 | @Setter(AccessLevel.PRIVATE)
43 | @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
44 | private Set roles = new HashSet<>();
45 |
46 | public void setAddress(Address address) {
47 | if (address != null) {
48 | address.setUser(this);
49 | } else if (this.address != null) {
50 | this.address.setUser(null);
51 | }
52 | this.address = address;
53 | }
54 |
55 | public void addRole(Role role) {
56 | roles.add(role);
57 | role.setUser(this);
58 | }
59 |
60 | public void addRoles(List roles) {
61 | this.roles.addAll(roles);
62 | roles.forEach(role -> role.setUser(this));
63 | }
64 |
65 | public void removeRole(Role role) {
66 | this.roles.remove(role);
67 | role.setUser(null);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/spring-data-jpa-exercises-util/src/main/java/com/bobocode/util/TestDataGenerator.java:
--------------------------------------------------------------------------------
1 | package com.bobocode.util;
2 |
3 |
4 | import com.bobocode.model.Address;
5 | import com.bobocode.model.Role;
6 | import com.bobocode.model.RoleType;
7 | import com.bobocode.model.User;
8 | import io.codearte.jfairy.Fairy;
9 | import io.codearte.jfairy.producer.person.Person;
10 |
11 | import java.time.LocalDate;
12 | import java.time.LocalDateTime;
13 | import java.util.List;
14 | import java.util.Random;
15 | import java.util.function.Predicate;
16 | import java.util.stream.Stream;
17 |
18 | import static java.util.stream.Collectors.toList;
19 |
20 | public class TestDataGenerator {
21 |
22 | private List generateRoleList() {
23 | Random random = new Random();
24 | Predicate randomPredicate = i -> random.nextBoolean();
25 |
26 | return Stream.of(RoleType.values())
27 | .filter(randomPredicate)
28 | .map(Role::valueOf)
29 | .collect(toList());
30 | }
31 |
32 | public User generateUser(RoleType... roles) {
33 | User user = generateUserWithoutRoles();
34 | Stream.of(roles)
35 | .map(Role::valueOf)
36 | .forEach(user::addRole);
37 |
38 | return user;
39 | }
40 |
41 | public User generateUserWithoutRoles() {
42 | Fairy fairy = Fairy.create();
43 | Person person = fairy.person();
44 |
45 | User user = new User();
46 | user.setFirstName(person.getFirstName());
47 | user.setLastName(person.getLastName());
48 | user.setEmail(person.getEmail());
49 | user.setBirthday(LocalDate.of(
50 | person.getDateOfBirth().getYear(),
51 | person.getDateOfBirth().getMonthOfYear(),
52 | person.getDateOfBirth().getDayOfMonth()));
53 | user.setCreationDate(LocalDate.now());
54 |
55 | Address address = generateAddress();
56 | user.setAddress(address);
57 |
58 | return user;
59 | }
60 |
61 |
62 | public User generateUser() {
63 | User user = generateUserWithoutRoles();
64 | user.addRoles(generateRoleList());
65 |
66 | return user;
67 | }
68 |
69 | private Address generateAddress() {
70 | Fairy fairy = Fairy.create();
71 | Person person = fairy.person();
72 |
73 | Address address = new Address();
74 | address.setCity(person.getAddress().getCity());
75 | address.setStreet(person.getAddress().getStreet());
76 | address.setStreetNumber(person.getAddress().getStreetNumber());
77 | address.setApartmentNumber(person.getAddress().getApartmentNumber());
78 | address.setCreationDate(LocalDateTime.now());
79 | address.setZipCode(person.getAddress().getPostalCode());
80 |
81 | return address;
82 | }
83 |
84 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.bobocode
8 | spring-data-jpa-exercises
9 | 1.0-SNAPSHOT
10 |
11 | spring-data-jpa-exercises-model
12 | spring-data-jpa-exercises-util
13 | hello-jpa-repository
14 | user-service
15 |
16 |
17 | pom
18 |
19 |
20 | 11
21 | 11
22 |
23 |
24 |
25 |
26 | org.springframework.data
27 | spring-data-jpa
28 | 2.1.0.RELEASE
29 |
30 |
31 | org.springframework
32 | spring-test
33 | 5.0.7.RELEASE
34 |
35 |
36 | com.h2database
37 | h2
38 | 1.4.197
39 |
40 |
41 | org.slf4j
42 | slf4j-simple
43 | 1.7.24
44 |
45 |
46 | org.hibernate.javax.persistence
47 | hibernate-jpa-2.1-api
48 | 1.0.2.Final
49 |
50 |
51 | org.hibernate
52 | hibernate-core
53 | 5.3.2.Final
54 |
55 |
56 | org.junit.jupiter
57 | junit-jupiter-engine
58 | 5.2.0
59 | test
60 |
61 |
62 | org.junit.platform
63 | junit-platform-launcher
64 | 1.3.1
65 | test
66 |
67 |
68 | org.hamcrest
69 | hamcrest-all
70 | 1.3
71 | test
72 |
73 |
74 |
75 | org.projectlombok
76 | lombok
77 | 1.18.2
78 |
79 |
80 |
81 |
82 |
83 | javax.xml.bind
84 | jaxb-api
85 | 2.2.11
86 |
87 |
88 |
89 |
90 |
91 |
92 | org.apache.maven.plugins
93 | maven-surefire-plugin
94 | 2.22.0
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/hello-jpa-repository/src/test/java/com/bobocode/SpringDataJpaConfigTest.java:
--------------------------------------------------------------------------------
1 | package com.bobocode;
2 |
3 | import com.bobocode.config.JpaConfig;
4 | import com.bobocode.config.RootConfig;
5 | import com.bobocode.dao.UserRepository;
6 | import com.bobocode.model.User;
7 | import com.bobocode.util.TestDataGenerator;
8 | import org.junit.jupiter.api.Test;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.context.ApplicationContext;
11 | import org.springframework.context.annotation.Bean;
12 | import org.springframework.context.annotation.ComponentScan;
13 | import org.springframework.context.annotation.Configuration;
14 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
15 | import org.springframework.stereotype.Repository;
16 | import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
17 | import org.springframework.transaction.PlatformTransactionManager;
18 | import org.springframework.transaction.annotation.Transactional;
19 |
20 | import javax.persistence.EntityManagerFactory;
21 | import java.util.List;
22 | import java.util.stream.Stream;
23 |
24 | import static org.hamcrest.MatcherAssert.assertThat;
25 | import static org.hamcrest.Matchers.array;
26 | import static org.hamcrest.Matchers.equalTo;
27 | import static org.hamcrest.Matchers.is;
28 | import static org.hamcrest.Matchers.nullValue;
29 | import static org.hamcrest.core.IsNull.notNullValue;
30 |
31 | @SpringJUnitConfig(RootConfig.class)
32 | @Transactional
33 | class SpringDataJpaConfigTest {
34 | @Configuration
35 | static class TestConfig {
36 | @Bean
37 | TestDataGenerator dataGenerator() {
38 | return new TestDataGenerator();
39 | }
40 | }
41 |
42 | @Autowired
43 | private ApplicationContext applicationContext;
44 |
45 | @Autowired
46 | private UserRepository userRepository;
47 |
48 | @Autowired
49 | private TestDataGenerator dataGenerator;
50 |
51 | @Test
52 | void testTxManagerBeanName() {
53 | PlatformTransactionManager transactionManager = applicationContext.getBean(PlatformTransactionManager.class, "transactionManager");
54 |
55 | assertThat(transactionManager, notNullValue());
56 | }
57 |
58 | @Test
59 | void testUserRepositoryBeanName() {
60 | UserRepository userRepository = applicationContext.getBean(UserRepository.class, "userRepository");
61 |
62 | assertThat(userRepository, notNullValue());
63 | }
64 |
65 | @Test
66 | void testEntityManagerFactoryBeanName() {
67 | EntityManagerFactory entityManagerFactory = applicationContext.getBean(EntityManagerFactory.class, "entityManagerFactory");
68 |
69 | assertThat(entityManagerFactory, notNullValue());
70 | }
71 |
72 | @Test
73 | void testUserRepositoryIsNotMarkedAsRepository() {
74 | Repository repository = UserRepository.class.getAnnotation(Repository.class);
75 |
76 | assertThat(repository, nullValue());
77 | }
78 |
79 | @Test
80 | void testRootConfigComponentScan() {
81 | ComponentScan componentScan = RootConfig.class.getAnnotation(ComponentScan.class);
82 |
83 | String[] basePackages = componentScan.basePackages();
84 | if (basePackages.length == 0) {
85 | basePackages = componentScan.value();
86 | }
87 |
88 | assertThat(basePackages, array(equalTo("com.bobocode")));
89 | }
90 |
91 | @Test
92 | void testJpaConfigRepositoriesPackage() {
93 | EnableJpaRepositories enableJpaRepositories = JpaConfig.class.getAnnotation(EnableJpaRepositories.class);
94 |
95 | assertThat(enableJpaRepositories.basePackages(), array(equalTo("com.bobocode.dao")));
96 | }
97 |
98 | @Test
99 | void testSaveUser() {
100 | User user = dataGenerator.generateUser();
101 |
102 | userRepository.save(user);
103 |
104 | assertThat(user.getId(), notNullValue());
105 | }
106 |
107 | @Test
108 | void testFindAll() {
109 | Stream.generate(dataGenerator::generateUser).limit(10).forEach(userRepository::save);
110 |
111 | List users = userRepository.findAll();
112 |
113 | assertThat(users.size(), is(10));
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/user-service/src/test/java/com/bobocode/UserServiceAppTest.java:
--------------------------------------------------------------------------------
1 | package com.bobocode;
2 |
3 | import com.bobocode.config.JpaConfig;
4 | import com.bobocode.config.RootConfig;
5 | import com.bobocode.dao.UserRepository;
6 | import com.bobocode.exception.EntityNotFoundException;
7 | import com.bobocode.model.RoleType;
8 | import com.bobocode.model.User;
9 | import com.bobocode.service.UserService;
10 | import com.bobocode.util.TestDataGenerator;
11 | import org.junit.jupiter.api.Test;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.context.ApplicationContext;
14 | import org.springframework.context.annotation.Bean;
15 | import org.springframework.context.annotation.ComponentScan;
16 | import org.springframework.context.annotation.Configuration;
17 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
18 | import org.springframework.stereotype.Repository;
19 | import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
20 | import org.springframework.transaction.PlatformTransactionManager;
21 | import org.springframework.transaction.annotation.Transactional;
22 |
23 | import javax.persistence.EntityManager;
24 | import javax.persistence.EntityManagerFactory;
25 | import javax.persistence.Persistence;
26 | import javax.persistence.PersistenceContext;
27 | import java.util.List;
28 | import java.util.stream.Stream;
29 |
30 | import static java.util.stream.Collectors.toList;
31 | import static org.hamcrest.MatcherAssert.assertThat;
32 | import static org.hamcrest.Matchers.array;
33 | import static org.hamcrest.Matchers.equalTo;
34 | import static org.hamcrest.Matchers.everyItem;
35 | import static org.hamcrest.Matchers.greaterThan;
36 | import static org.hamcrest.Matchers.hasItem;
37 | import static org.hamcrest.Matchers.hasProperty;
38 | import static org.hamcrest.Matchers.hasSize;
39 | import static org.hamcrest.Matchers.is;
40 | import static org.hamcrest.Matchers.nullValue;
41 | import static org.hamcrest.core.IsNull.notNullValue;
42 | import static org.junit.jupiter.api.Assertions.assertTrue;
43 | import static org.junit.jupiter.api.Assertions.fail;
44 |
45 | @SpringJUnitConfig(RootConfig.class)
46 | @Transactional
47 | class UserServiceAppTest {
48 | @Configuration
49 | static class TestConfig {
50 | @Bean
51 | TestDataGenerator dataGenerator() {
52 | return new TestDataGenerator();
53 | }
54 | }
55 |
56 | @Autowired
57 | private ApplicationContext applicationContext;
58 |
59 | @Autowired
60 | private UserRepository userRepository;
61 |
62 | @Autowired
63 | private TestDataGenerator dataGenerator;
64 |
65 | @Autowired
66 | private UserService userService;
67 |
68 | @PersistenceContext
69 | private EntityManager entityManager;
70 |
71 | @Test
72 | void testTxManagerBeanName() {
73 | PlatformTransactionManager transactionManager = applicationContext.getBean(PlatformTransactionManager.class, "transactionManager");
74 |
75 | assertThat(transactionManager, notNullValue());
76 | }
77 |
78 | @Test
79 | void testUserRepositoryBeanName() {
80 | UserRepository userRepository = applicationContext.getBean(UserRepository.class, "userRepository");
81 |
82 | assertThat(userRepository, notNullValue());
83 | }
84 |
85 | @Test
86 | void testEntityManagerFactoryBeanName() {
87 | EntityManagerFactory entityManagerFactory = applicationContext.getBean(EntityManagerFactory.class, "entityManagerFactory");
88 |
89 | assertThat(entityManagerFactory, notNullValue());
90 | }
91 |
92 | @Test
93 | void testUserRepositoryIsNotMarkedAsRepository() {
94 | Repository repository = UserRepository.class.getAnnotation(Repository.class);
95 |
96 | assertThat(repository, nullValue());
97 | }
98 |
99 | @Test
100 | void testRootConfigComponentScan() {
101 | ComponentScan componentScan = RootConfig.class.getAnnotation(ComponentScan.class);
102 |
103 | String[] basePackages = componentScan.basePackages();
104 | if (basePackages.length == 0) {
105 | basePackages = componentScan.value();
106 | }
107 |
108 | assertThat(basePackages, array(equalTo("com.bobocode")));
109 | }
110 |
111 | @Test
112 | void testJpaConfigRepositoriesPackage() {
113 | EnableJpaRepositories enableJpaRepositories = JpaConfig.class.getAnnotation(EnableJpaRepositories.class);
114 |
115 | String[] basePackages = enableJpaRepositories.basePackages();
116 | if (basePackages.length == 0) {
117 | basePackages = enableJpaRepositories.value();
118 | }
119 |
120 | assertThat(basePackages, array(equalTo("com.bobocode.dao")));
121 | }
122 |
123 |
124 | @Test
125 | void testFindUsersByCity() {
126 | List userList = Stream.generate(dataGenerator::generateUser).limit(10).collect(toList());
127 | userRepository.saveAll(userList);
128 | entityManager.flush();
129 | userList.forEach(entityManager::detach);
130 |
131 | String city = userList.get(0).getAddress().getCity();
132 | List cityUsers = userService.findByCity(city);
133 |
134 | assertThat(cityUsers, hasSize(greaterThan(0)));
135 | assertThat(cityUsers, everyItem(hasProperty("address", hasProperty("city", equalTo(city)))));
136 | }
137 |
138 | @Test
139 | void testFindUsersByCityIsReadOnly() throws NoSuchMethodException {
140 | Transactional transactional = UserService.class.getMethod("findByCity", String.class)
141 | .getAnnotation(Transactional.class);
142 |
143 | assertThat(transactional.readOnly(), is(true));
144 | }
145 |
146 | @Test
147 | void testGetUserByEmail() {
148 | User generatedUser = dataGenerator.generateUser();
149 | userRepository.save(generatedUser);
150 | entityManager.flush();
151 | entityManager.detach(generatedUser);
152 |
153 | User foundUser = userService.getByEmail(generatedUser.getEmail());
154 |
155 | assertThat(foundUser, equalTo(generatedUser));
156 | }
157 |
158 | @Test
159 | void testGetUserByEmailFetchesRoles() {
160 | User generatedUser = dataGenerator.generateUser();
161 | userRepository.save(generatedUser);
162 | entityManager.flush();
163 | entityManager.detach(generatedUser);
164 |
165 | User foundUser = userService.getByEmail(generatedUser.getEmail());
166 |
167 | assertTrue(Persistence.getPersistenceUtil().isLoaded(foundUser, "roles"));
168 | }
169 |
170 | @Test
171 | void testGetUserByEmailForUserWithoutRoles() {
172 | User generatedUserWithoutRoles = dataGenerator.generateUserWithoutRoles();
173 | userRepository.save(generatedUserWithoutRoles);
174 | entityManager.flush();
175 | entityManager.detach(generatedUserWithoutRoles);
176 |
177 | User foundUser = userService.getByEmail(generatedUserWithoutRoles.getEmail());
178 |
179 | assertThat(foundUser, notNullValue());
180 | }
181 |
182 | @Test
183 | void testGetUserByEmailFetchesAddress() {
184 | User generatedUser = dataGenerator.generateUser();
185 | userRepository.save(generatedUser);
186 | entityManager.flush();
187 | entityManager.detach(generatedUser);
188 |
189 | User foundUser = userService.getByEmail(generatedUser.getEmail());
190 |
191 | assertTrue(Persistence.getPersistenceUtil().isLoaded(foundUser, "address"));
192 | }
193 |
194 | @Test
195 | void testGetUserByEmailForUserWithoutAddress() {
196 | User generatedUserWithoutAddress = dataGenerator.generateUser();
197 | generatedUserWithoutAddress.setAddress(null);
198 | userRepository.save(generatedUserWithoutAddress);
199 | entityManager.flush();
200 | entityManager.detach(generatedUserWithoutAddress);
201 |
202 | User foundUser = userService.getByEmail(generatedUserWithoutAddress.getEmail());
203 |
204 | assertThat(foundUser, notNullValue());
205 | }
206 |
207 | @Test
208 | void testGetByEmailIsReadOnly() throws NoSuchMethodException {
209 | Transactional transactional = UserService.class.getMethod("getByEmail", String.class)
210 | .getAnnotation(Transactional.class);
211 |
212 | assertThat(transactional.readOnly(), is(true));
213 | }
214 |
215 | @Test
216 | void testGetUserByNotExistingEmail() {
217 | try {
218 | User foundUser = userService.getByEmail("xxx@gmail.com");
219 | fail("Exception should be thrown");
220 | } catch (Exception e) {
221 | assertTrue(e instanceof EntityNotFoundException);
222 | assertThat(e.getMessage(), equalTo(String.format("Cannot find user by email %s", "xxx@gmail.com")));
223 | }
224 | }
225 |
226 | @Test
227 | void testAddRoleToAllUsers() {
228 | List userList = Stream.generate(dataGenerator::generateUser).limit(10).collect(toList());
229 | userRepository.saveAll(userList);
230 |
231 | userService.addRoleToAllUsers(RoleType.OPERATOR);
232 | entityManager.flush();
233 | userList.forEach(entityManager::detach);
234 |
235 | List users = userRepository.findAll();
236 |
237 | assertThat(users, everyItem(hasProperty("roles",
238 | hasItem(hasProperty("roleType", is(RoleType.OPERATOR))))));
239 | }
240 |
241 | @Test
242 | void testAddRoleToAllUsersIncludingUsersWithoutRoles() {
243 | List userList = Stream.generate(dataGenerator::generateUser).limit(10).collect(toList());
244 | User userWithoutRoles = dataGenerator.generateUserWithoutRoles();
245 | userList.add(userWithoutRoles);
246 |
247 | userRepository.saveAll(userList);
248 |
249 | userService.addRoleToAllUsers(RoleType.OPERATOR);
250 | entityManager.flush();
251 | userList.forEach(entityManager::detach);
252 |
253 | List users = userRepository.findAll();
254 |
255 | assertThat(users, everyItem(hasProperty("roles",
256 | hasItem(hasProperty("roleType", is(RoleType.OPERATOR))))));
257 | }
258 |
259 | @Test
260 | void testAddRoleToAllUsersDoesntAddDuplicates() {
261 | User user = dataGenerator.generateUser(RoleType.USER, RoleType.OPERATOR);
262 | userRepository.save(user);
263 |
264 | userService.addRoleToAllUsers(RoleType.OPERATOR);
265 |
266 | entityManager.flush();
267 | entityManager.detach(user);
268 |
269 | User foundUser = entityManager.find(User.class, user.getId());
270 |
271 | assertThat(foundUser.getRoles(), hasSize(2));
272 | }
273 |
274 |
275 | }
276 |
--------------------------------------------------------------------------------