Apply spring-format plugin

This commit is contained in:
Dave Syer 2020-01-03 11:22:05 +00:00
parent 82cb521d63
commit 4e1f87407d
36 changed files with 1128 additions and 1168 deletions

View file

@ -28,8 +28,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(proxyBeanMethods = false)
public class PetClinicApplication {
public static void main(String[] args) {
SpringApplication.run(PetClinicApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(PetClinicApplication.class, args);
}
}

View file

@ -31,20 +31,21 @@ import javax.persistence.MappedSuperclass;
*/
@MappedSuperclass
public class BaseEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
public Integer getId() {
return id;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public boolean isNew() {
return this.id == null;
}
public void setId(Integer id) {
this.id = id;
}
public boolean isNew() {
return this.id == null;
}
}

View file

@ -18,10 +18,9 @@ package org.springframework.samples.petclinic.model;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
/**
* Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. Used as a base class for objects
* needing these properties.
* Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. Used as
* a base class for objects needing these properties.
*
* @author Ken Krebs
* @author Juergen Hoeller
@ -29,20 +28,20 @@ import javax.persistence.MappedSuperclass;
@MappedSuperclass
public class NamedEntity extends BaseEntity {
@Column(name = "name")
private String name;
@Column(name = "name")
private String name;
public String getName() {
return this.name;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return this.getName();
}
@Override
public String toString() {
return this.getName();
}
}

View file

@ -27,28 +27,28 @@ import javax.validation.constraints.NotEmpty;
@MappedSuperclass
public class Person extends BaseEntity {
@Column(name = "first_name")
@NotEmpty
private String firstName;
@Column(name = "first_name")
@NotEmpty
private String firstName;
@Column(name = "last_name")
@NotEmpty
private String lastName;
@Column(name = "last_name")
@NotEmpty
private String lastName;
public String getFirstName() {
return this.firstName;
}
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return this.lastName;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}

View file

@ -18,4 +18,3 @@
* The classes in this package represent utilities used by the domain.
*/
package org.springframework.samples.petclinic.model;

View file

@ -45,108 +45,106 @@ import org.springframework.samples.petclinic.model.Person;
@Entity
@Table(name = "owners")
public class Owner extends Person {
@Column(name = "address")
@NotEmpty
private String address;
@Column(name = "city")
@NotEmpty
private String city;
@Column(name = "address")
@NotEmpty
private String address;
@Column(name = "telephone")
@NotEmpty
@Digits(fraction = 0, integer = 10)
private String telephone;
@Column(name = "city")
@NotEmpty
private String city;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
private Set<Pet> pets;
@Column(name = "telephone")
@NotEmpty
@Digits(fraction = 0, integer = 10)
private String telephone;
public String getAddress() {
return this.address;
}
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
private Set<Pet> pets;
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return this.address;
}
public String getCity() {
return this.city;
}
public void setAddress(String address) {
this.address = address;
}
public void setCity(String city) {
this.city = city;
}
public String getCity() {
return this.city;
}
public String getTelephone() {
return this.telephone;
}
public void setCity(String city) {
this.city = city;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getTelephone() {
return this.telephone;
}
protected Set<Pet> getPetsInternal() {
if (this.pets == null) {
this.pets = new HashSet<>();
}
return this.pets;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
protected void setPetsInternal(Set<Pet> pets) {
this.pets = pets;
}
protected Set<Pet> getPetsInternal() {
if (this.pets == null) {
this.pets = new HashSet<>();
}
return this.pets;
}
public List<Pet> getPets() {
List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
PropertyComparator.sort(sortedPets,
new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedPets);
}
protected void setPetsInternal(Set<Pet> pets) {
this.pets = pets;
}
public void addPet(Pet pet) {
if (pet.isNew()) {
getPetsInternal().add(pet);
}
pet.setOwner(this);
}
public List<Pet> getPets() {
List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedPets);
}
/**
* Return the Pet with the given name, or null if none found for this Owner.
*
* @param name to test
* @return true if pet name is already in use
*/
public Pet getPet(String name) {
return getPet(name, false);
}
public void addPet(Pet pet) {
if (pet.isNew()) {
getPetsInternal().add(pet);
}
pet.setOwner(this);
}
/**
* Return the Pet with the given name, or null if none found for this Owner.
*
* @param name to test
* @return true if pet name is already in use
*/
public Pet getPet(String name, boolean ignoreNew) {
name = name.toLowerCase();
for (Pet pet : getPetsInternal()) {
if (!ignoreNew || !pet.isNew()) {
String compName = pet.getName();
compName = compName.toLowerCase();
if (compName.equals(name)) {
return pet;
}
}
}
return null;
}
/**
* Return the Pet with the given name, or null if none found for this Owner.
* @param name to test
* @return true if pet name is already in use
*/
public Pet getPet(String name) {
return getPet(name, false);
}
@Override
public String toString() {
return new ToStringCreator(this)
/**
* Return the Pet with the given name, or null if none found for this Owner.
* @param name to test
* @return true if pet name is already in use
*/
public Pet getPet(String name, boolean ignoreNew) {
name = name.toLowerCase();
for (Pet pet : getPetsInternal()) {
if (!ignoreNew || !pet.isNew()) {
String compName = pet.getName();
compName = compName.toLowerCase();
if (compName.equals(name)) {
return pet;
}
}
}
return null;
}
@Override
public String toString() {
return new ToStringCreator(this)
.append("id", this.getId()).append("new", this.isNew()).append("lastName", this.getLastName())
.append("firstName", this.getFirstName()).append("address", this.address).append("city", this.city)
.append("telephone", this.telephone).toString();
}
.append("id", this.getId()).append("new", this.isNew())
.append("lastName", this.getLastName())
.append("firstName", this.getFirstName()).append("address", this.address)
.append("city", this.city).append("telephone", this.telephone).toString();
}
}

View file

@ -39,102 +39,107 @@ import java.util.Map;
@Controller
class OwnerController {
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
private final OwnerRepository owners;
private VisitRepository visits;
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
private final OwnerRepository owners;
public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
this.owners = clinicService;
this.visits = visits;
}
private VisitRepository visits;
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
this.owners = clinicService;
this.visits = visits;
}
@GetMapping("/owners/new")
public String initCreationForm(Map<String, Object> model) {
Owner owner = new Owner();
model.put("owner", owner);
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
@PostMapping("/owners/new")
public String processCreationForm(@Valid Owner owner, BindingResult result) {
if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} else {
this.owners.save(owner);
return "redirect:/owners/" + owner.getId();
}
}
@GetMapping("/owners/new")
public String initCreationForm(Map<String, Object> model) {
Owner owner = new Owner();
model.put("owner", owner);
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
@GetMapping("/owners/find")
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
return "owners/findOwners";
}
@PostMapping("/owners/new")
public String processCreationForm(@Valid Owner owner, BindingResult result) {
if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
else {
this.owners.save(owner);
return "redirect:/owners/" + owner.getId();
}
}
@GetMapping("/owners")
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
@GetMapping("/owners/find")
public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner());
return "owners/findOwners";
}
// allow parameterless GET request for /owners to return all records
if (owner.getLastName() == null) {
owner.setLastName(""); // empty string signifies broadest possible search
}
@GetMapping("/owners")
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
// find owners by last name
Collection<Owner> results = this.owners.findByLastName(owner.getLastName());
if (results.isEmpty()) {
// no owners found
result.rejectValue("lastName", "notFound", "not found");
return "owners/findOwners";
} else if (results.size() == 1) {
// 1 owner found
owner = results.iterator().next();
return "redirect:/owners/" + owner.getId();
} else {
// multiple owners found
model.put("selections", results);
return "owners/ownersList";
}
}
// allow parameterless GET request for /owners to return all records
if (owner.getLastName() == null) {
owner.setLastName(""); // empty string signifies broadest possible search
}
@GetMapping("/owners/{ownerId}/edit")
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
Owner owner = this.owners.findById(ownerId);
model.addAttribute(owner);
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
// find owners by last name
Collection<Owner> results = this.owners.findByLastName(owner.getLastName());
if (results.isEmpty()) {
// no owners found
result.rejectValue("lastName", "notFound", "not found");
return "owners/findOwners";
}
else if (results.size() == 1) {
// 1 owner found
owner = results.iterator().next();
return "redirect:/owners/" + owner.getId();
}
else {
// multiple owners found
model.put("selections", results);
return "owners/ownersList";
}
}
@PostMapping("/owners/{ownerId}/edit")
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @PathVariable("ownerId") int ownerId) {
if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} else {
owner.setId(ownerId);
this.owners.save(owner);
return "redirect:/owners/{ownerId}";
}
}
@GetMapping("/owners/{ownerId}/edit")
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
Owner owner = this.owners.findById(ownerId);
model.addAttribute(owner);
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
/**
* Custom handler for displaying an owner.
*
* @param ownerId the ID of the owner to display
* @return a ModelMap with the model attributes for the view
*/
@GetMapping("/owners/{ownerId}")
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
ModelAndView mav = new ModelAndView("owners/ownerDetails");
Owner owner = this.owners.findById(ownerId);
for (Pet pet : owner.getPets()) {
pet.setVisitsInternal(visits.findByPetId(pet.getId()));
}
mav.addObject(owner);
return mav;
}
@PostMapping("/owners/{ownerId}/edit")
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result,
@PathVariable("ownerId") int ownerId) {
if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
else {
owner.setId(ownerId);
this.owners.save(owner);
return "redirect:/owners/{ownerId}";
}
}
/**
* Custom handler for displaying an owner.
* @param ownerId the ID of the owner to display
* @return a ModelMap with the model attributes for the view
*/
@GetMapping("/owners/{ownerId}")
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
ModelAndView mav = new ModelAndView("owners/ownerDetails");
Owner owner = this.owners.findById(ownerId);
for (Pet pet : owner.getPets()) {
pet.setVisitsInternal(visits.findByPetId(pet.getId()));
}
mav.addObject(owner);
return mav;
}
}

