Skip to content

Commit 35e12c1

Browse files
committed
chore: align project formatting and config with HMCTS standards
- Refactor all Java files to comply with HMCTS checkstyle rules - Expand wildcard imports and fix indentation/line-length violations - Add .editorconfig using HMCTS formatting conventions - Update .gitignore to include HMCTS-relevant patterns - Remove Spotless plugin from build.gradle (not used in HMCTS projects) - Ensure Checkstyle uses HMCTS-provided configuration files This brings the project into alignment with the HMCTS engineering standards and eliminates conflicting or redundant formatting tools.
1 parent b7c1b9b commit 35e12c1

File tree

10 files changed

+626
-845
lines changed

10 files changed

+626
-845
lines changed

.editorconfig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# http://editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_style = space
6+
indent_size = 2
7+
end_of_line = lf
8+
charset = utf-8
9+
trim_trailing_whitespace = true
10+
insert_final_newline = true
11+
max_line_length = 120
12+
13+
[*.java]
14+
indent_size = 4
15+
ij_continuation_indent_size = 4
16+
ij_java_align_multiline_parameters = true
17+
ij_java_align_multiline_parameters_in_calls = true
18+
ij_java_call_parameters_new_line_after_left_paren = true
19+
ij_java_call_parameters_right_paren_on_new_line = true
20+
ij_java_call_parameters_wrap = on_every_item

.gitignore

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
HELP.md
22
.gradle
33
build/
4+
**/build/
5+
*.class
46
!gradle/wrapper/gradle-wrapper.jar
57
!**/src/main/**/build/
68
!**/src/test/**/build/
9+
bin/main/application.yaml
10+
**/target
711

812

913
### STS ###
@@ -26,6 +30,12 @@ bin/
2630
out/
2731
!**/src/main/**/out/
2832
!**/src/test/**/out/
33+
.mirrord
34+
.DS_Store
35+
36+
# node_modules
37+
package-lock.json
38+
node_modules/
2939

3040
### NetBeans ###
3141
/nbproject/private/
@@ -53,4 +63,5 @@ out/
5363
*.pem
5464

5565
# Environment variables
56-
.env
66+
.env
67+

build.gradle

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ plugins {
77
id 'jacoco' // Code coverage
88
id 'checkstyle' // Style rule enforcement
99
id 'com.github.spotbugs' version '6.0.7' // Static analysis for bugs
10-
id 'com.diffplug.spotless' version '6.25.0' // Code formatting
1110
}
1211

