Skip to content

Commit f2dfcd5

Browse files
committed
GP-67 update exercise while preparing overview
* change the order of the tests * update javadocs * simplify impl * add todo
1 parent d962943 commit f2dfcd5

File tree

7 files changed

+66
-83
lines changed

7 files changed

+66
-83
lines changed
Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,16 @@
11
package com.bobocode.config;
22

33
import com.bobocode.TestDataGenerator;
4-
import org.springframework.context.annotation.Bean;
5-
import org.springframework.context.annotation.ComponentScan;
6-
import org.springframework.context.annotation.Import;
7-
import org.springframework.context.annotation.ImportResource;
8-
import org.springframework.stereotype.Component;
94

105
/**
11-
* This class specify application context configuration. Basically, it's all about which instances of which classes
12-
* should be created and registered in the context. An instance that is registered in the context is called 'bean'.
6+
* This class specifies application context configuration. It tells Spring to scan "dao" and "service" packages in order
7+
* to find and create instances for {@link com.bobocode.dao.FakeAccountDao} and
8+
* {@link com.bobocode.service.AccountService}.
139
* <p>
14-
* To tell the container, which bean should be created, you could either specify packages to scan using @{@link ComponentScan},
15-
* or declare your own beans using @{@link Bean}. When you use @{@link ComponentScan} the container will discover
16-
* specified package and its sub-folders, to find all classes marked @{@link Component}.
17-
* <p>
18-
* If you want to import other configs from Java class or XML file, you could use @{@link Import}
19-
* and @{@link ImportResource} accordingly
20-
* <p>
21-
* todo 1: make this class a Spring configuration class
22-
* todo 2: enable component scanning for dao and service packages
23-
* todo 3: provide explicit configuration for a bean of type {@link TestDataGenerator} with name "dataGenerator" in this class.
24-
* hint: use method creation approach with @Bean annotation;
25-
* todo 4: Don't specify bean name "dataGenerator" explicitly
10+
* It also explicitly configures a bean of {@link TestDataGenerator} called "dataGenerator". This beans will be injected
11+
* into {@link com.bobocode.dao.FakeAccountDao} in order to generate some fake accounts.
2612
*/
27-
2813
public class ApplicationConfig {
29-
14+
// todo: configure application context according to javadoc by following tests in ApplicationConfigTest
15+
// todo: verify final implementation by running ApplicationContextTest
3016
}

3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/AccountDao.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import java.util.List;
66