View file

@ -23,9 +23,10 @@ import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
/**
* Repository class for <code>Owner</code> domain objects All method names are compliant with Spring Data naming
* conventions so this interface can easily be extended for Spring Data.
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* Repository class for <code>Owner</code> domain objects All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring
* Data. See:
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
*
* @author Ken Krebs
* @author Juergen Hoeller
@ -34,31 +35,30 @@ import org.springframework.transaction.annotation.Transactional;
*/
public interface OwnerRepository extends Repository<Owner, Integer> {
/**
* Retrieve {@link Owner}s from the data store by last name, returning all owners
* whose last name <i>starts</i> with the given name.
* @param lastName Value to search for
* @return a Collection of matching {@link Owner}s (or an empty Collection if none
* found)
*/
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
@Transactional(readOnly = true)
Collection<Owner> findByLastName(@Param("lastName") String lastName);
/**
* Retrieve {@link Owner}s from the data store by last name, returning all owners
* whose last name <i>starts</i> with the given name.
* @param lastName Value to search for
* @return a Collection of matching {@link Owner}s (or an empty Collection if none
* found)
*/
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
@Transactional(readOnly = true)
Collection<Owner> findByLastName(@Param("lastName") String lastName);
/**
* Retrieve an {@link Owner} from the data store by id.
* @param id the id to search for
* @return the {@link Owner} if found
*/
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
@Transactional(readOnly = true)
Owner findById(@Param("id") Integer id);
/**
* Save an {@link Owner} to the data store, either inserting or updating it.
* @param owner the {@link Owner} to save
*/
void save(Owner owner);
/**
* Retrieve an {@link Owner} from the data store by id.
* @param id the id to search for
* @return the {@link Owner} if found
*/
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
@Transactional(readOnly = true)
Owner findById(@Param("id") Integer id);
/**
* Save an {@link Owner} to the data store, either inserting or updating it.
* @param owner the {@link Owner} to save
*/
void save(Owner owner);
}