1312
group = 'com.codesungrape.hmcts'
@@ -112,19 +111,10 @@ jacocoTestCoverageVerification {
112111

113112
// ===== CODE QUALITY & STYLE CONFIGURATION =====
114113

115-
spotless {
116-
java {
117-
googleJavaFormat('1.17.0').aosp() // A popular, opinionated style
118-
removeUnusedImports()
119-
trimTrailingWhitespace()
120-
endWithNewline()
121-
}
122-
}
123-
124114
checkstyle {
125-
toolVersion = '12.1.2'
126-
maxWarnings = 0 // Fail build on any warning
127-
configFile = file("${rootDir}/config/checkstyle/checkstyle.xml")
115+
maxWarnings = 0
116+
toolVersion = '10.26.1'
117+
getConfigDirectory().set(new File(rootDir, 'config/checkstyle'))
128118
}
129119

130120
spotbugs {

config/checkstyle/checkstyle.xml

Lines changed: 237 additions & 467 deletions
Large diffs are not rendered by default.

src/main/java/com/codesungrape/hmcts/bookapi/dto/BookRequest.java

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,13 @@
44
import jakarta.validation.constraints.NotBlank;
55

66
/**
7-
* DTO representing the required input for creating or replacing a Book resource.
8-
* This class mirrors the OpenAPI 'BookInput' schema.
9-
*
10-
* @Value: Makes fields final, adds constructor, getters, equals, hashCode, toString.
11-
* @NotBlank: Field required; empty/missing value returns 400 Bad Request in Spring.
12-
* @JsonProperty: Maps snake_case JSON to camelCase Java using Jackson.
7+
* DTO representing the required input for creating or replacing a Book resource. This class mirrors
8+
* the OpenAPI 'BookInput' schema. @Value: Makes fields final, adds constructor, getters, equals,
9+
* hashCode, toString. @NotBlank: Field required; empty/missing value returns 400 Bad Request in
10+
* Spring. @JsonProperty: Maps snake_case JSON to camelCase Java using Jackson.
1311
*/
1412
public record BookRequest(
15-
@JsonProperty("title")
16-
@NotBlank(message = "Title is required")
17-
String title,
18-
19-
@JsonProperty("synopsis")
20-
@NotBlank(message = "Synopsis is required")
21-
String synopsis,
22-
23-
@JsonProperty("author")
24-
@NotBlank(message = "Author is required")
25-
String author
26-
) {
27-
}
13+
@JsonProperty("title") @NotBlank(message = "Title is required") String title,
14+
@JsonProperty("synopsis") @NotBlank(message = "Synopsis is required") String synopsis,
15+
@JsonProperty("author") @NotBlank(message = "Author is required") String author) {
16+
}

src/main/java/com/codesungrape/hmcts/bookapi/entity/Book.java

Lines changed: 51 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
import jakarta.persistence.PrePersist;
99
import jakarta.persistence.PreUpdate;
1010
import jakarta.persistence.Table;
11+
1112
import java.time.Instant;
1213
import java.util.UUID;
14+
1315
import lombok.AccessLevel;
1416
import lombok.AllArgsConstructor;
1517
import lombok.Builder;
@@ -18,22 +20,14 @@
1820
import lombok.Setter;
1921

2022
/**
21-
* Represents the Book table in PostgreSQL as a JPA entity.
22-
* Stores the persisted state of a Book resource.
23-
* HMCTS Rule: IDs must be opaque; using UUID for distributed ID generation.
24-
*
25-
* @Entity: Marks the class as a JPA entity for Hibernate table mapping.
26-
* @Table: Specifies the database table; HMCTS: lowercase, singular table name.
27-
* Lombok Annotations:
28-
* @Getter: Generates getters for all fields.
29-
* @Setter: Generates setters for all fields.
30-
* @NoArgsConstructor: Protected no-arg constructor for JPA instantiation.
31-
* @AllArgsConstructor: Constructor with all fields for test convenience.
32-
* @Builder: Adds builder pattern for easy object creation.
33-
* Example: Book.builder()
34-
* .title("A")
35-
* .author("B")
36-
* .build();
23+
* Represents the Book table in PostgreSQL as a JPA entity. Stores the persisted state of a Book
24+
* resource. HMCTS Rule: IDs must be opaque; using UUID for distributed ID generation. @Entity:
25+
* Marks the class as a JPA entity for Hibernate table mapping. @Table: Specifies the database
26+
* table; HMCTS: lowercase, singular table name. Lombok Annotations: @Getter: Generates getters for
27+
* all fields. @Setter: Generates setters for all fields. @NoArgsConstructor: Protected no-arg
28+
* constructor for JPA instantiation. @AllArgsConstructor: Constructor with all fields for test
29+
* convenience. @Builder: Adds builder pattern for easy object creation. Example: Book.builder()
30+
* .title("A") .author("B") .build();
3731
*/
3832
@Entity
3933
@Table(name = "book")
@@ -44,53 +38,54 @@
4438
@Builder // For convenience in creating instances
4539
public class Book {
4640

47-
@Id // Primary key of the table
48-
@GeneratedValue(strategy = GenerationType.UUID)
49-
@Column(name = "id", nullable = false)
50-
private UUID id;
41+
@Id // Primary key of the table
42+
@GeneratedValue(strategy = GenerationType.UUID)
43+
@Column(name = "id", nullable = false)
44+
private UUID id;
45+
46+
@Column(name = "title", nullable = false)
47+
private String title;
5148

52-
@Column(name = "title", nullable = false)
53-
private String title;
49+
@Column(name = "synopsis", nullable = false, columnDefinition = "TEXT")
50+
private String synopsis;
5451

55-
@Column(name = "synopsis", nullable = false, columnDefinition = "TEXT")
56-
private String synopsis;
52+
@Column(name = "author", nullable = false)
53+
private String author;
5754

58-
@Column(name = "author", nullable = false)
59-
private String author;
55+
// Soft delete - makes DELETE operations idempotent (safe to repeat)
56+
// Using @Builder.Default to ensure the builder respects this initialization
57+
// if the field is not set explicitly.
58+
@Column(name = "deleted", nullable = false)
59+
@Builder.Default
60+
private boolean deleted = false;
6061

61-
// Soft delete - makes DELETE operations idempotent (safe to repeat)
62-
// Using @Builder.Default to ensure the builder respects this initialization
63-
// if the field is not set explicitly.
64-
@Column(name = "deleted", nullable = false)
65-
@Builder.Default
66-
private boolean deleted = false;
62+
// `createdAt` is null upon object creation.
63+
// It will be set by the `onCreate()` method right before persistence.
64+
@Column(name = "created_at", nullable = false, updatable = false)
65+
private Instant createdAt;
6766

68-
// `createdAt` is null upon object creation.
69-
// It will be set by the `onCreate()` method right before persistence.
70-
@Column(name = "created_at", nullable = false, updatable = false)
71-
private Instant createdAt;
67+
@Column(name = "modified_at")
68+
private Instant modifiedAt;
7269

73-
@Column(name = "modified_at")
74-
private Instant modifiedAt;
70+
// --- JPA lifecycle callbacks ---
7571

76-
// --- JPA lifecycle callbacks ---
77-
/**
78-
* Sets createdAt before persisting a new Book record.
79-
*/
80-
@PrePersist
81-
protected void onCreate() {
82-
this.createdAt = Instant.now();
83-
}
72+
/**
73+
* Sets createdAt before persisting a new Book record.
74+
*/
75+
@PrePersist
76+
protected void onCreate() {
77+
this.createdAt = Instant.now();
78+
}
8479

85-
// --- Business Logic Helper ---
86-
// HMCTS requires business logic to live in services; setter hooks are allowed.
87-
// Lifecycle callback: runs automatically before Hibernate updates a database record.
80+
// --- Business Logic Helper ---
81+
// HMCTS requires business logic to live in services; setter hooks are allowed.
82+
// Lifecycle callback: runs automatically before Hibernate updates a database record.
8883

89-
/**
90-
* Updates modifiedAt before updating an existing Book record.
91-
*/
92-
@PreUpdate
93-
protected void onUpdate() {
94-
this.modifiedAt = Instant.now();
95-
}
84+
/**
85+
* Updates modifiedAt before updating an existing Book record.
86+
*/
87+
@PreUpdate
88+
protected void onUpdate() {
89+
this.modifiedAt = Instant.now();
90+
}
9691
}
Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
11
package com.codesungrape.hmcts.bookapi.repository;
22

33
import com.codesungrape.hmcts.bookapi.entity.Book;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
47
import java.util.List;
58
import java.util.Optional;
69
import java.util.UUID;
7-
import org.springframework.data.jpa.repository.JpaRepository;
8-
import org.springframework.stereotype.Repository;
910

1011
/**
11-
* Repository interface for Book entities.
12-
* Provides CRUD operations and custom queries for non-deleted books.
13-
* Spring Data JPA automatically implements this interface at runtime.
12+
* Repository interface for Book entities. Provides CRUD operations and custom queries for
13+
* non-deleted books. Spring Data JPA automatically implements this interface at runtime.
1414
*/
1515
@Repository
1616
public interface BookRepository extends JpaRepository<Book, UUID> {
1717

18-
/**
19-
* Custom query retrieves all Book records that have not been soft-deleted.
20-
*/
21-
List<Book> findAllByDeletedFalse();
22-
23-
/**
24-
* Retrieves a single Book by ID, if it exists and has not been soft-deleted.
25-
*/
26-
Optional<Book> findByIdAndDeletedFalse(UUID id);
18+
/**
19+
* Custom query retrieves all Book records that have not been soft-deleted.
20+
*/
21+
List<Book> findAllByDeletedFalse();
2722

28-
}
23+
/**
24+
* Retrieves a single Book by ID, if it exists and has not been soft-deleted.
25+
*/
26+
Optional<Book> findByIdAndDeletedFalse(UUID id);
27+
}

