Skip to content

Commit 513e2f9

Browse files
author
Piotr Kubicki
committed
Merge remote-tracking branch 'origin/feature/2-dataaccess' into feature/2-dataaccess-repositories
# Conflicts: # pom.xml # src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java # src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java
2 parents c119814 + b5eebea commit 513e2f9

File tree

13 files changed

+169
-98
lines changed

13 files changed

+169
-98
lines changed

README.md

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,53 @@
1-
# Java Backend Developer Training – Lab Source
1+
# Java Backend Developer Training – Reference Implementation
22

3-
> 📌 **This repository contains the reference implementation of the application developed during the Java Backend Developer training.**\
4-
> Participants progressively gain access to additional branches as they progress through the course.
3+
> 📌 **This repository contains the _reference implementation_ of the application developed step-by-step during the _Java Backend Developer Training_.**
4+
> Each subsequent branch adds more functionality on top of the previous one, allowing participants to explore and compare their solutions.
55
66
## 📖 Project Overview
77

8-
This project is a **Spring Boot 3** application designed to serve as a **backend development reference implementation**. It follows **clean coding principles** and modern development best practices.
8+
This is a **Spring Boot 3** backend application named **_Appointment Booking System_**, created as part of hands-on backend development training.
9+
It follows modern architectural and coding practices, including **clean code**, **layered structure**, and **modular design**.
910

10-
The application developed during the Java Backend Developer training is called _**Appointment Booking System**_.
11+
📄 Specification: [**AppointmentBookingAppDoc.md**](AppointmentBookingAppDoc.md)
1112

12-
#### Here you will find the specification: **[AppointmentBookingAppDoc.md](AppointmentBookingAppDoc.md).**
13+
## 🌱 Branch Progression
1314