View file

@ -48,66 +48,65 @@ import org.springframework.samples.petclinic.visit.Visit;
@Table(name = "pets")
public class Pet extends NamedEntity {
@Column(name = "birth_date")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDate;
@Column(name = "birth_date")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDate;
@ManyToOne
@JoinColumn(name = "type_id")
private PetType type;
@ManyToOne
@JoinColumn(name = "type_id")
private PetType type;
@ManyToOne
@JoinColumn(name = "owner_id")
private Owner owner;
@ManyToOne
@JoinColumn(name = "owner_id")
private Owner owner;
@Transient
private Set<Visit> visits = new LinkedHashSet<>();
@Transient
private Set<Visit> visits = new LinkedHashSet<>();
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
public LocalDate getBirthDate() {
return this.birthDate;
}
public LocalDate getBirthDate() {
return this.birthDate;
}
public PetType getType() {
return this.type;
}
public PetType getType() {
return this.type;
}
public void setType(PetType type) {
this.type = type;
}
public void setType(PetType type) {
this.type = type;
}
public Owner getOwner() {
return this.owner;
}
public Owner getOwner() {
return this.owner;
}
protected void setOwner(Owner owner) {
this.owner = owner;
}
protected void setOwner(Owner owner) {
this.owner = owner;
}
protected Set<Visit> getVisitsInternal() {
if (this.visits == null) {
this.visits = new HashSet<>();
}
return this.visits;
}
protected Set<Visit> getVisitsInternal() {
if (this.visits == null) {
this.visits = new HashSet<>();
}
return this.visits;
}
protected void setVisitsInternal(Collection<Visit> visits) {
this.visits = new LinkedHashSet<>(visits);
}
protected void setVisitsInternal(Collection<Visit> visits) {
this.visits = new LinkedHashSet<>(visits);
}
public List<Visit> getVisits() {
List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal());
PropertyComparator.sort(sortedVisits,
new MutableSortDefinition("date", false, false));
return Collections.unmodifiableList(sortedVisits);
}
public List<Visit> getVisits() {
List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal());
PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false));
return Collections.unmodifiableList(sortedVisits);
}
public void addVisit(Visit visit) {
getVisitsInternal().add(visit);
visit.setPetId(this.getId());
}
public void addVisit(Visit visit) {
getVisitsInternal().add(visit);
visit.setPetId(this.getId());
}
}

