Skip to content

Commit f4c0742

Browse files
refactor: consolidate validation logic into AssertUtil across domain and DTOs
1 parent d025e04 commit f4c0742

18 files changed

Lines changed: 182 additions & 154 deletions

File tree

meetup4j-modulith-ddd-ha/src/main/java/dev/sivalabs/meetup4j/events/domain/model/Event.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,27 @@ public Event(EventId id,
3333
Capacity capacity,
3434
EventLocation location,
3535
int registrationsCount) {
36-
this.id = AssertUtil.requireNotNull(id, "Event ID cannot be null");
37-
this.code = AssertUtil.requireNotNull(code, "Event code cannot be null");
38-
this.details = AssertUtil.requireNotNull(details, "Event details cannot be null");
39-
this.schedule = AssertUtil.requireNotNull(schedule, "Event schedule cannot be null");
40-
this.type = AssertUtil.requireNotNull(type, "Event type cannot be null");
41-
this.status = AssertUtil.requireNotNull(eventStatus, "Event status cannot be null");
42-
this.ticketPrice = AssertUtil.requireNotNull(ticketPrice, "Event ticket price cannot be null");
43-
this.capacity = AssertUtil.requireNotNull(capacity, "Event capacity cannot be null");
44-
this.location = AssertUtil.requireNotNull(location, "Event location cannot be null");
45-
this.registrationsCount = AssertUtil.requireMin(registrationsCount, 0, "Event registrations count cannot be negative");
36+
AssertUtil.requireNotNull(id, "Event ID cannot be null");
37+
AssertUtil.requireNotNull(code, "Event code cannot be null");
38+
AssertUtil.requireNotNull(details, "Event details cannot be null");
39+
AssertUtil.requireNotNull(schedule, "Event schedule cannot be null");
40+
AssertUtil.requireNotNull(type, "Event type cannot be null");
41+
AssertUtil.requireNotNull(eventStatus, "Event status cannot be null");
42+
AssertUtil.requireNotNull(ticketPrice, "Event ticket price cannot be null");
43+
AssertUtil.requireNotNull(capacity, "Event capacity cannot be null");
44+
AssertUtil.requireNotNull(location, "Event location cannot be null");
45+
AssertUtil.requireMin(registrationsCount, 0, "Event registrations count cannot be negative");
46+
47+
this.id = id;
48+
this.code = code;
49+
this.details = details;
50+
this.schedule = schedule;
51+
this.type = type;
52+
this.status = eventStatus;
53+
this.ticketPrice = ticketPrice;
54+
this.capacity = capacity;
55+
this.location = location;
56+
this.registrationsCount = registrationsCount;
4657
}
4758

