Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,21 @@ public void addVisit(Integer petId, Visit visit) {
pet.addVisit(visit);
}

/**
* Adds the given {@link Vaccine} to the {@link Pet} with the given identifier.
* @param petId the identifier of the {@link Pet}, must not be {@literal null}.
* @param vaccine the vaccine to add, must not be {@literal null}.
*/
public void addVaccine(Integer petId, Vaccine vaccine) {

Assert.notNull(petId, "Pet identifier must not be null!");
Assert.notNull(vaccine, "Vaccine must not be null!");

Pet pet = getPet(petId);

Assert.notNull(pet, "Invalid Pet identifier!");

pet.addVaccine(vaccine);
}

}
13 changes: 13 additions & 0 deletions src/main/java/org/springframework/samples/petclinic/owner/Pet.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ public class Pet extends NamedEntity {
@OrderBy("date ASC")
private final Set<Visit> visits = new LinkedHashSet<>();

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you change to EAGER fetch loading?

@JoinColumn(name = "pet_id")
@OrderBy("vaccinationDate DESC")
private final Set<Vaccine> vaccines = new LinkedHashSet<>();

public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
Expand All @@ -82,4 +87,12 @@ public void addVisit(Visit visit) {
getVisits().add(visit);
}

public Collection<Vaccine> getVaccines() {
return this.vaccines;
}

public void addVaccine(Vaccine vaccine) {
getVaccines().add(vaccine);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.owner;

import java.time.LocalDate;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.samples.petclinic.model.BaseEntity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotBlank;

/**
* Simple JavaBean domain object representing a vaccine record.
*
* @author Spring PetClinic
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need author?
Is it in git, so just can use git blame.

*/
@Entity
@Table(name = "vaccines")
public class Vaccine extends BaseEntity {

@Column(name = "vaccine_name")
@NotBlank
private String name;

@Column(name = "vaccination_date")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate vaccinationDate;

@Column(name = "next_reminder_date")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate nextReminderDate;

/**
* Creates a new instance of Vaccine for the current date
*/
public Vaccine() {
this.vaccinationDate = LocalDate.now();
}

public String getName() {
return this.name;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not to use Lombok?

}

public void setName(String name) {
this.name = name;
}

public LocalDate getVaccinationDate() {
return this.vaccinationDate;
}

public void setVaccinationDate(LocalDate vaccinationDate) {
this.vaccinationDate = vaccinationDate;
}

public LocalDate getNextReminderDate() {
return this.nextReminderDate;
}

public void setNextReminderDate(LocalDate nextReminderDate) {
this.nextReminderDate = nextReminderDate;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.owner;

import java.util.Map;
import java.util.Optional;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import jakarta.validation.Valid;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

/**
* @author Spring PetClinic
*/
@Controller
class VaccineController {

private final OwnerRepository owners;

public VaccineController(OwnerRepository owners) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use Lombok

this.owners = owners;
}

@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}

/**
* Called before each and every @RequestMapping annotated method. 2 goals: - Make sure
* we always have fresh data - Since we do not use the session scope, make sure that
* Pet object always has an id (Even though id is not part of the form fields)
* @param petId
* @return Pet
*/
@ModelAttribute("vaccine")
public Vaccine loadPetWithVaccine(@PathVariable("ownerId") int ownerId, @PathVariable("petId") int petId,
Map<String, Object> model) {
Optional<Owner> optionalOwner = owners.findById(ownerId);
Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException(
"Owner not found with id: " + ownerId + ". Please ensure the ID is correct "));

Pet pet = owner.getPet(petId);
if (pet == null) {
throw new IllegalArgumentException(
"Pet with id " + petId + " not found for owner with id " + ownerId + ".");
}
model.put("pet", pet);
model.put("owner", owner);

Vaccine vaccine = new Vaccine();
pet.addVaccine(vaccine);
return vaccine;
}

// Spring MVC calls method loadPetWithVaccine(...) before initNewVaccineForm is
// called
@GetMapping("/owners/{ownerId}/pets/{petId}/vaccines/new")
public String initNewVaccineForm() {
return "pets/createOrUpdateVaccineForm";
}

// Spring MVC calls method loadPetWithVaccine(...) before processNewVaccineForm is
// called
@PostMapping("/owners/{ownerId}/pets/{petId}/vaccines/new")
public String processNewVaccineForm(@ModelAttribute Owner owner, @PathVariable int petId, @Valid Vaccine vaccine,
BindingResult result, RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "pets/createOrUpdateVaccineForm";
}

owner.addVaccine(petId, vaccine);
this.owners.save(owner);
redirectAttributes.addFlashAttribute("message", "Vaccine record has been added");
return "redirect:/owners/{ownerId}";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.owner;

import org.springframework.data.jpa.repository.JpaRepository;

/**
* Repository class for <code>Vaccine</code> domain objects. All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring
* Data.
*
* @author Spring PetClinic
*/
public interface VaccineRepository extends JpaRepository<Vaccine, Integer> {

}