View file

@ -34,76 +34,80 @@ import java.util.Collection;
@RequestMapping("/owners/{ownerId}")
class PetController {
private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
private final PetRepository pets;
private final OwnerRepository owners;
private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
public PetController(PetRepository pets, OwnerRepository owners) {
this.pets = pets;
this.owners = owners;
}
private final PetRepository pets;
@ModelAttribute("types")
public Collection<PetType> populatePetTypes() {
return this.pets.findPetTypes();
}
private final OwnerRepository owners;
@ModelAttribute("owner")
public Owner findOwner(@PathVariable("ownerId") int ownerId) {
return this.owners.findById(ownerId);
}
public PetController(PetRepository pets, OwnerRepository owners) {
this.pets = pets;
this.owners = owners;
}
@InitBinder("owner")
public void initOwnerBinder(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
@ModelAttribute("types")
public Collection<PetType> populatePetTypes() {
return this.pets.findPetTypes();
}
@InitBinder("pet")
public void initPetBinder(WebDataBinder dataBinder) {
dataBinder.setValidator(new PetValidator());
}
@ModelAttribute("owner")
public Owner findOwner(@PathVariable("ownerId") int ownerId) {
return this.owners.findById(ownerId);
}
@GetMapping("/pets/new")
public String initCreationForm(Owner owner, ModelMap model) {
Pet pet = new Pet();
owner.addPet(pet);
model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
}
@InitBinder("owner")
public void initOwnerBinder(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
@PostMapping("/pets/new")
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) {
if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null){
result.rejectValue("name", "duplicate", "already exists");
}
owner.addPet(pet);
if (result.hasErrors()) {
model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} else {
this.pets.save(pet);
return "redirect:/owners/{ownerId}";
}
}
@InitBinder("pet")
public void initPetBinder(WebDataBinder dataBinder) {
dataBinder.setValidator(new PetValidator());
}
@GetMapping("/pets/{petId}/edit")
public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) {
Pet pet = this.pets.findById(petId);
model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
}
@GetMapping("/pets/new")
public String initCreationForm(Owner owner, ModelMap model) {
Pet pet = new Pet();
owner.addPet(pet);
model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
}
@PostMapping("/pets/{petId}/edit")
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) {
if (result.hasErrors()) {
pet.setOwner(owner);
model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} else {
owner.addPet(pet);
this.pets.save(pet);
return "redirect:/owners/{ownerId}";
}
}
@PostMapping("/pets/new")
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) {
if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) {
result.rejectValue("name", "duplicate", "already exists");
}
owner.addPet(pet);
if (result.hasErrors()) {
model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
}
else {
this.pets.save(pet);
return "redirect:/owners/{ownerId}";
}
}
@GetMapping("/pets/{petId}/edit")
public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) {
Pet pet = this.pets.findById(petId);
model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
}
@PostMapping("/pets/{petId}/edit")
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) {
if (result.hasErrors()) {
pet.setOwner(owner);
model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
}
else {
owner.addPet(pet);
this.pets.save(pet);
return "redirect:/owners/{ownerId}";
}
}
}