4859
public static Event createDraft(

meetup4j-modulith-ddd-ha/src/main/java/dev/sivalabs/meetup4j/events/domain/vo/Capacity.java

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
package dev.sivalabs.meetup4j.events.domain.vo;
22

3-
import com.fasterxml.jackson.annotation.JsonCreator;
4-
import com.fasterxml.jackson.annotation.JsonValue;
5-
import jakarta.validation.constraints.Max;
6-
import jakarta.validation.constraints.Positive;
3+
import dev.sivalabs.meetup4j.shared.AssertUtil;
74

8-
public record Capacity(
9-
@JsonValue
10-
@Positive(message = "Capacity must be positive")
11-
@Max(value = 10000, message = "Capacity cannot exceed 10000")
12-
Integer value) {
5+
public record Capacity(Integer value) {
136
public static final Capacity UNLIMITED = new Capacity(null);
147

15-
@JsonCreator
168
public Capacity {
17-
if (value != null && value < 0) {
18-
throw new IllegalArgumentException("Capacity cannot be negative");
9+
if(value != null) {
10+
AssertUtil.requireSize(value, 0, 10000, "Capacity");
1911
}
2012
}
2113

meetup4j-modulith-ddd-ha/src/main/java/dev/sivalabs/meetup4j/events/domain/vo/EventCode.java

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
package dev.sivalabs.meetup4j.events.domain.vo;
22

3-
import com.fasterxml.jackson.annotation.JsonCreator;
4-
import com.fasterxml.jackson.annotation.JsonValue;
3+
import dev.sivalabs.meetup4j.shared.AssertUtil;
54
import dev.sivalabs.meetup4j.shared.TSIDUtil;
6-
import jakarta.validation.constraints.NotBlank;
75

8-
public record EventCode(@JsonValue
9-
@NotBlank(message = "Event code cannot be empty")
10-
String code) {
11-
@JsonCreator
6+
public record EventCode(String code) {
7+
128
public EventCode {
13-
if (code == null || code.trim().isEmpty()) {
14-
throw new IllegalArgumentException("Event code cannot be empty");
15-
}
9+
AssertUtil.requireNotBlank(code, "Event code");
1610
}
1711

1812
public static EventCode of(String code) {

meetup4j-modulith-ddd-ha/src/main/java/dev/sivalabs/meetup4j/events/domain/vo/EventDetails.java

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,19 @@
11
package dev.sivalabs.meetup4j.events.domain.vo;
22

3-
import com.fasterxml.jackson.annotation.JsonCreator;
4-
import com.fasterxml.jackson.annotation.JsonProperty;
5-
import jakarta.validation.constraints.NotBlank;
6-
import jakarta.validation.constraints.Pattern;
7-
import jakarta.validation.constraints.Size;
8-
9-
import static dev.sivalabs.meetup4j.shared.AssertUtil.requireNotNull;
3+
import dev.sivalabs.meetup4j.shared.AssertUtil;
104

115
public record EventDetails(
12-
@NotBlank(message = "Title is required")
13-
@Size(min = 3, max = 200, message = "Title must be between 3 and 200 characters")
146
String title,
15-
16-
@NotBlank(message = "Description is required")
17-
@Size(max = 10000, message = "Description cannot exceed 10000 characters")
187
String description,
19-
20-
@Size(max = 500, message = "Image URL cannot exceed 500 characters")
21-
@Pattern(regexp = "^https?://.*", message = "Image URL must be a valid HTTP/HTTPS URL")
228
String imageUrl) {
239

24-
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
25-
public EventDetails(
26-
@JsonProperty("title") String title,
27-
@JsonProperty("description") String description,
28-
@JsonProperty("imageUrl") String imageUrl
29-
) {
30-
this.title = requireNotNull(title, "title cannot be null");
31-
this.description = requireNotNull(description, "description cannot be null");
32-
this.imageUrl = imageUrl;
10+
public EventDetails {
11+
AssertUtil.requireNotNull(title, "title cannot be null");
12+
AssertUtil.requireSize(title, 3, 200, "title");
13+
AssertUtil.requireNotNull(description, "description cannot be null");
14+
AssertUtil.requireSize(description, 1, 10000, "description");
15+
AssertUtil.requireSize(imageUrl, 1, 500, "imageUrl");
16+
AssertUtil.requirePattern(imageUrl, "^https?://.*", "Image URL must be a valid HTTP/HTTPS URL");
3317
}
3418

3519
public static EventDetails of(String title, String description, String imageUrl) {

meetup4j-modulith-ddd-ha/src/main/java/dev/sivalabs/meetup4j/events/domain/vo/EventId.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package dev.sivalabs.meetup4j.events.domain.vo;
22

3+
import dev.sivalabs.meetup4j.shared.AssertUtil;
34
import dev.sivalabs.meetup4j.shared.TSIDUtil;
45

56
public record EventId(Long id) {
67
public EventId {
7-
if (id == null || id < 0) {
8-
throw new IllegalArgumentException("Event id cannot be null");
9-
}
8+
AssertUtil.requireNotNull(id, "Event id");
9+
AssertUtil.requireMin(id, 0, "Event id cannot be negative");
1010
}
1111

1212
public static EventId of(Long id) {

meetup4j-modulith-ddd-ha/src/main/java/dev/sivalabs/meetup4j/events/domain/vo/EventLocation.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,10 @@
11
package dev.sivalabs.meetup4j.events.domain.vo;
22

3-
import com.fasterxml.jackson.annotation.JsonCreator;
4-
import com.fasterxml.jackson.annotation.JsonProperty;
5-
63
public record EventLocation(
74
String venue,
85
String virtualLink) {
96

10-
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
11-
public EventLocation(
12-
@JsonProperty("venue") String venue,
13-
@JsonProperty("virtualLink") String virtualLink
14-
) {
15-
this.venue = venue;
16-
this.virtualLink = virtualLink;
17-
7+
public EventLocation {
188
if (venue == null && virtualLink == null) {
199
throw new IllegalArgumentException("Either venue or virtualLink must be provided");
2010
}

meetup4j-modulith-ddd-ha/src/main/java/dev/sivalabs/meetup4j/events/domain/vo/Schedule.java

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,19 @@
11
package dev.sivalabs.meetup4j.events.domain.vo;
22

3-
import com.fasterxml.jackson.annotation.JsonCreator;
4-
import com.fasterxml.jackson.annotation.JsonProperty;
5-
import jakarta.validation.constraints.NotNull;
3+
import dev.sivalabs.meetup4j.shared.AssertUtil;
64

75
import java.time.Instant;
86

97
public record Schedule(
10-
@NotNull(message = "Start datetime is required")
118
Instant startDatetime,
12-
@NotNull(message = "End datetime is required")
139
Instant endDatetime) {
1410

15-
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
16-
public Schedule(
17-
@JsonProperty("startDatetime") Instant startDatetime,
18-
@JsonProperty("endDatetime") Instant endDatetime
19-
) {
20-
if (startDatetime == null || endDatetime == null) {
21-
throw new IllegalArgumentException("Start and end datetime cannot be null");
22-
}
11+
public Schedule {
12+
AssertUtil.requireNotNull(startDatetime, "Start datetime cannot be null");
13+
AssertUtil.requireNotNull(endDatetime, "End datetime cannot be null");
2314
if (endDatetime.isBefore(startDatetime)) {
2415
throw new IllegalArgumentException("End datetime cannot be before start datetime");
2516
}
26-
this.startDatetime = startDatetime;
27-
this.endDatetime = endDatetime;
2817
}
2918

3019
public static Schedule of(Instant startDatetime, Instant endDatetime) {

meetup4j-modulith-ddd-ha/src/main/java/dev/sivalabs/meetup4j/events/domain/vo/TicketPrice.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
11
package dev.sivalabs.meetup4j.events.domain.vo;
22

3-
import com.fasterxml.jackson.annotation.JsonCreator;
4-
import com.fasterxml.jackson.annotation.JsonValue;
5-
import jakarta.validation.constraints.DecimalMin;
3+
import dev.sivalabs.meetup4j.shared.AssertUtil;
64

75
import java.math.BigDecimal;
86

9-
public record TicketPrice(
10-
@JsonValue
11-
@DecimalMin(value = "0.0", message = "Ticket price must be non-negative")
12-
BigDecimal amount) {
7+
public record TicketPrice(BigDecimal amount) {
138
public static final TicketPrice FREE = TicketPrice.of(BigDecimal.ZERO);
149

15-
@JsonCreator
1610
public TicketPrice {
17-
if (amount == null) {
18-
throw new IllegalArgumentException("Ticket price cannot be null");
19-
}
11+
AssertUtil.requireNotNull(amount, "Ticket price cannot be null");
2012
if (amount.compareTo(BigDecimal.ZERO) < 0) {
2113
throw new IllegalArgumentException("Ticket price cannot be negative");
2214
}
Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,41 @@
11
package dev.sivalabs.meetup4j.events.interfaces.rest;
22

3-
import com.fasterxml.jackson.annotation.JsonUnwrapped;
43
import dev.sivalabs.meetup4j.events.domain.model.EventType;
5-
import dev.sivalabs.meetup4j.events.domain.vo.*;
6-
import jakarta.validation.Valid;
7-
import jakarta.validation.constraints.NotNull;
4+
import jakarta.validation.constraints.*;
5+
6+
import java.math.BigDecimal;
7+
import java.time.Instant;
88

99
record CreateEventRequest(
10-
@JsonUnwrapped
11-
@Valid
12-
EventDetails details,
10+
@NotBlank(message = "Title is required")
11+
@Size(min = 3, max = 200, message = "Title must be between 3 and 200 characters")
12+
String title,
13+
14+
@NotBlank(message = "Description is required")
15+
@Size(max = 10000, message = "Description cannot exceed 10000 characters")
16+
String description,
17+
18+
@Size(max = 500, message = "Image URL cannot exceed 500 characters")
19+
@Pattern(regexp = "^https?://.*", message = "Image URL must be a valid HTTP/HTTPS URL")
20+
String imageUrl,
21+
22+
@NotNull(message = "Start datetime is required")
23+
Instant startDatetime,
1324

14-
@JsonUnwrapped
15-
@Valid
16-
Schedule schedule,
25+
@NotNull(message = "End datetime is required")
26+
Instant endDatetime,
1727

1828
@NotNull(message = "Event type is required")
1929
EventType type,
2030

21-
@Valid TicketPrice ticketPrice,
31+
@DecimalMin(value = "0.0", message = "Ticket price must be non-negative")
32+
BigDecimal ticketPrice,
2233

23-
@Valid Capacity capacity,
34+
@Positive(message = "Capacity must be positive")
35+
@Max(value = 10000, message = "Capacity cannot exceed 10000")
36+
Integer capacity,
2437

25-
@JsonUnwrapped
26-
@Valid
27-
EventLocation location) {
38+
String venue,
39+
String virtualLink
40+
) {
2841
}

meetup4j-modulith-ddd-ha/src/main/java/dev/sivalabs/meetup4j/events/interfaces/rest/EventsController.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import dev.sivalabs.meetup4j.events.application.command.dto.PublishEventCmd;
99
import dev.sivalabs.meetup4j.events.application.query.EventQueryService;
1010
import dev.sivalabs.meetup4j.events.application.query.dto.EventVM;
11-
import dev.sivalabs.meetup4j.events.domain.vo.EventCode;
11+
import dev.sivalabs.meetup4j.events.domain.vo.*;
1212
import jakarta.validation.Valid;
1313
import org.slf4j.Logger;
1414
import org.slf4j.LoggerFactory;
@@ -56,12 +56,12 @@ ResponseEntity<EventVM> findEventByCode(@PathVariable EventCode eventCode) {
5656
@PostMapping
5757
ResponseEntity<CreateEventResponse> createEvent(@RequestBody @Valid CreateEventRequest request) {
5858
var cmd = new CreateEventCmd(
59-
request.details(),
60-
request.schedule(),
59+
EventDetails.of(request.title(), request.description(), request.imageUrl()),
60+
Schedule.of(request.startDatetime(), request.endDatetime()),
6161
request.type(),
62-
request.ticketPrice(),
63-
request.capacity(),
64-
request.location()
62+
TicketPrice.of(request.ticketPrice()),
63+
Capacity.of(request.capacity()),
64+
EventLocation.of(request.venue(), request.virtualLink())
6565
);
6666
EventCode eventCode = createEventUseCase.createEvent(cmd);
6767
log.info("Event created with code: {}", eventCode);

0 commit comments

Comments
 (0)