Skip to content

Commit 9dc8f85

Browse files
adding domain classes
1 parent 6970fdf commit 9dc8f85

File tree

14 files changed

+603
-50
lines changed

14 files changed

+603
-50
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
*.class
22
.gradle
3-
*/build/
3+
**/build/
44
*/bin/
55
*/.settings/
66
.project

aws-sdk-2/expenses-1/README.md

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
# Java AWS Lambda with Serverless.com Tutorial
22

3-
## Expense Service Tutorial - Iteration 1
3+
## Expense Service Tutorial - Iteration 1
44

5-
Goal: Define core domain classes
5+
Goal: Define some domain classes with tests
66

7-
Steps
8-
1. Implement `Expense`
9-
2. Implement `Person`
10-
3. TODO: other bussiness logic container/"service" class? "Repository" with mocked implementation...
11-
4. Test!
7+
Steps:
8+
1. Create `Expense` and `Person` model classes - with tests
9+
2. Create a repository interface for creating and retrieving expenses and people - with tests

aws-sdk-2/expenses-1/build.gradle

+7-42
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,17 @@
1-
apply plugin: 'java'
1+
plugins {
2+
id 'java'
3+
}
24

35
repositories {
46
mavenCentral()
57
}
68

7-
sourceCompatibility = 1.11
8-
targetCompatibility = 1.11
9-
109
dependencies {
11-
// compile (
12-
// 'com.amazonaws:aws-lambda-java-core:1.1.0',
13-
// 'com.amazonaws:aws-lambda-java-log4j:1.0.0',
14-
// 'com.amazonaws:aws-lambda-java-events:2.2.6',
15-
// 'com.fasterxml.jackson.core:jackson-core:2.8.5',
16-
// 'com.fasterxml.jackson.core:jackson-databind:2.8.5',
17-
// 'com.fasterxml.jackson.core:jackson-annotations:2.8.5'
18-
// )
19-
20-
testImplementation(
21-
'org.junit.jupiter:junit-jupiter-api:5.1.0'
22-
)
23-
testRuntimeOnly(
24-
'org.junit.jupiter:junit-jupiter-engine:5.1.0'
25-
)
10+
testImplementation 'org.assertj:assertj-core:3.22.0'
11+
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
12+
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
2613
}
2714