View file

@ -22,9 +22,10 @@ import org.springframework.data.repository.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* Repository class for <code>Pet</code> domain objects All method names are compliant with Spring Data naming
* conventions so this interface can easily be extended for Spring Data.
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* Repository class for <code>Pet</code> domain objects All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring
* Data. See:
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
*
* @author Ken Krebs
* @author Juergen Hoeller
@ -33,27 +34,26 @@ import org.springframework.transaction.annotation.Transactional;
*/
public interface PetRepository extends Repository<Pet, Integer> {
/**
* Retrieve all {@link PetType}s from the data store.
* @return a Collection of {@link PetType}s.
*/
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
@Transactional(readOnly = true)
List<PetType> findPetTypes();
/**
* Retrieve all {@link PetType}s from the data store.
* @return a Collection of {@link PetType}s.
*/
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
@Transactional(readOnly = true)
List<PetType> findPetTypes();
/**
* Retrieve a {@link Pet} from the data store by id.
* @param id the id to search for
* @return the {@link Pet} if found
*/
@Transactional(readOnly = true)
Pet findById(Integer id);
/**
* Retrieve a {@link Pet} from the data store by id.
* @param id the id to search for
* @return the {@link Pet} if found
*/
@Transactional(readOnly = true)
Pet findById(Integer id);
/**
* Save a {@link Pet} to the data store, either inserting or updating it.
* @param pet the {@link Pet} to save
*/
void save(Pet pet);
/**
* Save a {@link Pet} to the data store, either inserting or updating it.
* @param pet the {@link Pet} to save
*/
void save(Pet pet);
}

View file

@ -21,8 +21,7 @@ import javax.persistence.Table;
import org.springframework.samples.petclinic.model.NamedEntity;
/**
* @author Juergen Hoeller
* Can be Cat, Dog, Hamster...
* @author Juergen Hoeller Can be Cat, Dog, Hamster...
*/
@Entity
@Table(name = "types")

View file

@ -24,9 +24,10 @@ import org.springframework.format.Formatter;
import org.springframework.stereotype.Component;
/**
* Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting from Spring 3.0, Formatters have
* come as an improvement in comparison to legacy PropertyEditors. See the following links for more details: - The
* Spring ref doc: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format
* Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting
* from Spring 3.0, Formatters have come as an improvement in comparison to legacy
* PropertyEditors. See the following links for more details: - The Spring ref doc:
* https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format
*
* @author Mark Fisher
* @author Juergen Hoeller
@ -35,28 +36,27 @@ import org.springframework.stereotype.Component;
@Component
public class PetTypeFormatter implements Formatter<PetType> {
private final PetRepository pets;
private final PetRepository pets;
@Autowired
public PetTypeFormatter(PetRepository pets) {
this.pets = pets;
}
@Autowired
public PetTypeFormatter(PetRepository pets) {
this.pets = pets;
}
@Override
public String print(PetType petType, Locale locale) {
return petType.getName();
}
@Override
public String print(PetType petType, Locale locale) {
return petType.getName();
}
@Override
public PetType parse(String text, Locale locale) throws ParseException {
Collection<PetType> findPetTypes = this.pets.findPetTypes();
for (PetType type : findPetTypes) {
if (type.getName().equals(text)) {
return type;
}
}
throw new ParseException("type not found: " + text, 0);
}
@Override
public PetType parse(String text, Locale locale) throws ParseException {
Collection<PetType> findPetTypes = this.pets.findPetTypes();
for (PetType type : findPetTypes) {
if (type.getName().equals(text)) {
return type;
}
}
throw new ParseException("type not found: " + text, 0);
}
}

View file

@ -22,7 +22,8 @@ import org.springframework.validation.Validator;
/**
* <code>Validator</code> for <code>Pet</code> forms.
* <p>
* We're not using Bean Validation annotations here because it is easier to define such validation rule in Java.
* We're not using Bean Validation annotations here because it is easier to define such
* validation rule in Java.
* </p>
*
* @author Ken Krebs
@ -30,35 +31,34 @@ import org.springframework.validation.Validator;
*/
public class PetValidator implements Validator {
private static final String REQUIRED = "required";
private static final String REQUIRED = "required";
@Override
public void validate(Object obj, Errors errors) {
Pet pet = (Pet) obj;
String name = pet.getName();
// name validation
if (!StringUtils.hasLength(name)) {
errors.rejectValue("name", REQUIRED, REQUIRED);
}
@Override
public void validate(Object obj, Errors errors) {
Pet pet = (Pet) obj;
String name = pet.getName();
// name validation
if (!StringUtils.hasLength(name)) {
errors.rejectValue("name", REQUIRED, REQUIRED);
}
// type validation
if (pet.isNew() && pet.getType() == null) {
errors.rejectValue("type", REQUIRED, REQUIRED);
}
// type validation
if (pet.isNew() && pet.getType() == null) {
errors.rejectValue("type", REQUIRED, REQUIRED);
}
// birth date validation
if (pet.getBirthDate() == null) {
errors.rejectValue("birthDate", REQUIRED, REQUIRED);
}
}
/**
* This Validator validates *just* Pet instances
*/
@Override
public boolean supports(Class<?> clazz) {
return Pet.class.isAssignableFrom(clazz);
}
// birth date validation
if (pet.getBirthDate() == null) {
errors.rejectValue("birthDate", REQUIRED, REQUIRED);
}
}
/**
* This Validator validates *just* Pet instances
*/
@Override
public boolean supports(Class<?> clazz) {
return Pet.class.isAssignableFrom(clazz);
}
}