src/main/java/com/codesungrape/hmcts/bookapi/service/BookService.java

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,47 +13,46 @@
1313
@RequiredArgsConstructor // Lombok creates constructor for dependency injection
1414
public class BookService {
1515

16-
// Create a field to store the repo
17-
private final BookRepository bookRepository;
18-
19-
/**
20-
* Creates a new Book entity from the given BookRequest DTO and persists it.
21-
*
22-
* @param request DTO containing book details (title, author, synopsis)
23-
* @return The saved Book entity
24-
* @throws NullPointerException if request is null
25-
* @throws IllegalArgumentException if title is null or blank
26-
* @throws IllegalStateException if the repository fails to save the book
27-
*/
28-
29-
public Book createBook(BookRequest request) {
30-
// Validation check for business rules (e.g., uniqueness, if required)
31-
if (request == null) {
32-
throw new NullPointerException("BookRequest cannot be null");
16+
// Create a field to store the repo
17+
private final BookRepository bookRepository;
18+
19+
/**
20+
* Creates a new Book entity from the given BookRequest DTO and persists it.
21+
*
22+
* @param request DTO containing book details (title, author, synopsis)
23+
* @return The saved Book entity
24+
* @throws NullPointerException if request is null
25+
* @throws IllegalArgumentException if title is null or blank
26+
* @throws IllegalStateException if the repository fails to save the book
27+
*/
28+
public Book createBook(BookRequest request) {
29+
// Validation check for business rules (e.g., uniqueness, if required)
30+
if (request == null) {
31+
throw new NullPointerException("BookRequest cannot be null");
32+
}
33+
34+
// TODO: Leaving this here for now as i haven't implemented the Controller Layer yet
35+
// The service layer is duplicating validation that already exists in the
36+
// BookRequest DTO with @notblank annotations. Since the DTO has validation
37+
// constraints, this manual check is redundant when Spring's validation
38+
// framework is properly configured in the controller layer.
39+
// Consider removing this duplication or adding a comment explaining
40+
// why service-level validation is necessary in addition to DTO validation.
41+
if (request.title() == null || request.title().isBlank()) {
42+
throw new IllegalArgumentException("Book title cannot be null or blank");
43+
}
44+
45+
// Map DTO to Entity
46+
Book newBook =
47+
Book.builder()
48+
.title(request.title())
49+
.author(request.author())
50+
.synopsis(request.synopsis())
51+
// ID and created_at are auto-generated by JPA/DB
52+
.build();
53+
54+
Book savedBook = bookRepository.save(newBook);
55+
56+
return savedBook;
3357
}
34-
35-
36-
// TODO: Leaving this here for now as i haven't implemented the Controller Layer yet
37-
// The service layer is duplicating validation that already exists in the
38-
// BookRequest DTO with @notblank annotations. Since the DTO has validation
39-
// constraints, this manual check is redundant when Spring's validation
40-
// framework is properly configured in the controller layer.
41-
// Consider removing this duplication or adding a comment explaining
42-
// why service-level validation is necessary in addition to DTO validation.
43-
if (request.title() == null || request.title().isBlank()) {
44-
throw new IllegalArgumentException("Book title cannot be null or blank");
45-
}
46-
47-
// Map DTO to Entity
48-
Book newBook = Book.builder()
49-
.title(request.title())
50-
.author(request.author())
51-
.synopsis(request.synopsis())
52-
// ID and created_at are auto-generated by JPA/DB
53-
.build();
54-
55-
Book savedBook = bookRepository.save(newBook);
56-
57-
return savedBook;
58-
}
59-
}
58+
}

0 commit comments

Comments
 (0)