77
/**
8-
* Defines an API for {@link Account} data access object (DAO).
8+
* Defines a simple API for {@link Account} data access object (DAO).
99
*/
1010
public interface AccountDao {
1111
List<Account> findAll();

3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,20 @@
22

33
import com.bobocode.TestDataGenerator;
44
import com.bobocode.model.Account;
5-
import org.springframework.beans.factory.annotation.Autowired;
6-
import org.springframework.stereotype.Component;
75

86
import java.util.List;
97
import java.util.stream.Stream;
108

119
import static java.util.stream.Collectors.toList;
1210

1311
/**
14-
* This class should be marked with @{@link Component}, thus Spring container will create an instance
15-
* of {@link FakeAccountDao} class, and will register it the context.
12+
* {@link FakeAccountDao} implements {@link AccountDao} using fake data. Instead of storing and fetching accounts from
13+
* some storage, it just generates fake records using {@link TestDataGenerator}.
1614
* <p>
17-
* todo: configure this class as Spring component with bean name "accountDao"
18-
* todo: use explicit (with {@link Autowired} annotation) constructor-based dependency injection for specific bean
15+
* An instance of this class should be created and added to the application context, so it is marked as Spring component.
16+
* Its bean is called "accountDao". And it uses constructor with explicit autowired annotation in order to inject
17+
* {@link TestDataGenerator} instance.
1918
*/
20-
2119
public class FakeAccountDao implements AccountDao {
2220
private List<Account> accounts;
2321

3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
import com.bobocode.dao.AccountDao;
44
import com.bobocode.model.Account;
55

6-
import java.util.Comparator;
7-
import java.util.List;
6+
import static java.util.Comparator.comparing;
87

98
/**
10-
* Provides service API for {@link Account}.
9+
* {@link AccountService} is a very simple service that allows to find the richest person based on data provided to
10+
* {@link AccountDao}.
1111
* <p>
12-
* todo: configure {@link AccountService} bean implicitly using special annotation for service classes
13-
* todo: use implicit constructor-based dependency injection (don't use {@link org.springframework.beans.factory.annotation.Autowired})
12+
* Since it's a service that should be added to the application context, it is marked as Spring service. It order to get
13+
* {@link AccountDao} instances, it uses implicit constructor-based injection.
1414
*/
15-
1615
public class AccountService {
1716
private final AccountDao accountDao;
1817

@@ -21,9 +20,9 @@ public AccountService(AccountDao accountDao) {
2120
}
2221

2322
public Account findRichestAccount() {
24-
List<Account> accounts = accountDao.findAll();
25-
return accounts.stream()
26-
.max(Comparator.comparing(Account::getBalance))
27-
.get();
23+
return accountDao.findAll()
24+
.stream()
25+
.max(comparing(Account::getBalance))
26+
.orElseThrow();
2827
}
2928
}

3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationConfigTest.java

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.bobocode.dao.FakeAccountDao;
66
import com.bobocode.service.AccountService;
77
import org.junit.jupiter.api.*;
8+
import org.springframework.beans.factory.annotation.Autowired;
89
import org.springframework.context.annotation.Bean;
910
import org.springframework.context.annotation.ComponentScan;
1011
import org.springframework.context.annotation.Configuration;
@@ -18,7 +19,7 @@
1819
import static org.junit.jupiter.api.Assertions.assertNotNull;
1920

2021
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
21-
public class ApplicationConfigTest {
22+
class ApplicationConfigTest {
2223

2324
@Test
2425
@Order(1)
@@ -52,6 +53,24 @@ void componentScanPackagesAreSpecified() {
5253

5354
@Test
5455
@Order(4)
56+
@DisplayName("FakeAccountDao is configured as @Component")
57+
void fakeAccountDaoIsConfiguredAsComponent() {
58+
Component component = FakeAccountDao.class.getAnnotation(Component.class);
59+
60+
assertNotNull(component);
61+
}
62+
63+
@Test
64+
@Order(5)
65+
@DisplayName("AccountDao constructor is marked with @Autowired")
66+
void accountDaoConstructorIsMarkedWithAutowired() throws NoSuchMethodException {
67+
Autowired autowired = FakeAccountDao.class.getConstructor(TestDataGenerator.class).getAnnotation(Autowired.class);
68+
69+
assertNotNull(autowired);
70+
}
71+
72+
@Test
73+
@Order(6)
5574
@DisplayName("DataGenerator bean is configured in method marked with @Bean")
5675
void dataGeneratorBeanIsConfiguredExplicitly() {
5776
Method[] methods = ApplicationConfig.class.getMethods();
@@ -61,7 +80,7 @@ void dataGeneratorBeanIsConfiguredExplicitly() {
6180
}
6281

6382
@Test
64-
@Order(5)
83+
@Order(7)
6584
@DisplayName("DataGenerator bean name is not specified explicitly")
6685
void dataGeneratorBeanNameIsNotSpecifiedExplicitly() {
6786
Method[] methods = ApplicationConfig.class.getMethods();
@@ -73,16 +92,7 @@ void dataGeneratorBeanNameIsNotSpecifiedExplicitly() {
7392
}
7493

7594
@Test
76-
@Order(6)
77-
@DisplayName("FakeAccountDao is configured as @Component")
78-
void fakeAccountDaoIsConfiguredAsComponent() {
79-
Component component = FakeAccountDao.class.getAnnotation(Component.class);
80-
81-
assertNotNull(component);
82-
}
83-
84-
@Test
85-
@Order(7)
95+
@Order(8)
8696
@DisplayName("AccountService is configured as @Service")
8797
void accountServiceIsConfiguredAsService() {
8898
Service service = AccountService.class.getAnnotation(Service.class);
@@ -91,7 +101,7 @@ void accountServiceIsConfiguredAsService() {
91101
}
92102

93103
@Test
94-
@Order(8)
104+
@Order(9)
95105
@DisplayName("AccountService bean name is not specified explicitly")
96106
void accountServiceBeanNameIsNotSpecifiedExplicitly() {
97107
Service service = AccountService.class.getAnnotation(Service.class);
@@ -100,7 +110,7 @@ void accountServiceBeanNameIsNotSpecifiedExplicitly() {
100110
}
101111

102112
@Test
103-
@Order(9)
113+
@Order(10)
104114
@DisplayName("AccountService doesn't use @Autowired")
105115
void accountServiceDoesNotUseAutowired() throws NoSuchMethodException {
106116
Annotation[] annotations = AccountService.class.getConstructor(AccountDao.class).getDeclaredAnnotations();

3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,6 @@ static class TestConfig {
2626
@Autowired
2727
private ApplicationContext applicationContext;
2828

29-
@Autowired
30-
private AccountService accountService;
31-
32-
@Autowired
33-
private AccountDao accountDao;
34-
3529
@Test
3630
@Order(1)
3731
@DisplayName("DataGenerator has only one bean")
@@ -43,7 +37,7 @@ void dataGeneratorHasOnlyOneBean() {
4337

4438
@Test
4539
@Order(2)
46-
@DisplayName("DataGenerator bean has proper name")
40+
@DisplayName("DataGenerator bean is called \"dataGenerator\"")
4741
void testDataGeneratorBeanName() {
4842
Map<String, TestDataGenerator> dataGeneratorBeanMap = applicationContext.getBeansOfType(TestDataGenerator.class);
4943

@@ -61,22 +55,13 @@ void accountDaoHasOnlyOneBean() {
6155

6256
@Test
6357
@Order(4)
64-
@DisplayName("AccountDao bean has proper name")
58+
@DisplayName("AccountDao bean is called \"accountDao\"")
6559
void accountDaoBeanName() {
6660
Map<String, AccountDao> accountDaoBeanMap = applicationContext.getBeansOfType(AccountDao.class);
6761

6862
assertThat(accountDaoBeanMap.keySet()).contains("accountDao");
6963
}
7064

71-
@Test
72-
@Order(5)
73-
@DisplayName("AccountDao constructor is marked with @Autowired")
74-
void accountDaoConstructorIsMarkedWithAutowired() throws NoSuchMethodException {
75-
Autowired autowired = FakeAccountDao.class.getConstructor(TestDataGenerator.class).getAnnotation(Autowired.class);
76-
77-
assertNotNull(autowired);
78-
}
79-
8065
@Test
8166
@Order(6)
8267
@DisplayName("AccountService has only one bean")
@@ -88,7 +73,7 @@ void accountServiceHasOnlyOneBean() {
8873

8974
@Test
9075
@Order(7)
91-
@DisplayName("AccountService has proper name")
76+
@DisplayName("AccountService bean is called \"accountService\"")
9277
void accountServiceBeanName() {
9378
Map<String, AccountService> accountServiceMap = applicationContext.getBeansOfType(AccountService.class);
9479

java-web-course-util/spring-framework-exercises-util/src/main/java/com/bobocode/TestDataGenerator.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,31 @@
88
import java.math.BigDecimal;
99
import java.time.LocalDate;
1010
import java.time.LocalDateTime;
11-
import java.util.Random;
11+
import java.util.concurrent.ThreadLocalRandom;
1212

1313
public class TestDataGenerator {
1414
public Account generateAccount() {
1515
Fairy fairy = Fairy.create();
1616
Person person = fairy.person();
17-
Random random = new Random();
1817

19-
Account fakeAccount = new Account();
20-
fakeAccount.setFirstName(person.getFirstName());
21-
fakeAccount.setLastName(person.getLastName());
22-
fakeAccount.setEmail(person.getEmail());
23-
fakeAccount.setBirthday(LocalDate.of(
18+
Account account = convertToAccount(person);
19+
BigDecimal balance = BigDecimal.valueOf(ThreadLocalRandom.current().nextInt(200_000));
20+
account.setBalance(balance);
21+
account.setCreationTime(LocalDateTime.now());
22+
23+
return account;
24+
}
25+
26+
private Account convertToAccount(Person person) {
27+
Account account = new Account();
28+
account.setFirstName(person.getFirstName());
29+
account.setLastName(person.getLastName());
30+
account.setEmail(person.getEmail());
31+
account.setBirthday(LocalDate.of(
2432
person.getDateOfBirth().getYear(),
2533
person.getDateOfBirth().getMonthOfYear(),
2634
person.getDateOfBirth().getDayOfMonth()));
27-
fakeAccount.setGender(Gender.valueOf(person.getSex().name()));
28-
fakeAccount.setBalance(BigDecimal.valueOf(random.nextInt(200_000)));
29-
fakeAccount.setCreationTime(LocalDateTime.now());
30-
31-
return fakeAccount;
35+
account.setGender(Gender.valueOf(person.getSex().name()));
36+
return account;
3237
}
3338
}

0 commit comments

Comments
 (0)