View file

@ -40,55 +40,53 @@ import org.springframework.web.bind.annotation.PostMapping;
@Controller
class VisitController {
private final VisitRepository visits;
private final PetRepository pets;
private final VisitRepository visits;
private final PetRepository pets;
public VisitController(VisitRepository visits, PetRepository pets) {
this.visits = visits;
this.pets = pets;
}
public VisitController(VisitRepository visits, PetRepository pets) {
this.visits = visits;
this.pets = pets;
}
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
@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("visit")
public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) {
Pet pet = this.pets.findById(petId);
pet.setVisitsInternal(this.visits.findByPetId(petId));
model.put("pet", pet);
Visit visit = new Visit();
pet.addVisit(visit);
return visit;
}
/**
* 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("visit")
public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) {
Pet pet = this.pets.findById(petId);
pet.setVisitsInternal(this.visits.findByPetId(petId));
model.put("pet", pet);
Visit visit = new Visit();
pet.addVisit(visit);
return visit;
}
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
@GetMapping("/owners/*/pets/{petId}/visits/new")
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
return "pets/createOrUpdateVisitForm";
}
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
@GetMapping("/owners/*/pets/{petId}/visits/new")
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
return "pets/createOrUpdateVisitForm";
}
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
@PostMapping("/owners/{ownerId}/pets/{petId}/visits/new")
public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm";
} else {
this.visits.save(visit);
return "redirect:/owners/{ownerId}";
}
}
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
@PostMapping("/owners/{ownerId}/pets/{petId}/visits/new")
public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm";
}
else {
this.visits.save(visit);
return "redirect:/owners/{ownerId}";
}
}
}

View file

@ -32,24 +32,24 @@ import org.springframework.context.annotation.Configuration;
@EnableCaching
class CacheConfiguration {
@Bean
public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {
return cm -> {
cm.createCache("vets", cacheConfiguration());
};
}
@Bean
public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {
return cm -> {
cm.createCache("vets", cacheConfiguration());
};
}
/**
* Create a simple configuration that enable statistics via the JCache programmatic
* configuration API.
* <p>
* Within the configuration object that is provided by the JCache API standard, there
* is only a very limited set of configuration options. The really relevant
* configuration options (like the size limit) must be set via a configuration
* mechanism that is provided by the selected JCache implementation.
*/
private javax.cache.configuration.Configuration<Object, Object> cacheConfiguration() {
return new MutableConfiguration<>().setStatisticsEnabled(true);
}
/**
* Create a simple configuration that enable statistics via the JCache programmatic
* configuration API.
* <p>
* Within the configuration object that is provided by the JCache API standard, there
* is only a very limited set of configuration options. The really relevant
* configuration options (like the size limit) must be set via a configuration
* mechanism that is provided by the selected JCache implementation.
*/
private javax.cache.configuration.Configuration<Object, Object> cacheConfiguration() {
return new MutableConfiguration<>().setStatisticsEnabled(true);
}
}

