From 45a97bb2f3e5a6cb62943c154678b5325a3e182b Mon Sep 17 00:00:00 2001 From: Serhii Date: Thu, 1 Apr 2021 17:07:44 +0300 Subject: [PATCH 1/3] GP-67 Add legacy exercise --- .../3-0-0-hello-spring-framework/README.MD | 21 ++ .../3-0-0-hello-spring-framework/pom.xml | 38 ++++ .../java/com/bobocode/config/AppConfig.java | 15 ++ .../java/com/bobocode/dao/AccountDao.java | 12 ++ .../java/com/bobocode/dao/FakeAccountDao.java | 31 +++ .../com/bobocode/service/AccountService.java | 29 +++ .../test/java/com/bobocode/AppConfigTest.java | 188 ++++++++++++++++++ 3-0-spring-framework/pom.xml | 1 + java-web-course-util/pom.xml | 6 + .../spring-framework-exercises-model/pom.xml | 23 +++ .../main/java/com/bobocode/model/Account.java | 23 +++ .../main/java/com/bobocode/model/Gender.java | 6 + .../java/com/bobocode/model/jpa/Role.java | 56 ++++++ .../java/com/bobocode/model/jpa/RoleType.java | 5 + .../java/com/bobocode/model/jpa/User.java | 56 ++++++ .../spring-framework-exercises-util/pom.xml | 27 +++ .../java/com/bobocode/TestDataGenerator.java | 81 ++++++++ 17 files changed, 618 insertions(+) create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/README.MD create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/pom.xml create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/AppConfig.java create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/AccountDao.java create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/AppConfigTest.java create mode 100644 java-web-course-util/spring-framework-exercises-model/pom.xml create mode 100644 java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/Account.java create mode 100644 java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/Gender.java create mode 100644 java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/Role.java create mode 100644 java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/RoleType.java create mode 100644 java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/User.java create mode 100644 java-web-course-util/spring-framework-exercises-util/pom.xml create mode 100644 java-web-course-util/spring-framework-exercises-util/src/main/java/com/bobocode/TestDataGenerator.java diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/README.MD b/3-0-spring-framework/3-0-0-hello-spring-framework/README.MD new file mode 100644 index 0000000..ff8f127 --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/README.MD @@ -0,0 +1,21 @@ +# Hello ApplicationContext exercise :muscle: +Improve your *Spring ApplicationContext* Java configuration skills +### Task +The task is to **configure `ApplicationContext`** that contains `AccountService` bean, `AccountDao` bean +and `TestDataGenerator` bean. Your job is to follow the instructions in the *todo* section and **implement +a proper configuration.** + +To verify your configuration, run `AppConfigTest.java` + + +### Pre-conditions :heavy_exclamation_mark: +You're supposed to be familiar with *Spring IoC* and *Dependency injection* + +### How to start :question: +* Just clone the repository and start implementing the **todo** section, verify your changes by running tests +* If you don't have enough knowledge about this domain, check out the [links below](#related-materials-information_source) +* Don't worry if you got stuck, checkout the **exercise/completed** branch and see the final implementation + +### Related materials :information_source: + * [Spring IoC basics tutorial](https://github.com/boy4uck/spring-framework-tutorial/tree/master/spring-framework-ioc-basics) + diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/pom.xml b/3-0-spring-framework/3-0-0-hello-spring-framework/pom.xml new file mode 100644 index 0000000..ac02bfe --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/pom.xml @@ -0,0 +1,38 @@ + + + + 3-0-spring-framework + com.bobocode + 1.0-SNAPSHOT + + 4.0.0 + + 3-0-0-hello-spring-framework + + + + org.springframework + spring-context + 5.0.7.RELEASE + + + org.springframework + spring-test + 5.0.7.RELEASE + + + org.hamcrest + hamcrest-all + 1.3 + test + + + com.bobocode + spring-framework-exercises-util + 1.0-SNAPSHOT + + + + \ No newline at end of file diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/AppConfig.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/AppConfig.java new file mode 100644 index 0000000..da2b1d9 --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/AppConfig.java @@ -0,0 +1,15 @@ +package com.bobocode.config; + +import com.bobocode.TestDataGenerator; + +/** + * This class application context configuration. + *

+ * todo: make this class a Spring configuration class + * todo: enable component scanning for dao and service packages + * todo: provide explicit configuration for a bean of type {@link TestDataGenerator} with name "dataGenerator" in this class. + * todo: Don't specify bean name "dataGenerator" explicitly + */ +public class AppConfig { + +} diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/AccountDao.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/AccountDao.java new file mode 100644 index 0000000..cbc888b --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/AccountDao.java @@ -0,0 +1,12 @@ +package com.bobocode.dao; + +import com.bobocode.model.Account; + +import java.util.List; + +/** + * Defines an API for {@link Account} data access object (DAO). + */ +public interface AccountDao { + List findAll(); +} diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java new file mode 100644 index 0000000..a2e6b3e --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java @@ -0,0 +1,31 @@ +package com.bobocode.dao; + +import com.bobocode.TestDataGenerator; +import com.bobocode.model.Account; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; + +/** + * Provides a fake {@link AccountDao} implementation that uses generated fake data. + *