2815
test {
29-
// environment "STAGE","development"
3016
useJUnitPlatform()
31-
}
32-
33-
// Task for building the zip file for upload
34-
task buildZip(type: Zip) {
35-
// Using the Zip API from gradle to build a zip file of all the dependencies
36-
//
37-
// The path to this zip file can be set in the serverless.yml file for the
38-
// package/artifact setting for deployment to the S3 bucket
39-
//
40-
// Link: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Zip.html
41-
42-
// set the base name of the zip file
43-
baseName = "expenses-service"
44-
from compileJava
45-
from processResources
46-
into('lib') {
47-
from configurations.runtime
48-
}
49-
}
50-
51-
build.dependsOn buildZip
52-
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.example.expenses.model;
2+
3+
import java.math.BigDecimal;
4+
import java.time.LocalDate;
5+
import java.util.Objects;
6+
import java.util.UUID;
7+
8+
public class Expense {
9+
private final UUID id;
10+
private final BigDecimal amount;
11+
private final LocalDate date;
12+
private final Person paidByPerson;
13+
14+
public Expense(UUID id, BigDecimal amount, LocalDate date, Person paidByPerson) {
15+
this.id = id;
16+
this.amount = amount;
17+
this.date = date;
18+
this.paidByPerson = paidByPerson;
19+
}
20+
21+
public Expense(BigDecimal amount, Person paidByPerson) {
22+
this(UUID.randomUUID(), amount, LocalDate.now(), paidByPerson);
23+
}
24+
25+
public UUID getId() {
26+
return id;
27+
}
28+
29+
public BigDecimal getAmount() {
30+
return amount;
31+
}
32+
33+
public LocalDate getDate() {
34+
return date;
35+
}
36+
37+
public Person getPaidByPerson() {
38+
return paidByPerson;
39+
}
40+
41+
@Override
42+
public boolean equals(Object o) {
43+
if (this == o) return true;
44+
if (o == null || getClass() != o.getClass()) return false;
45+
Expense expense = (Expense) o;
46+
return Objects.equals(id, expense.id) && Objects.equals(amount, expense.amount) && Objects.equals(date, expense.date) && Objects.equals(paidByPerson, expense.paidByPerson);
47+
}
48+
49+
@Override
50+
public int hashCode() {
51+
return Objects.hash(id, amount, date, paidByPerson);
52+
}
53+
54+
@Override
55+
public String toString() {
56+
return "Expense{" +
57+
"id=" + id +
58+
", amount=" + amount +
59+
", date=" + date +
60+
", paidByPerson=" + paidByPerson +
61+
'}';
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.example.expenses.model;
2+
3+
public class Person {
4+
protected final String email;
5+
6+
public Person(String email) {
7+
this.email = email;
8+
}
9+
10+
public String getEmail() {
11+
return email;
12+
}
13+
14+
@Override
15+
public boolean equals(Object o) {
16+
if (this == o) return true;
17+
if (o == null || getClass() != o.getClass()) return false;
18+
19+
Person person = (Person) o;
20+
21+
return email.equals(person.email);
22+
}
23+
24+
@Override
25+
public int hashCode() {
26+
return email.hashCode();
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.example.expenses.repository;
2+
3+
import com.example.expenses.model.Expense;
4+
import com.example.expenses.model.Person;
5+
6+
import java.util.List;
7+
import java.util.Optional;
8+
9+
/**
10+
* DataRepository:
11+
* I define the protocol -- the set of methods -- that other parts of the application can use to
12+
* persist instances of the domain model (Persons, Expenses).
13+
* <p>
14+
* My name, {@code DataRepository}, is intended to indicate the abstract idea that <em>this</em>
15+
* is where data lives, without binding to any specific implementation like memory, file or database.
16+
* <p>
17+
*/
18+
public interface DataRepository {
19+
20+
/**
21+
* Add a new Person instance to the datastore. If the Person passed to this method already exists
22+
* in the repository, we'll return that instance and ignore the request.
23+
* If you ask for a {@literal null} Person, it will throw a NullPointerException.
24+
* @param person A non-null Person instance.
25+
* @return The Person instance you added or that already existed in the repository.
26+
*/
27+
Person addPerson(Person person);
28+
29+
/**
30+
* Find a Person instance with the given email address.
31+
* @param email Email address of the Person we want to find.
32+
* @return An Optional containing the Person if they exist in the repository, empty otherwise.
33+
*/
34+
Optional<Person> findPerson( String email );
35+
36+
/**
37+
* Answer with a List of all Person instances in the repository.
38+
* @return A set of Person instances, possible empty, but never {@literal null}.
39+
*/
40+
List<Person> allPersons();
41+
42+
/**
43+
* Add a new Expense instance to the repository.
44+
* If this expense's id is null, then it will be filled in with a random UUID.
45+
* If this expense's data is null,k then it will be filled in with today's date.
46+
* @param expense A non-null Expense instance
47+
* @return The Expense instance you added
48+
*/
49+
Expense addExpense(Expense expense);
50+
51+
/**
52+
* Finds all the expenses paid for by specified person.
53+
* @param person the non-null Person instance that must match the Expense's paidByPerson field.
54+
* @return A set of Expense instances, possible empty, but never {@literal null}. Sorted ascending according to date.
55+
*/
56+
List<Expense> findExpensesPaidBy(Person person);
57+
58+
/**
59+
* Answer with a List of all Expense instances in the repository.
60+
* @return A set of Expense instances, possible empty, but never {@literal null}. Sorted ascending according to date.
61+
*/
62+
List<Expense> allExpenses();
63+
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.example.expenses.repository.memory;
2+
3+
import com.example.expenses.model.Expense;
4+
import com.example.expenses.model.Person;
5+
import com.example.expenses.repository.DataRepository;
6+
7+
import java.util.*;
8+
import java.util.stream.Collectors;
9+
10+
public class InMemoryRepository implements DataRepository {
11+
private final Set<Person> people = new HashSet<>();
12+
private final Set<Expense> expenses = new HashSet<>();
13+
14+
/**
15+
* {@inheritDoc}
16+
*/
17+
@Override
18+
public List<Person> allPersons() {
19+
return people.stream().collect(Collectors.toUnmodifiableList());
20+
}
21+
22+
/**
23+
* {@inheritDoc}
24+
*/
25+
@Override
26+
public Optional<Person> findPerson(String email) {
27+
return people.stream()
28+
.filter(Person -> Person.getEmail().equalsIgnoreCase(email))
29+
.findFirst();
30+
}
31+
32+
/**
33+
* {@inheritDoc}
34+
*/
35+
@Override
36+
public Person addPerson(Person person) {
37+
Optional<Person> alreadyExists = findPerson(person.getEmail());
38+
if (alreadyExists.isPresent()) {
39+
return alreadyExists.get();
40+
}
41+
people.add(person);
42+
return person;
43+
}
44+
45+
@Override
46+
public Expense addExpense(Expense expense) {
47+
expenses.add(expense);
48+
return expense;
49+
}
50+
51+
@Override
52+
public List<Expense> findExpensesPaidBy(Person person) {
53+
return expenses.stream().filter(expense -> expense.getPaidByPerson().equals(person)).collect(Collectors.toUnmodifiableList());
54+
}
55+
56+
@Override
57+
public List<Expense> allExpenses() {
58+
return expenses.stream().collect(Collectors.toUnmodifiableList());
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.example.expenses.model;
2+
3+
import org.junit.jupiter.api.DisplayName;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.math.BigDecimal;
7+
import java.time.LocalDate;
8+
import java.util.UUID;
9+
10+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
11+
12+
class ExpenseTest {
13+
14+
@Test
15+
@DisplayName("Two expenses are the same if their fields are the same")
16+
void sameExpense() {
17+
UUID id = UUID.randomUUID();
18+
Person me = new Person("[email protected]");
19+
Expense e1 = new Expense(id, BigDecimal.valueOf(100.0), LocalDate.of(2022, 3, 15), me);
20+
Expense e2 = new Expense(id, BigDecimal.valueOf(100.0), LocalDate.of(2022, 3, 15), me);
21+
assertThat(e1).isEqualTo(e2);
22+
}
23+
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.example.expenses.model;
2+
3+
import org.junit.jupiter.api.DisplayName;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
7+
8+
class PersonTest {
9+
10+
@Test
11+
@DisplayName("Two people are the same if their emails are the same")
12+
void samePerson() {
13+
Person p1 = new Person("[email protected]");
14+
Person p2 = new Person("[email protected]");
15+
assertThat(p1).isEqualTo(p2);
16+
}
17+
18+
}

0 commit comments

Comments
 (0)