View file

@ -28,10 +28,10 @@ import org.springframework.web.bind.annotation.GetMapping;
@Controller
class CrashController {
@GetMapping("/oups")
public String triggerException() {
throw new RuntimeException("Expected: controller used to showcase what "
+ "happens when an exception is thrown");
}
@GetMapping("/oups")
public String triggerException() {
throw new RuntimeException(
"Expected: controller used to showcase what " + "happens when an exception is thrown");
}
}

View file

@ -16,15 +16,15 @@
package org.springframework.samples.petclinic.system;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
class WelcomeController {
@GetMapping("/")
public String welcome() {
return "welcome";
}
@GetMapping("/")
public String welcome() {
return "welcome";
}
}

View file

@ -45,35 +45,35 @@ import org.springframework.samples.petclinic.model.Person;
@Table(name = "vets")
public class Vet extends Person {
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), inverseJoinColumns = @JoinColumn(name = "specialty_id"))
private Set<Specialty> specialties;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"),
inverseJoinColumns = @JoinColumn(name = "specialty_id"))
private Set<Specialty> specialties;
protected Set<Specialty> getSpecialtiesInternal() {
if (this.specialties == null) {
this.specialties = new HashSet<>();
}
return this.specialties;
}
protected Set<Specialty> getSpecialtiesInternal() {
if (this.specialties == null) {
this.specialties = new HashSet<>();
}
return this.specialties;
}
protected void setSpecialtiesInternal(Set<Specialty> specialties) {
this.specialties = specialties;
}
protected void setSpecialtiesInternal(Set<Specialty> specialties) {
this.specialties = specialties;
}
@XmlElement
public List<Specialty> getSpecialties() {
List<Specialty> sortedSpecs = new ArrayList<>(getSpecialtiesInternal());
PropertyComparator.sort(sortedSpecs,
new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedSpecs);
}
@XmlElement
public List<Specialty> getSpecialties() {
List<Specialty> sortedSpecs = new ArrayList<>(getSpecialtiesInternal());
PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedSpecs);
}
public int getNrOfSpecialties() {
return getSpecialtiesInternal().size();
}
public int getNrOfSpecialties() {
return getSpecialtiesInternal().size();
}
public void addSpecialty(Specialty specialty) {
getSpecialtiesInternal().add(specialty);
}
public void addSpecialty(Specialty specialty) {
getSpecialtiesInternal().add(specialty);
}
}

View file

@ -30,29 +30,29 @@ import java.util.Map;
@Controller
class VetController {
private final VetRepository vets;
private final VetRepository vets;
public VetController(VetRepository clinicService) {
this.vets = clinicService;
}
public VetController(VetRepository clinicService) {
this.vets = clinicService;
}
@GetMapping("/vets.html")
public String showVetList(Map<String, Object> model) {
// Here we are returning an object of type 'Vets' rather than a collection of Vet
// objects so it is simpler for Object-Xml mapping
Vets vets = new Vets();
vets.getVetList().addAll(this.vets.findAll());
model.put("vets", vets);
return "vets/vetList";
}
@GetMapping("/vets.html")
public String showVetList(Map<String, Object> model) {
// Here we are returning an object of type 'Vets' rather than a collection of Vet
// objects so it is simpler for Object-Xml mapping
Vets vets = new Vets();
vets.getVetList().addAll(this.vets.findAll());
model.put("vets", vets);
return "vets/vetList";
}
@GetMapping({ "/vets" })
public @ResponseBody Vets showResourcesVetList() {
// Here we are returning an object of type 'Vets' rather than a collection of Vet
// objects so it is simpler for JSon/Object mapping
Vets vets = new Vets();
vets.getVetList().addAll(this.vets.findAll());
return vets;
}
@GetMapping({ "/vets" })
public @ResponseBody Vets showResourcesVetList() {
// Here we are returning an object of type 'Vets' rather than a collection of Vet
// objects so it is simpler for JSon/Object mapping
Vets vets = new Vets();
vets.getVetList().addAll(this.vets.findAll());
return vets;
}
}

