Skip to content

Commit 1847080

Browse files
authored
Merge pull request #295 from Rajshri-Firke/feature/pet-birthdate-validation
fix : Missing business validation on pet birthDate (future or unrealistic dates allowed)
2 parents c2cdc05 + 13789d0 commit 1847080

File tree

5 files changed

+123
-4
lines changed

5 files changed

+123
-4
lines changed

src/main/java/org/springframework/samples/petclinic/rest/controller/OwnerRestController.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.samples.petclinic.rest.controller;
1818

19+
import java.util.Collection;
20+
import java.util.List;
21+
1922
import org.springframework.http.HttpHeaders;
2023
import org.springframework.http.HttpStatus;
2124
import org.springframework.http.ResponseEntity;
@@ -26,7 +29,12 @@
2629
import org.springframework.samples.petclinic.model.Pet;
2730
import org.springframework.samples.petclinic.model.Visit;
2831
import org.springframework.samples.petclinic.rest.api.OwnersApi;
29-
import org.springframework.samples.petclinic.rest.dto.*;
32+
import org.springframework.samples.petclinic.rest.dto.OwnerDto;
33+
import org.springframework.samples.petclinic.rest.dto.OwnerFieldsDto;
34+
import org.springframework.samples.petclinic.rest.dto.PetDto;
35+
import org.springframework.samples.petclinic.rest.dto.PetFieldsDto;
36+
import org.springframework.samples.petclinic.rest.dto.VisitDto;
37+
import org.springframework.samples.petclinic.rest.dto.VisitFieldsDto;
3038
import org.springframework.samples.petclinic.service.ClinicService;
3139
import org.springframework.security.access.prepost.PreAuthorize;
3240
import org.springframework.web.bind.annotation.CrossOrigin;
@@ -36,9 +44,6 @@
3644

3745
import jakarta.transaction.Transactional;
3846

39-
import java.util.Collection;
40-
import java.util.List;
41-
4247
/**
4348
* @author Vitaliy Fedoriv
4449
*/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.springframework.samples.petclinic.rest.validation;
2+
3+
import jakarta.validation.Constraint;
4+
import jakarta.validation.Payload;
5+
import java.lang.annotation.*;
6+
7+
@Target({ ElementType.FIELD })
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Constraint(validatedBy = PetAgeValidator.class)
10+
@Documented
11+
public @interface PetAgeValidation {
12+
13+
String message() default "Birth date must not be in the future or older than 50 years";
14+
15+
Class<?>[] groups() default {};
16+
17+
Class<? extends Payload>[] payload() default {};
18+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.springframework.samples.petclinic.rest.validation;
2+
3+
import java.time.LocalDate;
4+
5+
import jakarta.validation.ConstraintValidator;
6+
import jakarta.validation.ConstraintValidatorContext;
7+
8+
public class PetAgeValidator implements ConstraintValidator<PetAgeValidation, LocalDate> {
9+
10+
@Override
11+
public boolean isValid(LocalDate birthDate, ConstraintValidatorContext context) {
12+
13+
if (birthDate == null) {
14+
return true;
15+
}
16+
17+
LocalDate today = LocalDate.now();
18+
19+
if (birthDate.isAfter(today)) {
20+
context.disableDefaultConstraintViolation();
21+
context.buildConstraintViolationWithTemplate(
22+
"Birth date cannot be in the future"
23+
).addConstraintViolation();
24+
return false;
25+
}
26+
27+
if (birthDate.isBefore(today.minusYears(50))) {
28+
context.disableDefaultConstraintViolation();
29+
context.buildConstraintViolationWithTemplate(
30+
"Birth date cannot be older than 50 years"
31+
).addConstraintViolation();
32+
return false;
33+
}
34+
35+
return true;
36+
}
37+
}

src/main/resources/openapi.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1953,6 +1953,7 @@ components:
19531953
type: string
19541954
format: date
19551955
example: '2010-09-07'
1956+
x-field-extra-annotation: "@org.springframework.samples.petclinic.rest.validation.PetAgeValidation"
19561957
type:
19571958
$ref: '#/components/schemas/PetType'
19581959
required:
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.springframework.validation;
2+
3+
import jakarta.validation.ConstraintValidatorContext;
4+
import org.junit.jupiter.api.Test;
5+
import org.mockito.Mockito;
6+
import org.springframework.samples.petclinic.rest.validation.PetAgeValidator;
7+
8+
import java.time.LocalDate;
9+
10+
import static org.junit.jupiter.api.Assertions.*;
11+
import static org.mockito.Mockito.*;
12+
13+
class PetAgeValidatorTest {
14+
15+
private final PetAgeValidator validator = new PetAgeValidator();
16+
17+
@Test
18+
void shouldReturnFalseWhenBirthDateIsInFuture() {
19+
LocalDate futureDate = LocalDate.now().plusDays(1);
20+
21+
ConstraintValidatorContext context = mock(ConstraintValidatorContext.class);
22+
when(context.buildConstraintViolationWithTemplate(anyString()))
23+
.thenReturn(mock(ConstraintValidatorContext.ConstraintViolationBuilder.class));
24+
25+
boolean result = validator.isValid(futureDate, context);
26+
27+
assertFalse(result);
28+
}
29+
30+
@Test
31+
void shouldReturnFalseWhenBirthDateIsOlderThan50Years() {
32+
LocalDate tooOldDate = LocalDate.now().minusYears(51);
33+
34+
ConstraintValidatorContext context = mock(ConstraintValidatorContext.class);
35+
when(context.buildConstraintViolationWithTemplate(anyString()))
36+
.thenReturn(mock(ConstraintValidatorContext.ConstraintViolationBuilder.class));
37+
38+
boolean result = validator.isValid(tooOldDate, context);
39+
40+
assertFalse(result);
41+
}
42+
43+
@Test
44+
void shouldReturnTrueWhenBirthDateIsValid() {
45+
LocalDate validDate = LocalDate.now().minusYears(10);
46+
47+
boolean result = validator.isValid(validDate, null);
48+
49+
assertTrue(result);
50+
}
51+
52+
@Test
53+
void shouldReturnTrueWhenBirthDateIsNull() {
54+
boolean result = validator.isValid(null, null);
55+
56+
assertTrue(result);
57+
}
58+
}

0 commit comments

Comments
 (0)