14-
### 🛠 Tech Stack
15+
The repository grows in complexity and functionality across branches:
16+
17+
| Branch | Description |
18+
|--------|------------------------------------------------------------------------|
19+
| `main` | Base Spring Boot setup with basic health and H2 endpoints |
20+
| `feature/1-create-new-application` | Same as main |
21+
| `feature/2-dataaccess` | Persistence layer with Spring Data JPA and H2, part 1 |
22+
| `feature/2-dataaccess-repositories` | Persistence layer with Spring Data JPA and H2, part 2 |
23+
| `feature/3-business-logic` | Service layer and business logic introduced |
24+
| `feature/4-services` | OpenAPI/Swagger setup for live API documentation and testing |
25+
| `feature/5-security` | Spring Security integration for basic authentication and authorization |
26+
27+
## 🌐 Useful Endpoints
28+
29+
After starting the application, you can access the following in your browser:
30+
31+
| URL | Available from | Description |
32+
|-----|----------------|-------------|
33+
| [http://localhost:8080/actuator/health](http://localhost:8080/actuator/health) | `main` | Basic application health check |
34+
| [http://localhost:8080/h2-console](http://localhost:8080/h2-console) | `main` | In-memory H2 database console |
35+
| [http://localhost:8080/swagger-ui/index.html](http://localhost:8080/swagger-ui/index.html) | `feature/4-services` | OpenAPI UI for testing and exploring REST API |
36+
37+
## 🛠 Tech Stack
1538

1639
- **Java 21**
1740
- **Spring Boot 3**
18-
- **Maven 3.9.x** as the build tool
19-
- **JUnit 5 & AssertJ** for testing
41+
- **Maven 3.9+**
42+
- **JUnit 5 & AssertJ**
43+
- **H2 Database**
44+
- **OpenAPI & Swagger UI**
45+
- **Spring Security**
2046
- **GitHub Actions** for CI/CD
2147

22-
## 📂 Repository Structure
48+
## 📁 Project Structure
49+
50+
2351

2452
```
2553
java-backend-developer-app/
@@ -80,12 +108,17 @@ GitHub Actions is used for CI/CD, configured in \`.github/workflows/ci.yml\`. Th
80108
- **Every push and pull request** to \`main\` and feature branches.
81109
- **Runs tests** and generates reports.
82110

111+
## 🙋 Who Is This For?
112+
This reference repo is intended for trainers and mentors to demonstrate completed solutions.
113+
🧑‍💻 **Each training participant works independently in a separate student repository.** This repository serves as a working example.
114+
83115
## 🤝 Contribution Guidelines
84116

85-
1. Create a **feature branch** for any changes.
117+
1. Create a **feature branch** for any changes from a particular, possibly smallest "main" feature branch, e.g. 'feature/2-data-access'.
86118
2. Ensure the code **follows project conventions** and is properly tested.
87-
3. Open a **Pull Request** to \`main\`. Direct pushes are restricted.
119+
3. Open a **Pull Request** to particular, corresponding "main" feature branch, e.g. 'feature/2-data-access'. Direct pushes are restricted.
88120
4. Wait for **CI to pass** and a **review** before merging.
121+
5. Rebase higher feature branches onto changed one, e.g. if you merged to 'feature/3-business-logic', then you should rebase 'feature/4-services' and 'feature/5-security' to have your changes there as well.
89122

90123
## License
91124

pom.xml

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>3.4.3</version>
8+
<version>3.4.4</version>
99
<relativePath/> <!-- lookup parent from repository -->
1010
</parent>
1111
<groupId>com.capgemini.training</groupId>
@@ -55,7 +55,7 @@
5555
<dependency>
5656
<groupId>org.projectlombok</groupId>
5757
<artifactId>lombok</artifactId>
58-
<scope>provided</scope>
58+
<scope>provided</scope>
5959
</dependency>
6060
<dependency>
6161
<groupId>org.springframework.boot</groupId>
@@ -79,6 +79,13 @@
7979

8080
<build>
8181
<plugins>
82+
<plugin>
83+
<groupId>org.apache.maven.plugins</groupId>
84+
<artifactId>maven-compiler-plugin</artifactId>
85+
<configuration>
86+
<release>${java.version}</release>
87+
</configuration>
88+
</plugin>
8289
<plugin>
8390
<groupId>org.springframework.boot</groupId>
8491
<artifactId>spring-boot-maven-plugin</artifactId>
@@ -104,12 +111,12 @@
104111
<plugin>
105112
<groupId>org.apache.maven.plugins</groupId>
106113
<artifactId>maven-surefire-plugin</artifactId>
107-
<version>3.5.2</version>
114+
<version>3.5.3</version>
108115
</plugin>
109116
<plugin>
110117
<groupId>org.apache.maven.plugins</groupId>
111118
<artifactId>maven-failsafe-plugin</artifactId>
112-
<version>3.5.2</version>
119+
<version>3.5.3</version>
113120
<executions>
114121
<execution>
115122
<goals>
@@ -122,7 +129,7 @@
122129
<plugin>
123130
<groupId>org.apache.maven.plugins</groupId>
124131
<artifactId>maven-surefire-report-plugin</artifactId>
125-
<version>3.5.2</version>
132+
<version>3.5.3</version>
126133
<executions>
127134
<execution>
128135
<phase>verify</phase>
@@ -151,6 +158,24 @@
151158
</execution>
152159
</executions>
153160
</plugin>
161+
<plugin>
162+
<groupId>com.diffplug.spotless</groupId>
163+
<artifactId>spotless-maven-plugin</artifactId>
164+
<version>2.43.0</version>
165+
<configuration>
166+
<java>
167+
<removeUnusedImports/>
168+
<eclipse/>
169+
</java>
170+
</configuration>
171+
<executions>
172+
<execution>
173+
<goals>
174+
<goal>check</goal>
175+
</goals>
176+
</execution>
177+
</executions>
178+
</plugin>
154179
</plugins>
155180
</build>
156181
</project>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package com.capgemini.training.appointmentbooking.common.datatype;
22

33
public enum AppointmentStatus {
4-
SCHEDULED, CANCELLED, COMPLETED;
4+
SCHEDULED, CANCELLED, COMPLETED
55
}
Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
11
package com.capgemini.training.appointmentbooking.common.datatype;
22

3+
import lombok.Getter;
4+
5+
@Getter
36
public enum Specialization {
4-
5-
DENTIST("Dentist"),
6-
CARDIOLOGIST("Cardiologist"),
7-
PEDIATRICIAN("Pediatrician"),
8-
UROLOGIST("Urologist"),
9-
NEUROLOGIST("Neurologist"),
10-
ORTHOPAEDIST("Orthopaedist");
11-
12-
private String name;
13-
14-
private Specialization(String name) {
7+
8+
DENTIST("Dentist"), CARDIOLOGIST("Cardiologist"), PEDIATRICIAN("Pediatrician"), UROLOGIST("Urologist"), NEUROLOGIST(
9+
"Neurologist"), ORTHOPAEDIST("Orthopaedist");
10+
11+
private final String name;
12+
13+
Specialization(String name) {
1514
this.name = name;
1615
}
1716

18-
public String getName() {
19-
return this.name;
20-
}
21-
2217
public static Specialization getByName(String name) {
2318

2419
for (Specialization s : Specialization.values()) {
@@ -28,5 +23,5 @@ public static Specialization getByName(String name) {
2823
}
2924
return null;
3025
}
31-
26+
3227
}

src/main/java/com/capgemini/training/appointmentbooking/dataaccess/converter/SpecializationConverter.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ public class SpecializationConverter implements AttributeConverter<Specializatio
99

1010
@Override
1111
public String convertToDatabaseColumn(Specialization specialization) {
12-
12+
1313
return specialization != null ? specialization.getName() : null;
14-
14+
1515
}
1616

1717
@Override
18-
public Specialization convertToEntityAttribute(String dbData) {
19-
if (dbData == null) {
20-
return null;
21-
}
22-
return Specialization.getByName(dbData);
23-
}
18+
public Specialization convertToEntityAttribute(String dbData) {
19+
if (dbData == null) {
20+
return null;
21+
}
22+
return Specialization.getByName(dbData);
23+
}
2424

2525
}

src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,26 @@
1919
import lombok.Setter;
2020

2121
@Entity
22-
@Table(name="APPOINTMENT")
22+
@Table(name = "APPOINTMENT")
2323
@Getter
2424
@Setter
2525
public class AppointmentEntity extends BaseEntity {
26-
26+
2727
@Id
2828
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "APPOINTMENT_SEQ_GEN")
29-
@SequenceGenerator(sequenceName = "APPOINTMENT_SEQ", name = "APPOINTMENT_SEQ_GEN", allocationSize = 100, initialValue = 1)
29+
@SequenceGenerator(sequenceName = "APPOINTMENT_SEQ", name = "APPOINTMENT_SEQ_GEN", allocationSize = 100)
3030
private Long id;
31-
31+
3232
@ManyToOne(fetch = FetchType.LAZY)
3333
private ClientEntity client;
34-
34+
3535
@ManyToOne(fetch = FetchType.LAZY)
3636
private TreatmentEntity treatment;
37-
38-
@Column(name="DATE_TIME")
37+
38+
@Column(name = "DATE_TIME")
3939
private Instant dateTime;
40-
40+
4141
@Enumerated(EnumType.STRING)
4242
private AppointmentStatus status;
43-
43+
4444
}

src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/BaseEntity.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.capgemini.training.appointmentbooking.dataaccess.entity;
22

33
import java.time.Instant;
4-
import java.util.Date;
54

65
import jakarta.persistence.Column;
76
import jakarta.persistence.MappedSuperclass;
@@ -14,24 +13,24 @@
1413
@MappedSuperclass
1514
@Getter
1615
public class BaseEntity {
17-
16+
1817
@Version
1918
@Setter
2019
private int version;
2120

22-
@Column(insertable = true, updatable = false)
21+
@Column(updatable = false)
2322
private Instant created;
24-
25-
@Column(name="LAST_UPDATED")
23+
24+
@Column(name = "LAST_UPDATED")
2625
private Instant lastUpdated;
27-
26+
2827
@PrePersist
2928
public void prePersist() {
3029
Instant now = Instant.now();
3130
this.created = now;
3231
this.lastUpdated = now;
3332
}
34-
33+
3534
@PreUpdate
3635
public void preUpdate() {
3736
this.lastUpdated = Instant.now();

src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/ClientEntity.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,21 @@
1616
import lombok.Setter;
1717

1818
@Entity
19-
@Table(name="CLIENT")
19+
@Table(name = "CLIENT")
2020
@Getter
2121
@Setter
22-
public class ClientEntity extends BaseEntity {
23-
22+
public class ClientEntity extends BaseEntity {
23+
2424
@Id
2525
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CLIENT_SEQ_GEN")
26-
@SequenceGenerator(sequenceName = "CLIENT_SEQ", name = "CLIENT_SEQ_GEN", allocationSize = 100, initialValue = 1)
26+
@SequenceGenerator(sequenceName = "CLIENT_SEQ", name = "CLIENT_SEQ_GEN", allocationSize = 100)
2727
private Long id;
28-
29-
@OneToOne(optional = false, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST })
28+
29+
@OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST})
3030
private UserEntity user;
31-
32-
@OneToMany(mappedBy = "client", fetch = FetchType.LAZY, orphanRemoval=true, cascade = { CascadeType.PERSIST, CascadeType.REMOVE })
31+
32+
@OneToMany(mappedBy = "client", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST,
33+
CascadeType.REMOVE})
3334
private List<AppointmentEntity> appointments;
34-
35+
3536
}

src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,24 @@
99
import java.util.List;
1010

1111
@Entity
12-
@Table(name="SPECIALIST")
12+
@Table(name = "SPECIALIST")
1313
@Getter
1414
@Setter
1515
@NamedQuery(name = "SpecialistEntity.findBySpecialization", query = "select s from SpecialistEntity s where specialization =:specialization")
1616
public class SpecialistEntity extends BaseEntity {
1717

1818
@Id
1919
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SPECIALIST_SEQ_GEN")
20-
@SequenceGenerator(sequenceName = "SPECIALIST_SEQ", name = "SPECIALIST_SEQ_GEN", allocationSize = 100, initialValue = 1)
20+
@SequenceGenerator(sequenceName = "SPECIALIST_SEQ", name = "SPECIALIST_SEQ_GEN", allocationSize = 100)
2121
private Long id;
22-
23-
@OneToOne(optional = false, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST })
22+
23+
@OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST})
2424
private UserEntity user;
25-
25+
2626
@Convert(converter = SpecializationConverter.class)
2727
private Specialization specialization;
2828

29-
@OneToMany(mappedBy = "specialist", fetch = FetchType.LAZY, orphanRemoval = true, cascade = { CascadeType.PERSIST, CascadeType.REMOVE })
29+
@OneToMany(mappedBy = "specialist", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST,
30+
CascadeType.REMOVE})
3031
private List<TreatmentEntity> treatments;
3132
}

0 commit comments

Comments
 (0)