View file

@ -23,9 +23,10 @@ import org.springframework.data.repository.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* Repository class for <code>Vet</code> domain objects All method names are compliant with Spring Data naming
* conventions so this interface can easily be extended for Spring Data.
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* Repository class for <code>Vet</code> domain objects All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring
* Data. See:
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
*
* @author Ken Krebs
* @author Juergen Hoeller
@ -34,14 +35,12 @@ import org.springframework.transaction.annotation.Transactional;
*/
public interface VetRepository extends Repository<Vet, Integer> {
/**
* Retrieve all <code>Vet</code>s from the data store.
*
* @return a <code>Collection</code> of <code>Vet</code>s
*/
@Transactional(readOnly = true)
@Cacheable("vets")
Collection<Vet> findAll() throws DataAccessException;
/**
* Retrieve all <code>Vet</code>s from the data store.
* @return a <code>Collection</code> of <code>Vet</code>s
*/
@Transactional(readOnly = true)
@Cacheable("vets")
Collection<Vet> findAll() throws DataAccessException;
}

View file

@ -22,22 +22,22 @@ import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Simple domain object representing a list of veterinarians. Mostly here to be used for the 'vets' {@link
* org.springframework.web.servlet.view.xml.MarshallingView}.
* Simple domain object representing a list of veterinarians. Mostly here to be used for
* the 'vets' {@link org.springframework.web.servlet.view.xml.MarshallingView}.
*
* @author Arjen Poutsma
*/
@XmlRootElement
public class Vets {
private List<Vet> vets;
private List<Vet> vets;
@XmlElement
public List<Vet> getVetList() {
if (vets == null) {
vets = new ArrayList<>();
}
return vets;
}
@XmlElement
public List<Vet> getVetList() {
if (vets == null) {
vets = new ArrayList<>();
}
return vets;
}
}

View file

@ -35,46 +35,46 @@ import org.springframework.samples.petclinic.model.BaseEntity;
@Table(name = "visits")
public class Visit extends BaseEntity {
@Column(name = "visit_date")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date;
@Column(name = "visit_date")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date;
@NotEmpty
@Column(name = "description")
private String description;
@NotEmpty
@Column(name = "description")
private String description;
@Column(name = "pet_id")
private Integer petId;
@Column(name = "pet_id")
private Integer petId;
/**
* Creates a new instance of Visit for the current date
*/
public Visit() {
this.date = LocalDate.now();
}
/**
* Creates a new instance of Visit for the current date
*/
public Visit() {
this.date = LocalDate.now();
}
public LocalDate getDate() {
return this.date;
}
public LocalDate getDate() {
return this.date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public String getDescription() {
return this.description;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getPetId() {
return this.petId;
}
public Integer getPetId() {
return this.petId;
}
public void setPetId(Integer petId) {
this.petId = petId;
}
public void setPetId(Integer petId) {
this.petId = petId;
}
}

View file

@ -22,9 +22,10 @@ import org.springframework.data.repository.Repository;
import org.springframework.samples.petclinic.model.BaseEntity;
/**
* Repository class for <code>Visit</code> domain objects All method names are compliant with Spring Data naming
* conventions so this interface can easily be extended for Spring Data.
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* Repository class for <code>Visit</code> domain objects All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring
* Data. See:
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
*
* @author Ken Krebs
* @author Juergen Hoeller
@ -33,14 +34,13 @@ import org.springframework.samples.petclinic.model.BaseEntity;
*/
public interface VisitRepository extends Repository<Visit, Integer> {
/**
* Save a <code>Visit</code> to the data store, either inserting or updating it.
*
* @param visit the <code>Visit</code> to save
* @see BaseEntity#isNew
*/
void save(Visit visit) throws DataAccessException;
/**
* Save a <code>Visit</code> to the data store, either inserting or updating it.
* @param visit the <code>Visit</code> to save
* @see BaseEntity#isNew
*/
void save(Visit visit) throws DataAccessException;
List<Visit> findByPetId(Integer petId);
List<Visit> findByPetId(Integer petId);
}