+ * todo: configure this class as Spring component with bean name "accountDao" + * todo: use explicit (with {@link Autowired} annotation) constructor-based dependency injection + */ +public class FakeAccountDao implements AccountDao { + private List accounts; + + public FakeAccountDao(TestDataGenerator testDataGenerator) { + this.accounts = Stream.generate(testDataGenerator::generateAccount) + .limit(20) + .collect(toList()); + } + + @Override + public List findAll() { + return accounts; + } +} diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java new file mode 100644 index 0000000..1b036dd --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java @@ -0,0 +1,29 @@ +package com.bobocode.service; + +import com.bobocode.dao.AccountDao; +import com.bobocode.model.Account; + +import java.util.Comparator; +import java.util.List; + +/** + * Provides service API for {@link Account}. + *

+ * todo: configure {@link AccountService} bean implicitly using special annotation for service classes + * todo: use implicit constructor-based dependency injection (don't use {@link org.springframework.beans.factory.annotation.Autowired}) + */ +public class AccountService { + private final AccountDao accountDao; + + public AccountService(AccountDao accountDao) { + this.accountDao = accountDao; + } + + public Account findRichestAccount() { + List accounts = accountDao.findAll(); + return accounts.stream() + .max(Comparator.comparing(Account::getBalance)) + .get(); + } + +} diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/AppConfigTest.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/AppConfigTest.java new file mode 100644 index 0000000..dd54541 --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/AppConfigTest.java @@ -0,0 +1,188 @@ +package com.bobocode; + +import com.bobocode.config.AppConfig; +import com.bobocode.dao.AccountDao; +import com.bobocode.dao.FakeAccountDao; +import com.bobocode.model.Account; +import com.bobocode.service.AccountService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Comparator; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.arrayContainingInAnyOrder; +import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + + +@SpringJUnitConfig +class AppConfigTest { + @Configuration + @ComponentScan(basePackages = "com.bobocode") + static class TestConfig { + } + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private AccountService accountService; + + @Autowired + private AccountDao accountDao; + + @Test + void testConfigClassIsMarkedAsConfiguration() { + Configuration configuration = AppConfig.class.getAnnotation(Configuration.class); + + assertThat(configuration, notNullValue()); + } + + @Test + void testComponentScanIsEnabled() { + ComponentScan componentScan = AppConfig.class.getAnnotation(ComponentScan.class); + + assertThat(componentScan, notNullValue()); + } + + @Test + void testComponentScanPackagesAreSpecified() { + ComponentScan componentScan = AppConfig.class.getAnnotation(ComponentScan.class); + String[] packages = componentScan.basePackages(); + if (packages.length == 0) { + packages = componentScan.value(); + } + assertThat(packages, arrayContainingInAnyOrder("com.bobocode.dao", "com.bobocode.service")); + } + + @Test + void testDataGeneratorHasOnlyOneBean() { + Map testDataGeneratorMap = applicationContext.getBeansOfType(TestDataGenerator.class); + + assertThat(testDataGeneratorMap.size(), is(1)); + } + + @Test + void testDataGeneratorBeanIsConfiguredExplicitly() { + Method[] methods = AppConfig.class.getMethods(); + Method testDataGeneratorBeanMethod = findTestDataGeneratorBeanMethod(methods); + + + assertThat(testDataGeneratorBeanMethod, notNullValue()); + } + + @Test + void testDataGeneratorBeanName() { + Map dataGeneratorBeanMap = applicationContext.getBeansOfType(TestDataGenerator.class); + + assertThat(dataGeneratorBeanMap.keySet(), hasItem("dataGenerator")); + } + + @Test + void testDataGeneratorBeanNameIsNotSpecifiedExplicitly() { + Method[] methods = AppConfig.class.getMethods(); + Method testDataGeneratorBeanMethod = findTestDataGeneratorBeanMethod(methods); + Bean bean = testDataGeneratorBeanMethod.getDeclaredAnnotation(Bean.class); + + assertThat(bean.name(), arrayWithSize(0)); + assertThat(bean.value(), arrayWithSize(0)); + } + + private Method findTestDataGeneratorBeanMethod(Method[] methods) { + for (Method method : methods) { + if (method.getReturnType().equals(TestDataGenerator.class) + && method.getDeclaredAnnotation(Bean.class) != null) { + return method; + } + } + return null; + } + + @Test + void testFakeAccountDaoIsConfiguredAsComponent() { + Component component = FakeAccountDao.class.getAnnotation(Component.class); + + assertThat(component, notNullValue()); + } + + @Test + void testAccountDaoHasOnlyOneBean() { + Map accountDaoBeanMap = applicationContext.getBeansOfType(AccountDao.class); + + assertThat(accountDaoBeanMap.size(), is(1)); + } + + @Test + void testAccountDaoBeanName() { + Map accountDaoBeanMap = applicationContext.getBeansOfType(AccountDao.class); + + assertThat(accountDaoBeanMap.keySet(), hasItem("accountDao")); + } + + @Test + void testAccountDaoConstructorIsMarkedWithAutowired() throws NoSuchMethodException { + Autowired autowired = FakeAccountDao.class.getConstructor(TestDataGenerator.class).getAnnotation(Autowired.class); + + assertThat(autowired, notNullValue()); + } + + @Test + void testAccountServiceHasOnlyOneBean() { + Map accountServiceMap = applicationContext.getBeansOfType(AccountService.class); + + assertThat(accountServiceMap.size(), is(1)); + } + + @Test + void testAccountServiceIsConfiguredAsService() { + Service service = AccountService.class.getAnnotation(Service.class); + + assertThat(service, notNullValue()); + } + + @Test + void testAccountServiceBeanName() { + Map accountServiceMap = applicationContext.getBeansOfType(AccountService.class); + + assertThat(accountServiceMap.keySet(), hasItem("accountService")); + } + + @Test + void testAccountServiceBeanNameIsNotSpecifiedExplicitly() { + Service service = AccountService.class.getAnnotation(Service.class); + + assertThat(service.value(), equalTo("")); + } + + @Test + void testAccountServiceDoesNotUseAutowired() throws NoSuchMethodException { + Annotation[] annotations = AccountService.class.getConstructor(AccountDao.class).getDeclaredAnnotations(); + + assertThat(annotations, arrayWithSize(0)); + } + + @Test + void testFindRichestAccount() { + Account richestAccount = accountService.findRichestAccount(); + + Account actualRichestAccount = accountDao.findAll().stream().max(Comparator.comparing(Account::getBalance)).get(); + + assertThat(richestAccount, equalTo(actualRichestAccount)); + } + + +} diff --git a/3-0-spring-framework/pom.xml b/3-0-spring-framework/pom.xml index ac5d5da..00b1ab1 100644 --- a/3-0-spring-framework/pom.xml +++ b/3-0-spring-framework/pom.xml @@ -13,6 +13,7 @@ pom + 3-0-0-hello-spring-framework 3-0-1-hello-spring-mvc diff --git a/java-web-course-util/pom.xml b/java-web-course-util/pom.xml index c1baf2c..4807701 100644 --- a/java-web-course-util/pom.xml +++ b/java-web-course-util/pom.xml @@ -8,7 +8,13 @@ 1.0-SNAPSHOT 4.0.0 + pom java-web-course-util + + spring-framework-exercises-model + spring-framework-exercises-util + + \ No newline at end of file diff --git a/java-web-course-util/spring-framework-exercises-model/pom.xml b/java-web-course-util/spring-framework-exercises-model/pom.xml new file mode 100644 index 0000000..bc1e759 --- /dev/null +++ b/java-web-course-util/spring-framework-exercises-model/pom.xml @@ -0,0 +1,23 @@ + + + + java-web-course-util + com.bobocode + 1.0-SNAPSHOT + + 4.0.0 + pom + + spring-framework-exercises-model + + + + org.hibernate.javax.persistence + hibernate-jpa-2.1-api + 1.0.2.Final + + + + \ No newline at end of file diff --git a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/Account.java b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/Account.java new file mode 100644 index 0000000..1a0bb14 --- /dev/null +++ b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/Account.java @@ -0,0 +1,23 @@ +package com.bobocode.model; + +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@NoArgsConstructor +@Getter +@Setter +@ToString +@EqualsAndHashCode(of = "email") +public class Account { + private Long id; + private String firstName; + private String lastName; + private String email; + private LocalDate birthday; + private Gender gender; + private LocalDateTime creationTime; + private BigDecimal balance = BigDecimal.ZERO; +} diff --git a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/Gender.java b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/Gender.java new file mode 100644 index 0000000..8a5b149 --- /dev/null +++ b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/Gender.java @@ -0,0 +1,6 @@ +package com.bobocode.model; + +public enum Gender { + MALE, + FEMALE +} diff --git a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/Role.java b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/Role.java new file mode 100644 index 0000000..ad2925f --- /dev/null +++ b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/Role.java @@ -0,0 +1,56 @@ +package com.bobocode.model.jpa; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.*; +import java.time.LocalDateTime; +import java.util.Objects; + +@NoArgsConstructor +@Getter +@Setter +@ToString(exclude = "user") +@Entity +@Table(name = "role") +public class Role { + @Id + @GeneratedValue + private Long id; + + @Enumerated(EnumType.STRING) + @Column(name = "role_type") + private RoleType roleType; + + @Column(name = "creation_date") + private LocalDateTime creationDate = LocalDateTime.now(); + + @ManyToOne + @JoinColumn(name = "user_id") + private User user; + + public static Role valueOf(RoleType roleType) { + return new Role(roleType); + } + + private Role(RoleType roleType) { + this.roleType = roleType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Role)) return false; + + Role role = (Role) o; + + return Objects.equals(id, role.id); + } + + @Override + public int hashCode() { + return 31; + } +} diff --git a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/RoleType.java b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/RoleType.java new file mode 100644 index 0000000..b59a327 --- /dev/null +++ b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/RoleType.java @@ -0,0 +1,5 @@ +package com.bobocode.model.jpa; + +public enum RoleType { + USER, ADMIN, OPERATOR, CUSTOMER +} diff --git a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/User.java b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/User.java new file mode 100644 index 0000000..75f1412 --- /dev/null +++ b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/User.java @@ -0,0 +1,56 @@ +package com.bobocode.model.jpa; + +import lombok.*; + +import javax.persistence.*; +import java.time.LocalDate; +import java.util.HashSet; +import java.util.Set; + + +@NoArgsConstructor +@Getter +@Setter +@ToString +@EqualsAndHashCode(of = "email") +@Entity +@Table(name = "user") +public class User { + @Id + @GeneratedValue + private Long id; + + @Column(name = "first_name") + private String firstName; + + @Column(name = "last_name") + private String lastName; + + @Column(name = "email") + private String email; + + @Column(name = "birthday") + private LocalDate birthday; + + @Column(name = "creation_date") + private LocalDate creationDate; + + @Setter(AccessLevel.PRIVATE) + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private Set roles = new HashSet<>(); + + public void addRole(Role role) { + roles.add(role); + role.setUser(this); + } + + public void addRoles(Set roles) { + this.roles.addAll(roles); + roles.forEach(role -> role.setUser(this)); + } + + public void removeRole(Role role) { + this.roles.remove(role); + role.setUser(null); + } +} diff --git a/java-web-course-util/spring-framework-exercises-util/pom.xml b/java-web-course-util/spring-framework-exercises-util/pom.xml new file mode 100644 index 0000000..cb4288a --- /dev/null +++ b/java-web-course-util/spring-framework-exercises-util/pom.xml @@ -0,0 +1,27 @@ + + + + java-web-course-util + com.bobocode + 1.0-SNAPSHOT + + 4.0.0 + pom + + spring-framework-exercises-util + + + + com.bobocode + spring-framework-exercises-model + 1.0-SNAPSHOT + + + io.codearte.jfairy + jfairy + 0.5.7 + + + \ No newline at end of file diff --git a/java-web-course-util/spring-framework-exercises-util/src/main/java/com/bobocode/TestDataGenerator.java b/java-web-course-util/spring-framework-exercises-util/src/main/java/com/bobocode/TestDataGenerator.java new file mode 100644 index 0000000..60b464e --- /dev/null +++ b/java-web-course-util/spring-framework-exercises-util/src/main/java/com/bobocode/TestDataGenerator.java @@ -0,0 +1,81 @@ +package com.bobocode; + +import com.bobocode.model.Account; +import com.bobocode.model.Gender; +import com.bobocode.model.jpa.Role; +import com.bobocode.model.jpa.RoleType; +import com.bobocode.model.jpa.User; +import io.codearte.jfairy.Fairy; +import io.codearte.jfairy.producer.person.Person; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Random; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toSet; + +public class TestDataGenerator { + public Account generateAccount(){ + Fairy fairy = Fairy.create(); + Person person = fairy.person(); + Random random = new Random(); + + Account fakeAccount = new Account(); + fakeAccount.setFirstName(person.getFirstName()); + fakeAccount.setLastName(person.getLastName()); + fakeAccount.setEmail(person.getEmail()); + fakeAccount.setBirthday(LocalDate.of( + person.getDateOfBirth().getYear(), + person.getDateOfBirth().getMonthOfYear(), + person.getDateOfBirth().getDayOfMonth())); + fakeAccount.setGender(Gender.valueOf(person.getSex().name())); + fakeAccount.setBalance(BigDecimal.valueOf(random.nextInt(200_000))); + fakeAccount.setCreationTime(LocalDateTime.now()); + + return fakeAccount; + } + + public User generateUser() { + User user = generateUserOnly(); + user.addRoles(generateRoleSet()); + return user; + } + + public User generateUser(RoleType... roleTypes) { + Set roles = Stream.of(roleTypes).map(Role::valueOf).collect(Collectors.toSet()); + User user = generateUserOnly(); + user.addRoles(roles); + return user; + } + + private User generateUserOnly() { + Fairy fairy = Fairy.create(); + Person person = fairy.person(); + + User user = new User(); + user.setFirstName(person.getFirstName()); + user.setLastName(person.getLastName()); + user.setEmail(person.getEmail()); + user.setBirthday(LocalDate.of( + person.getDateOfBirth().getYear(), + person.getDateOfBirth().getMonthOfYear(), + person.getDateOfBirth().getDayOfMonth())); + user.setCreationDate(LocalDate.now()); + return user; + } + + public static Set generateRoleSet() { + Random random = new Random(); + Predicate randomPredicate = i -> random.nextBoolean(); + + return Stream.of(RoleType.values()) + .filter(randomPredicate) + .map(Role::valueOf) + .collect(toSet()); + } +} From 124ec60734c9977cabe9c8a617c6494700d2b885 Mon Sep 17 00:00:00 2001 From: Serhii Date: Mon, 5 Apr 2021 12:23:12 +0300 Subject: [PATCH 2/3] GP-67 Update tests --- .../3-0-0-hello-spring-framework/pom.xml | 17 +- .../java/com/bobocode/config/AppConfig.java | 15 -- .../bobocode/config/ApplicationConfig.java | 27 +++ .../java/com/bobocode/dao/FakeAccountDao.java | 7 +- .../com/bobocode/service/AccountService.java | 5 +- .../test/java/com/bobocode/AppConfigTest.java | 188 ------------------ .../com/bobocode/ApplicationConfigTest.java | 120 +++++++++++ .../com/bobocode/ApplicationContextTest.java | 112 +++++++++++ .../spring-framework-exercises-model/pom.xml | 1 - .../spring-framework-exercises-util/pom.xml | 2 +- 10 files changed, 283 insertions(+), 211 deletions(-) delete mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/AppConfig.java create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java delete mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/AppConfigTest.java create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationConfigTest.java create mode 100644 3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/pom.xml b/3-0-spring-framework/3-0-0-hello-spring-framework/pom.xml index ac02bfe..0dd36ae 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/pom.xml +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/pom.xml @@ -15,12 +15,17 @@ org.springframework spring-context - 5.0.7.RELEASE + 5.2.12.RELEASE org.springframework spring-test - 5.0.7.RELEASE + 5.2.12.RELEASE + + + com.bobocode + spring-framework-exercises-util + 1.0-SNAPSHOT org.hamcrest @@ -28,10 +33,16 @@ 1.3 test + + org.slf4j + slf4j-simple + 1.7.24 + com.bobocode - spring-framework-exercises-util + spring-framework-exercises-model 1.0-SNAPSHOT + compile diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/AppConfig.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/AppConfig.java deleted file mode 100644 index da2b1d9..0000000 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/AppConfig.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.bobocode.config; - -import com.bobocode.TestDataGenerator; - -/** - * This class application context configuration. - *

- * todo: make this class a Spring configuration class - * todo: enable component scanning for dao and service packages - * todo: provide explicit configuration for a bean of type {@link TestDataGenerator} with name "dataGenerator" in this class. - * todo: Don't specify bean name "dataGenerator" explicitly - */ -public class AppConfig { - -} diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java new file mode 100644 index 0000000..52a92d3 --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java @@ -0,0 +1,27 @@ +package com.bobocode.config; + +import com.bobocode.TestDataGenerator; +import org.springframework.context.annotation.*; +import org.springframework.stereotype.Component; + +/** + * This class specify application context configuration. Basically, it's all about which instances of which classes + * should be created and registered in the context. An instance that is registered in the context is called 'bean'. + * + * To tell the container, which bean should be created, you could either specify packages to scan using @{@link ComponentScan}, + * or declare your own beans using @{@link Bean}. When you use @{@link ComponentScan} the container will discover + * specified package and its sub-folders, to find all classes marked @{@link Component}. + * + * If you want to import other configs from Java class or XML file, you could use @{@link Import} + * and @{@link ImportResource} accordingly + *

+ * todo 1: make this class a Spring configuration class + * todo 2: enable component scanning for dao and service packages + * todo 3: provide explicit configuration for a bean of type {@link TestDataGenerator} with name "dataGenerator" in this class. + * hint: use method creation approach with @Bean annotation; + * todo 4: Don't specify bean name "dataGenerator" explicitly + */ + +public class ApplicationConfig { + +} diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java index a2e6b3e..9543845 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java @@ -3,6 +3,7 @@ import com.bobocode.TestDataGenerator; import com.bobocode.model.Account; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import java.util.List; import java.util.stream.Stream; @@ -10,11 +11,13 @@ import static java.util.stream.Collectors.toList; /** - * Provides a fake {@link AccountDao} implementation that uses generated fake data. + * This class should be marked with @{@link Component}, thus Spring container will create an instance + * of {@link FakeAccountDao} class, and will register it the context. *

* todo: configure this class as Spring component with bean name "accountDao" - * todo: use explicit (with {@link Autowired} annotation) constructor-based dependency injection + * todo: use explicit (with {@link Autowired} annotation) constructor-based dependency injection for specific bean */ + public class FakeAccountDao implements AccountDao { private List accounts; diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java index 1b036dd..3fa68b6 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java @@ -2,6 +2,9 @@ import com.bobocode.dao.AccountDao; import com.bobocode.model.Account; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import java.util.Comparator; import java.util.List; @@ -12,6 +15,7 @@ * todo: configure {@link AccountService} bean implicitly using special annotation for service classes * todo: use implicit constructor-based dependency injection (don't use {@link org.springframework.beans.factory.annotation.Autowired}) */ + public class AccountService { private final AccountDao accountDao; @@ -25,5 +29,4 @@ public Account findRichestAccount() { .max(Comparator.comparing(Account::getBalance)) .get(); } - } diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/AppConfigTest.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/AppConfigTest.java deleted file mode 100644 index dd54541..0000000 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/AppConfigTest.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.bobocode; - -import com.bobocode.config.AppConfig; -import com.bobocode.dao.AccountDao; -import com.bobocode.dao.FakeAccountDao; -import com.bobocode.model.Account; -import com.bobocode.service.AccountService; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Comparator; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.arrayContainingInAnyOrder; -import static org.hamcrest.Matchers.arrayWithSize; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; - - -@SpringJUnitConfig -class AppConfigTest { - @Configuration - @ComponentScan(basePackages = "com.bobocode") - static class TestConfig { - } - - @Autowired - private ApplicationContext applicationContext; - - @Autowired - private AccountService accountService; - - @Autowired - private AccountDao accountDao; - - @Test - void testConfigClassIsMarkedAsConfiguration() { - Configuration configuration = AppConfig.class.getAnnotation(Configuration.class); - - assertThat(configuration, notNullValue()); - } - - @Test - void testComponentScanIsEnabled() { - ComponentScan componentScan = AppConfig.class.getAnnotation(ComponentScan.class); - - assertThat(componentScan, notNullValue()); - } - - @Test - void testComponentScanPackagesAreSpecified() { - ComponentScan componentScan = AppConfig.class.getAnnotation(ComponentScan.class); - String[] packages = componentScan.basePackages(); - if (packages.length == 0) { - packages = componentScan.value(); - } - assertThat(packages, arrayContainingInAnyOrder("com.bobocode.dao", "com.bobocode.service")); - } - - @Test - void testDataGeneratorHasOnlyOneBean() { - Map testDataGeneratorMap = applicationContext.getBeansOfType(TestDataGenerator.class); - - assertThat(testDataGeneratorMap.size(), is(1)); - } - - @Test - void testDataGeneratorBeanIsConfiguredExplicitly() { - Method[] methods = AppConfig.class.getMethods(); - Method testDataGeneratorBeanMethod = findTestDataGeneratorBeanMethod(methods); - - - assertThat(testDataGeneratorBeanMethod, notNullValue()); - } - - @Test - void testDataGeneratorBeanName() { - Map dataGeneratorBeanMap = applicationContext.getBeansOfType(TestDataGenerator.class); - - assertThat(dataGeneratorBeanMap.keySet(), hasItem("dataGenerator")); - } - - @Test - void testDataGeneratorBeanNameIsNotSpecifiedExplicitly() { - Method[] methods = AppConfig.class.getMethods(); - Method testDataGeneratorBeanMethod = findTestDataGeneratorBeanMethod(methods); - Bean bean = testDataGeneratorBeanMethod.getDeclaredAnnotation(Bean.class); - - assertThat(bean.name(), arrayWithSize(0)); - assertThat(bean.value(), arrayWithSize(0)); - } - - private Method findTestDataGeneratorBeanMethod(Method[] methods) { - for (Method method : methods) { - if (method.getReturnType().equals(TestDataGenerator.class) - && method.getDeclaredAnnotation(Bean.class) != null) { - return method; - } - } - return null; - } - - @Test - void testFakeAccountDaoIsConfiguredAsComponent() { - Component component = FakeAccountDao.class.getAnnotation(Component.class); - - assertThat(component, notNullValue()); - } - - @Test - void testAccountDaoHasOnlyOneBean() { - Map accountDaoBeanMap = applicationContext.getBeansOfType(AccountDao.class); - - assertThat(accountDaoBeanMap.size(), is(1)); - } - - @Test - void testAccountDaoBeanName() { - Map accountDaoBeanMap = applicationContext.getBeansOfType(AccountDao.class); - - assertThat(accountDaoBeanMap.keySet(), hasItem("accountDao")); - } - - @Test - void testAccountDaoConstructorIsMarkedWithAutowired() throws NoSuchMethodException { - Autowired autowired = FakeAccountDao.class.getConstructor(TestDataGenerator.class).getAnnotation(Autowired.class); - - assertThat(autowired, notNullValue()); - } - - @Test - void testAccountServiceHasOnlyOneBean() { - Map accountServiceMap = applicationContext.getBeansOfType(AccountService.class); - - assertThat(accountServiceMap.size(), is(1)); - } - - @Test - void testAccountServiceIsConfiguredAsService() { - Service service = AccountService.class.getAnnotation(Service.class); - - assertThat(service, notNullValue()); - } - - @Test - void testAccountServiceBeanName() { - Map accountServiceMap = applicationContext.getBeansOfType(AccountService.class); - - assertThat(accountServiceMap.keySet(), hasItem("accountService")); - } - - @Test - void testAccountServiceBeanNameIsNotSpecifiedExplicitly() { - Service service = AccountService.class.getAnnotation(Service.class); - - assertThat(service.value(), equalTo("")); - } - - @Test - void testAccountServiceDoesNotUseAutowired() throws NoSuchMethodException { - Annotation[] annotations = AccountService.class.getConstructor(AccountDao.class).getDeclaredAnnotations(); - - assertThat(annotations, arrayWithSize(0)); - } - - @Test - void testFindRichestAccount() { - Account richestAccount = accountService.findRichestAccount(); - - Account actualRichestAccount = accountDao.findAll().stream().max(Comparator.comparing(Account::getBalance)).get(); - - assertThat(richestAccount, equalTo(actualRichestAccount)); - } - - -} diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationConfigTest.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationConfigTest.java new file mode 100644 index 0000000..2d2496c --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationConfigTest.java @@ -0,0 +1,120 @@ +package com.bobocode; + +import com.bobocode.config.ApplicationConfig; +import com.bobocode.dao.AccountDao; +import com.bobocode.dao.FakeAccountDao; +import com.bobocode.service.AccountService; +import org.junit.jupiter.api.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class ApplicationConfigTest { + + @Test + @Order(1) + @DisplayName("Config class is marked as @Configuration") + void configClassIsMarkedAsConfiguration() { + Configuration configuration = ApplicationConfig.class.getAnnotation(Configuration.class); + + assertNotNull(configuration); + } + + @Test + @Order(2) + @DisplayName("@ComponentScan is enabled") + void componentScanIsEnabled() { + ComponentScan componentScan = ApplicationConfig.class.getAnnotation(ComponentScan.class); + + assertNotNull(componentScan); + } + + @Test + @Order(3) + @DisplayName("@ComponentScan packages are specified") + void componentScanPackagesAreSpecified() { + ComponentScan componentScan = ApplicationConfig.class.getAnnotation(ComponentScan.class); + String[] packages = componentScan.basePackages(); + if (packages.length == 0) { + packages = componentScan.value(); + } + assertThat(packages).containsExactlyInAnyOrder("com.bobocode.dao", "com.bobocode.service"); + } + + @Test + @Order(4) + @DisplayName("DataGenerator bean is configured in method marked with @Bean") + void dataGeneratorBeanIsConfiguredExplicitly() { + Method[] methods = ApplicationConfig.class.getMethods(); + Method testDataGeneratorBeanMethod = findTestDataGeneratorBeanMethod(methods); + + assertNotNull(testDataGeneratorBeanMethod); + } + + @Test + @Order(5) + @DisplayName("DataGenerator bean name is not specified explicitly") + void dataGeneratorBeanNameIsNotSpecifiedExplicitly() { + Method[] methods = ApplicationConfig.class.getMethods(); + Method testDataGeneratorBeanMethod = findTestDataGeneratorBeanMethod(methods); + Bean bean = testDataGeneratorBeanMethod.getDeclaredAnnotation(Bean.class); + + assertThat(bean.name().length).isEqualTo(0); + assertThat(bean.value().length).isEqualTo(0); + } + + @Test + @Order(6) + @DisplayName("FakeAccountDao is configured as @Component") + void fakeAccountDaoIsConfiguredAsComponent() { + Component component = FakeAccountDao.class.getAnnotation(Component.class); + + assertNotNull(component); + } + + @Test + @Order(7) + @DisplayName("AccountService is configured as @Service") + void accountServiceIsConfiguredAsService() { + Service service = AccountService.class.getAnnotation(Service.class); + + assertNotNull(service); + } + + @Test + @Order(8) + @DisplayName("AccountService bean name is not specified explicitly") + void accountServiceBeanNameIsNotSpecifiedExplicitly() { + Service service = AccountService.class.getAnnotation(Service.class); + + assertThat(service.value()).isEqualTo(""); + } + + @Test + @Order(9) + @DisplayName("AccountService doesn't use @Autowired") + void accountServiceDoesNotUseAutowired() throws NoSuchMethodException { + Annotation[] annotations = AccountService.class.getConstructor(AccountDao.class).getDeclaredAnnotations(); + + assertThat(annotations.length).isEqualTo(0); + } + + private Method findTestDataGeneratorBeanMethod(Method[] methods) { + for (Method method : methods) { + if (method.getReturnType().equals(TestDataGenerator.class) + && method.getDeclaredAnnotation(Bean.class) != null) { + return method; + } + } + return null; + } +} diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java new file mode 100644 index 0000000..07ae95c --- /dev/null +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java @@ -0,0 +1,112 @@ + package com.bobocode; + +import com.bobocode.dao.AccountDao; +import com.bobocode.dao.FakeAccountDao; +import com.bobocode.model.Account; +import com.bobocode.service.AccountService; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import java.util.Comparator; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@SpringJUnitConfig +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +class ApplicationContextTest { + @Configuration + @ComponentScan(basePackages = "com.bobocode") + static class TestConfig { + } + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private AccountService accountService; + + @Autowired + private AccountDao accountDao; + + @Test + @Order(1) + @DisplayName("DataGenerator has only one bean") + void dataGeneratorHasOnlyOneBean() { + Map testDataGeneratorMap = applicationContext.getBeansOfType(TestDataGenerator.class); + + assertThat(testDataGeneratorMap.size()).isEqualTo(1); + } + + @Test + @Order(2) + @DisplayName("DataGenerator bean has proper name") + void testDataGeneratorBeanName() { + Map dataGeneratorBeanMap = applicationContext.getBeansOfType(TestDataGenerator.class); + + assertThat(dataGeneratorBeanMap.keySet()).contains("dataGenerator"); + } + + @Test + @Order(3) + @DisplayName("AccountDao has only one bean") + void accountDaoHasOnlyOneBean() { + Map accountDaoBeanMap = applicationContext.getBeansOfType(AccountDao.class); + + assertThat(accountDaoBeanMap.size()).isEqualTo(1); + } + + @Test + @Order(4) + @DisplayName("AccountDao bean has proper name") + void accountDaoBeanName() { + Map accountDaoBeanMap = applicationContext.getBeansOfType(AccountDao.class); + + assertThat(accountDaoBeanMap.keySet()).contains("accountDao"); + } + + @Test + @Order(5) + @DisplayName("AccountDao constructor is marked with @Autowired") + void accountDaoConstructorIsMarkedWithAutowired() throws NoSuchMethodException { + Autowired autowired = FakeAccountDao.class.getConstructor(TestDataGenerator.class).getAnnotation(Autowired.class); + + assertNotNull(autowired); + } + + @Test + @Order(6) + @DisplayName("AccountService has only one bean") + void accountServiceHasOnlyOneBean() { + Map accountServiceMap = applicationContext.getBeansOfType(AccountService.class); + + assertThat(accountServiceMap.size()).isEqualTo(1); + } + + @Test + @Order(7) + @DisplayName("AccountService has proper name") + void accountServiceBeanName() { + Map accountServiceMap = applicationContext.getBeansOfType(AccountService.class); + + assertThat(accountServiceMap.keySet()).contains("accountService"); + } + + @Test + @Order(8) + @DisplayName("Find the richest account") + void findRichestAccount() { + Account richestAccount = accountService.findRichestAccount(); + + Account actualRichestAccount = accountDao.findAll().stream() + .max(Comparator.comparing(Account::getBalance)) + .orElseThrow(); + + assertThat(richestAccount).isEqualTo(actualRichestAccount); + } +} diff --git a/java-web-course-util/spring-framework-exercises-model/pom.xml b/java-web-course-util/spring-framework-exercises-model/pom.xml index bc1e759..070570d 100644 --- a/java-web-course-util/spring-framework-exercises-model/pom.xml +++ b/java-web-course-util/spring-framework-exercises-model/pom.xml @@ -8,7 +8,6 @@ 1.0-SNAPSHOT 4.0.0 - pom spring-framework-exercises-model diff --git a/java-web-course-util/spring-framework-exercises-util/pom.xml b/java-web-course-util/spring-framework-exercises-util/pom.xml index cb4288a..ee655e5 100644 --- a/java-web-course-util/spring-framework-exercises-util/pom.xml +++ b/java-web-course-util/spring-framework-exercises-util/pom.xml @@ -8,10 +8,10 @@ 1.0-SNAPSHOT 4.0.0 - pom spring-framework-exercises-util + com.bobocode From ecb63ee9c6730b183514707444b13ce965319c43 Mon Sep 17 00:00:00 2001 From: Serhii Date: Sat, 10 Apr 2021 12:19:25 +0300 Subject: [PATCH 3/3] GP-82 review updates --- .../bobocode/config/ApplicationConfig.java | 11 ++-- .../com/bobocode/service/AccountService.java | 3 - .../com/bobocode/ApplicationConfigTest.java | 2 +- .../com/bobocode/ApplicationContextTest.java | 17 +----- .../spring-framework-exercises-model/pom.xml | 8 --- .../java/com/bobocode/model/jpa/Role.java | 56 ------------------- .../java/com/bobocode/model/jpa/RoleType.java | 5 -- .../java/com/bobocode/model/jpa/User.java | 56 ------------------- .../java/com/bobocode/TestDataGenerator.java | 50 +---------------- 9 files changed, 10 insertions(+), 198 deletions(-) delete mode 100644 java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/Role.java delete mode 100644 java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/RoleType.java delete mode 100644 java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/User.java diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java index 52a92d3..91df5b3 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java @@ -1,24 +1,27 @@ package com.bobocode.config; import com.bobocode.TestDataGenerator; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.ImportResource; import org.springframework.stereotype.Component; /** * This class specify application context configuration. Basically, it's all about which instances of which classes * should be created and registered in the context. An instance that is registered in the context is called 'bean'. - * + *

* To tell the container, which bean should be created, you could either specify packages to scan using @{@link ComponentScan}, * or declare your own beans using @{@link Bean}. When you use @{@link ComponentScan} the container will discover * specified package and its sub-folders, to find all classes marked @{@link Component}. - * + *

* If you want to import other configs from Java class or XML file, you could use @{@link Import} * and @{@link ImportResource} accordingly *

* todo 1: make this class a Spring configuration class * todo 2: enable component scanning for dao and service packages * todo 3: provide explicit configuration for a bean of type {@link TestDataGenerator} with name "dataGenerator" in this class. - * hint: use method creation approach with @Bean annotation; + * hint: use method creation approach with @Bean annotation; * todo 4: Don't specify bean name "dataGenerator" explicitly */ diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java index 3fa68b6..3bc0b66 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java @@ -2,9 +2,6 @@ import com.bobocode.dao.AccountDao; import com.bobocode.model.Account; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; import java.util.Comparator; import java.util.List; diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationConfigTest.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationConfigTest.java index 2d2496c..2c7a211 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationConfigTest.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationConfigTest.java @@ -40,7 +40,7 @@ void componentScanIsEnabled() { @Test @Order(3) - @DisplayName("@ComponentScan packages are specified") + @DisplayName("@ComponentScan configured for \"dao\" and \"service\" packages") void componentScanPackagesAreSpecified() { ComponentScan componentScan = ApplicationConfig.class.getAnnotation(ComponentScan.class); String[] packages = componentScan.basePackages(); diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java index 07ae95c..6955a14 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java @@ -1,8 +1,7 @@ - package com.bobocode; +package com.bobocode; import com.bobocode.dao.AccountDao; import com.bobocode.dao.FakeAccountDao; -import com.bobocode.model.Account; import com.bobocode.service.AccountService; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; @@ -11,7 +10,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; -import java.util.Comparator; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; @@ -96,17 +94,4 @@ void accountServiceBeanName() { assertThat(accountServiceMap.keySet()).contains("accountService"); } - - @Test - @Order(8) - @DisplayName("Find the richest account") - void findRichestAccount() { - Account richestAccount = accountService.findRichestAccount(); - - Account actualRichestAccount = accountDao.findAll().stream() - .max(Comparator.comparing(Account::getBalance)) - .orElseThrow(); - - assertThat(richestAccount).isEqualTo(actualRichestAccount); - } } diff --git a/java-web-course-util/spring-framework-exercises-model/pom.xml b/java-web-course-util/spring-framework-exercises-model/pom.xml index 070570d..9edb14f 100644 --- a/java-web-course-util/spring-framework-exercises-model/pom.xml +++ b/java-web-course-util/spring-framework-exercises-model/pom.xml @@ -11,12 +11,4 @@ spring-framework-exercises-model - - - org.hibernate.javax.persistence - hibernate-jpa-2.1-api - 1.0.2.Final - - - \ No newline at end of file diff --git a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/Role.java b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/Role.java deleted file mode 100644 index ad2925f..0000000 --- a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/Role.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.bobocode.model.jpa; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; - -import javax.persistence.*; -import java.time.LocalDateTime; -import java.util.Objects; - -@NoArgsConstructor -@Getter -@Setter -@ToString(exclude = "user") -@Entity -@Table(name = "role") -public class Role { - @Id - @GeneratedValue - private Long id; - - @Enumerated(EnumType.STRING) - @Column(name = "role_type") - private RoleType roleType; - - @Column(name = "creation_date") - private LocalDateTime creationDate = LocalDateTime.now(); - - @ManyToOne - @JoinColumn(name = "user_id") - private User user; - - public static Role valueOf(RoleType roleType) { - return new Role(roleType); - } - - private Role(RoleType roleType) { - this.roleType = roleType; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Role)) return false; - - Role role = (Role) o; - - return Objects.equals(id, role.id); - } - - @Override - public int hashCode() { - return 31; - } -} diff --git a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/RoleType.java b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/RoleType.java deleted file mode 100644 index b59a327..0000000 --- a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/RoleType.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.bobocode.model.jpa; - -public enum RoleType { - USER, ADMIN, OPERATOR, CUSTOMER -} diff --git a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/User.java b/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/User.java deleted file mode 100644 index 75f1412..0000000 --- a/java-web-course-util/spring-framework-exercises-model/src/main/java/com/bobocode/model/jpa/User.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.bobocode.model.jpa; - -import lombok.*; - -import javax.persistence.*; -import java.time.LocalDate; -import java.util.HashSet; -import java.util.Set; - - -@NoArgsConstructor -@Getter -@Setter -@ToString -@EqualsAndHashCode(of = "email") -@Entity -@Table(name = "user") -public class User { - @Id - @GeneratedValue - private Long id; - - @Column(name = "first_name") - private String firstName; - - @Column(name = "last_name") - private String lastName; - - @Column(name = "email") - private String email; - - @Column(name = "birthday") - private LocalDate birthday; - - @Column(name = "creation_date") - private LocalDate creationDate; - - @Setter(AccessLevel.PRIVATE) - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - private Set roles = new HashSet<>(); - - public void addRole(Role role) { - roles.add(role); - role.setUser(this); - } - - public void addRoles(Set roles) { - this.roles.addAll(roles); - roles.forEach(role -> role.setUser(this)); - } - - public void removeRole(Role role) { - this.roles.remove(role); - role.setUser(null); - } -} diff --git a/java-web-course-util/spring-framework-exercises-util/src/main/java/com/bobocode/TestDataGenerator.java b/java-web-course-util/spring-framework-exercises-util/src/main/java/com/bobocode/TestDataGenerator.java index 60b464e..50cea04 100644 --- a/java-web-course-util/spring-framework-exercises-util/src/main/java/com/bobocode/TestDataGenerator.java +++ b/java-web-course-util/spring-framework-exercises-util/src/main/java/com/bobocode/TestDataGenerator.java @@ -2,9 +2,6 @@ import com.bobocode.model.Account; import com.bobocode.model.Gender; -import com.bobocode.model.jpa.Role; -import com.bobocode.model.jpa.RoleType; -import com.bobocode.model.jpa.User; import io.codearte.jfairy.Fairy; import io.codearte.jfairy.producer.person.Person; @@ -12,15 +9,9 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Random; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static java.util.stream.Collectors.toSet; public class TestDataGenerator { - public Account generateAccount(){ + public Account generateAccount() { Fairy fairy = Fairy.create(); Person person = fairy.person(); Random random = new Random(); @@ -39,43 +30,4 @@ public Account generateAccount(){ return fakeAccount; } - - public User generateUser() { - User user = generateUserOnly(); - user.addRoles(generateRoleSet()); - return user; - } - - public User generateUser(RoleType... roleTypes) { - Set roles = Stream.of(roleTypes).map(Role::valueOf).collect(Collectors.toSet()); - User user = generateUserOnly(); - user.addRoles(roles); - return user; - } - - private User generateUserOnly() { - Fairy fairy = Fairy.create(); - Person person = fairy.person(); - - User user = new User(); - user.setFirstName(person.getFirstName()); - user.setLastName(person.getLastName()); - user.setEmail(person.getEmail()); - user.setBirthday(LocalDate.of( - person.getDateOfBirth().getYear(), - person.getDateOfBirth().getMonthOfYear(), - person.getDateOfBirth().getDayOfMonth())); - user.setCreationDate(LocalDate.now()); - return user; - } - - public static Set generateRoleSet() { - Random random = new Random(); - Predicate randomPredicate = i -> random.nextBoolean(); - - return Stream.of(RoleType.values()) - .filter(randomPredicate) - .map(Role::valueOf) - .collect(toSet()); - } }