diff --git a/pom.xml b/pom.xml index e4e74747a..4cc8bd611 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,6 @@ petclinic - 1.8 UTF-8 @@ -70,6 +69,14 @@ + + + org.modelmapper + modelmapper + 2.3.8 + compile + + com.h2database @@ -131,6 +138,23 @@ spring-boot-devtools true + + junit + junit + 4.13 + test + + + junit + junit + test + + + org.projectlombok + lombok + 1.18.12 + test + diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonAttribute.java b/src/main/java/org/springframework/samples/petclinic/common/CommonAttribute.java new file mode 100644 index 000000000..4fe322fd1 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonAttribute.java @@ -0,0 +1,50 @@ +package org.springframework.samples.petclinic.common; + +/** + * Class for const attributes names to prevent error with attributes names + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public final class CommonAttribute { + + public static final String DESCRIPTION = "description"; + + public static final String NAME = "name"; + + public static final String NEW = "new"; + + public static final String OWNER = "owner"; + + public static final String OWNER_ID = "id"; + + public static final String OWNER_LAST_NAME = "lastName"; + + public static final String OWNER_FIRST_NAME = "firstName"; + + public static final String OWNER_PHONE = "telephone"; + + public static final String OWNER_ADDRESS = "address"; + + public static final String OWNER_CITY = "city"; + + public static final String OWNER_PETS = "pets"; + + public static final String PET = "pet"; + + public static final String SELECTIONS = "selections"; + + public static final String PET_BIRTH_DATE = "birthDate"; + + public static final String PET_NAME = "name"; + + public static final String PET_TYPE = "type"; + + public static final String VETS = "vets"; + + public static final String VISIT = "visit"; + + private CommonAttribute() { + throw new IllegalStateException("Utility class"); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonEndPoint.java b/src/main/java/org/springframework/samples/petclinic/common/CommonEndPoint.java new file mode 100644 index 000000000..fa4177eb1 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonEndPoint.java @@ -0,0 +1,36 @@ +package org.springframework.samples.petclinic.common; + +/** + * Class for const endpoint names to prevent error with endpoint names + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public final class CommonEndPoint { + + public static final String OWNERS = "/owners"; + + public static final String OWNERS_FIND = "/owners/find"; + + public static final String OWNERS_ID = "/owners/{ownerId}"; + + public static final String OWNERS_ID_EDIT = "/owners/{ownerId}/edit"; + + public static final String OWNERS_NEW = "/owners/new"; + + public static final String PETS_NEW = "/pets/new"; + + public static final String PETS_ID_EDIT = "/pets/{petId}/edit"; + + public static final String VETS = "/vets"; + + public static final String VETS_HTML = "/vets.html"; + + public static final String VISITS_NEW = "/owners/*/pets/{petId}/visits/new"; + + public static final String VISITS_EDIT = "/owners/{ownerId}/pets/{petId}/visits/new"; + + private CommonEndPoint() { + throw new IllegalStateException("Utility class"); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonError.java b/src/main/java/org/springframework/samples/petclinic/common/CommonError.java new file mode 100644 index 000000000..c7144975d --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonError.java @@ -0,0 +1,26 @@ +package org.springframework.samples.petclinic.common; + +/** + * Class for const error names to prevent errors + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public final class CommonError { + + public static final String DUPLICATE_ARGS = "duplicate"; + + public static final String DUPLICATE_MESSAGE = "already exists"; + + public static final String NOT_FOUND_ARGS = "notFound"; + + public static final String NOT_FOUND_MESSAGE = "notFound"; + + public static final String REQUIRED_ARGS = "required"; + + public static final String REQUIRED_MESSAGE = "required"; + + private CommonError() { + throw new IllegalStateException("Utility class"); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonView.java b/src/main/java/org/springframework/samples/petclinic/common/CommonView.java new file mode 100644 index 000000000..ddde0c73b --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonView.java @@ -0,0 +1,32 @@ +package org.springframework.samples.petclinic.common; + +/** + * Class for const view names to prevent error with view names + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public final class CommonView { + + public static final String OWNER_OWNERS_R = "redirect:/owners/"; + + public static final String OWNER_OWNERS_ID_R = "redirect:/owners/{ownerId}"; + + public static final String OWNER_CREATE_OR_UPDATE = "owners/createOrUpdateOwnerForm"; + + public static final String OWNER_FIND_OWNERS = "owners/findOwners"; + + public static final String OWNER_OWNERS_LIST = "owners/ownersList"; + + public static final String OWNER_DETAILS = "owners/ownerDetails"; + + public static final String PET_CREATE_OR_UPDATE = "pets/createOrUpdatePetForm"; + + public static final String VET_VETS_LIST = "vets/vetList"; + + public static final String VISIT_CREATE_OR_UPDATE = "pets/createOrUpdateVisitForm"; + + private CommonView() { + throw new IllegalStateException("Utility class"); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/controller/OwnerController.java b/src/main/java/org/springframework/samples/petclinic/controller/OwnerController.java new file mode 100644 index 000000000..6cfcec4ef --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/controller/OwnerController.java @@ -0,0 +1,152 @@ +/* + * Copyright 2012-2019 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.controller; + +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonEndPoint; +import org.springframework.samples.petclinic.common.CommonError; +import org.springframework.samples.petclinic.common.CommonView; +import org.springframework.samples.petclinic.dto.*; +import org.springframework.samples.petclinic.service.OwnerService; +import org.springframework.samples.petclinic.service.VisitService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.Map; + +/** + * @author Juergen Hoeller + * @author Ken Krebs + * @author Arjen Poutsma + * @author Michael Isvy + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Controller +class OwnerController { + + private final OwnerService ownerService; + + private final VisitService visitService; + + OwnerController(OwnerService ownerService, VisitService visitService) { + this.ownerService = ownerService; + this.visitService = visitService; + } + + @InitBinder("owner") + public void setAllowedFields(WebDataBinder dataBinder) { + dataBinder.setDisallowedFields(CommonAttribute.OWNER_ID); + } + + @GetMapping(CommonEndPoint.OWNERS_NEW) + public String initCreationForm(Map model) { + OwnerDTO owner = new OwnerDTO(); + model.put(CommonAttribute.OWNER, owner); + return CommonView.OWNER_CREATE_OR_UPDATE; + } + + @PostMapping(CommonEndPoint.OWNERS_NEW) + public String processCreationForm(@ModelAttribute(CommonAttribute.OWNER) @Valid OwnerDTO owner, + BindingResult result) { + if (result.hasErrors()) { + return CommonView.OWNER_CREATE_OR_UPDATE; + } + else { + this.ownerService.save(owner); + return CommonView.OWNER_OWNERS_R + owner.getId(); + } + } + + @GetMapping(CommonEndPoint.OWNERS_FIND) + public String initFindForm(Map model) { + model.put(CommonAttribute.OWNER, new OwnerDTO()); + return CommonView.OWNER_FIND_OWNERS; + } + + @GetMapping(CommonEndPoint.OWNERS) + public String processFindForm(@ModelAttribute(CommonAttribute.OWNER) OwnerDTO owner, BindingResult result, + Map model) { + + // allow parameterless GET request for /owners to return all records + if (owner.getLastName() == null) { + owner.setLastName(""); // empty string signifies broadest possible search + } + + // find owners by last name + Collection results = this.ownerService.findByLastName(owner.getLastName()); + if (results.isEmpty()) { + // no owners found + result.rejectValue(CommonAttribute.OWNER_LAST_NAME, CommonError.NOT_FOUND_ARGS, + CommonError.NOT_FOUND_MESSAGE); + return CommonView.OWNER_FIND_OWNERS; + } + else if (results.size() == 1) { + // 1 owner found + owner = results.iterator().next(); + return CommonView.OWNER_OWNERS_R + owner.getId(); + } + else { + // multiple owners found + model.put(CommonAttribute.SELECTIONS, results); + return CommonView.OWNER_OWNERS_LIST; + } + } + + @GetMapping(CommonEndPoint.OWNERS_ID_EDIT) + public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { + OwnerDTO ownerDTO = this.ownerService.findById(ownerId); + model.addAttribute(CommonAttribute.OWNER, ownerDTO); + return CommonView.OWNER_CREATE_OR_UPDATE; + } + + @PostMapping(CommonEndPoint.OWNERS_ID_EDIT) + public String processUpdateOwnerForm(@ModelAttribute(CommonAttribute.OWNER) @Valid OwnerDTO owner, + BindingResult result, @PathVariable("ownerId") int ownerId) { + if (result.hasErrors()) { + return CommonView.OWNER_CREATE_OR_UPDATE; + } + else { + owner.setId(ownerId); + this.ownerService.save(owner); + return CommonView.OWNER_OWNERS_ID_R; + } + } + + /** + * 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(CommonEndPoint.OWNERS_ID) + public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { + ModelAndView modelAndView = new ModelAndView(CommonView.OWNER_DETAILS); + OwnerDTO owner = this.ownerService.findById(ownerId); + + for (PetDTO petDTO : owner.getPets()) { + petDTO.setVisitsInternal(visitService.findByPetId(petDTO.getId())); + } + + modelAndView.addObject(CommonAttribute.OWNER, owner); + return modelAndView; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/controller/PetController.java b/src/main/java/org/springframework/samples/petclinic/controller/PetController.java new file mode 100644 index 000000000..d0d8ca9d7 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/controller/PetController.java @@ -0,0 +1,126 @@ +/* + * Copyright 2012-2019 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.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonEndPoint; +import org.springframework.samples.petclinic.common.CommonError; +import org.springframework.samples.petclinic.common.CommonView; +import org.springframework.samples.petclinic.dto.*; +import org.springframework.samples.petclinic.validator.PetDTOValidator; +import org.springframework.samples.petclinic.service.*; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.util.StringUtils; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.Collection; + +/** + * @author Juergen Hoeller + * @author Ken Krebs + * @author Arjen Poutsma + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Controller +@RequestMapping(CommonEndPoint.OWNERS_ID) +class PetController { + + private final OwnerService ownerService; + + private final PetService petService; + + private final PetTypeService petTypeService; + + @Autowired + PetController(OwnerService ownerService, PetService petService, PetTypeService petTypeService) { + this.ownerService = ownerService; + this.petService = petService; + this.petTypeService = petTypeService; + } + + @ModelAttribute("types") + public Collection populatePetTypes() { + return this.petService.findPetTypes(); + } + + @ModelAttribute("owner") + public OwnerDTO findOwner(@PathVariable("ownerId") int ownerId) { + return this.ownerService.findById(ownerId); + } + + @InitBinder("owner") + public void initOwnerBinder(WebDataBinder dataBinder) { + dataBinder.setDisallowedFields(CommonAttribute.OWNER_ID); + } + + @InitBinder("pet") + public void initPetBinder(WebDataBinder dataBinder) { + dataBinder.setValidator(new PetDTOValidator()); + } + + @GetMapping(CommonEndPoint.PETS_NEW) + public String initCreationForm(@ModelAttribute(CommonAttribute.OWNER) OwnerDTO owner, ModelMap model) { + PetDTO pet = new PetDTO(); + owner.addPet(pet); + model.put(CommonAttribute.PET, pet); + return CommonView.PET_CREATE_OR_UPDATE; + } + + @PostMapping(CommonEndPoint.PETS_NEW) + public String processCreationForm(@ModelAttribute(CommonAttribute.OWNER) OwnerDTO owner, + @ModelAttribute(CommonAttribute.PET) @Valid PetDTO pet, BindingResult result, ModelMap model) { + if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) { + result.rejectValue(CommonAttribute.NAME, CommonError.DUPLICATE_ARGS, CommonError.DUPLICATE_MESSAGE); + } + owner.addPet(pet); + if (result.hasErrors()) { + model.put(CommonAttribute.PET, pet); + return CommonView.PET_CREATE_OR_UPDATE; + } + else { + this.petService.save(pet); + return CommonView.OWNER_OWNERS_ID_R; + } + } + + @GetMapping(CommonEndPoint.PETS_ID_EDIT) + public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) { + PetDTO pet = this.petService.findById(petId); + model.put(CommonAttribute.PET, pet); + return CommonView.PET_CREATE_OR_UPDATE; + } + + @PostMapping(CommonEndPoint.PETS_ID_EDIT) + public String processUpdateForm(@ModelAttribute(CommonAttribute.PET) @Valid PetDTO pet, BindingResult result, + @ModelAttribute(CommonAttribute.OWNER) OwnerDTO owner, ModelMap model) { + if (result.hasErrors()) { + pet.setOwner(owner); + model.put(CommonAttribute.PET, pet); + return CommonView.PET_CREATE_OR_UPDATE; + } + else { + owner.addPet(pet); + this.petService.save(pet); + return CommonView.OWNER_OWNERS_ID_R; + } + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/vet/VetController.java b/src/main/java/org/springframework/samples/petclinic/controller/VetController.java similarity index 58% rename from src/main/java/org/springframework/samples/petclinic/vet/VetController.java rename to src/main/java/org/springframework/samples/petclinic/controller/VetController.java index fb5e321ba..64f00ca2f 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/VetController.java +++ b/src/main/java/org/springframework/samples/petclinic/controller/VetController.java @@ -13,8 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.vet; +package org.springframework.samples.petclinic.controller; +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonEndPoint; +import org.springframework.samples.petclinic.common.CommonView; +import org.springframework.samples.petclinic.dto.VetsDTO; +import org.springframework.samples.petclinic.service.VetService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; @@ -26,32 +31,33 @@ import java.util.Map; * @author Mark Fisher * @author Ken Krebs * @author Arjen Poutsma + * @author Paul-Emmanuel DOS SANTOS FACAO */ @Controller class VetController { - private final VetRepository vets; + private final VetService vetService; - public VetController(VetRepository clinicService) { - this.vets = clinicService; + VetController(VetService vetService) { + this.vetService = vetService; } - @GetMapping("/vets.html") + @GetMapping(CommonEndPoint.VETS_HTML) public String showVetList(Map 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"; + VetsDTO vets = new VetsDTO(); + vets.getVetList().addAll(this.vetService.findAll()); + model.put(CommonAttribute.VETS, vets); + return CommonView.VET_VETS_LIST; } - @GetMapping({ "/vets" }) - public @ResponseBody Vets showResourcesVetList() { + @GetMapping({ CommonEndPoint.VETS }) + public @ResponseBody VetsDTO 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()); + VetsDTO vets = new VetsDTO(); + vets.getVetList().addAll(this.vetService.findAll()); return vets; } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java b/src/main/java/org/springframework/samples/petclinic/controller/VisitController.java similarity index 58% rename from src/main/java/org/springframework/samples/petclinic/owner/VisitController.java rename to src/main/java/org/springframework/samples/petclinic/controller/VisitController.java index 375980312..3fb9bfb4c 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java +++ b/src/main/java/org/springframework/samples/petclinic/controller/VisitController.java @@ -13,14 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.controller; import java.util.Map; import javax.validation.Valid; -import org.springframework.samples.petclinic.visit.Visit; -import org.springframework.samples.petclinic.visit.VisitRepository; +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonEndPoint; +import org.springframework.samples.petclinic.common.CommonView; +import org.springframework.samples.petclinic.dto.PetDTO; +import org.springframework.samples.petclinic.dto.VisitDTO; +import org.springframework.samples.petclinic.service.PetService; +import org.springframework.samples.petclinic.service.VisitService; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.WebDataBinder; @@ -36,17 +41,18 @@ import org.springframework.web.bind.annotation.PostMapping; * @author Arjen Poutsma * @author Michael Isvy * @author Dave Syer + * @author Paul-Emmanuel DOS SANTOS FACAO */ @Controller class VisitController { - private final VisitRepository visits; + private final VisitService visitService; - private final PetRepository pets; + private final PetService petService; - public VisitController(VisitRepository visits, PetRepository pets) { - this.visits = visits; - this.pets = pets; + VisitController(VisitService visitService, PetService petService) { + this.visitService = visitService; + this.petService = petService; } @InitBinder @@ -58,34 +64,35 @@ class VisitController { * 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 + * @param petId Pet identification * @return Pet */ @ModelAttribute("visit") - public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map model) { - Pet pet = this.pets.findById(petId); - pet.setVisitsInternal(this.visits.findByPetId(petId)); - model.put("pet", pet); - Visit visit = new Visit(); + public VisitDTO loadPetWithVisit(@PathVariable("petId") int petId, Map model) { + PetDTO pet = this.petService.findById(petId); + pet.setVisitsInternal(this.visitService.findByPetId(petId)); + model.put(CommonAttribute.PET, pet); + VisitDTO visit = new VisitDTO(); pet.addVisit(visit); return visit; } // Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called - @GetMapping("/owners/*/pets/{petId}/visits/new") + @GetMapping(CommonEndPoint.VISITS_NEW) public String initNewVisitForm(@PathVariable("petId") int petId, Map model) { - return "pets/createOrUpdateVisitForm"; + return CommonView.VISIT_CREATE_OR_UPDATE; } // Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called - @PostMapping("/owners/{ownerId}/pets/{petId}/visits/new") - public String processNewVisitForm(@Valid Visit visit, BindingResult result) { + @PostMapping(CommonEndPoint.VISITS_EDIT) + public String processNewVisitForm(@ModelAttribute(CommonAttribute.VISIT) @Valid VisitDTO visit, + BindingResult result) { if (result.hasErrors()) { - return "pets/createOrUpdateVisitForm"; + return CommonView.VISIT_CREATE_OR_UPDATE; } else { - this.visits.save(visit); - return "redirect:/owners/{ownerId}"; + this.visitService.save(visit); + return CommonView.OWNER_OWNERS_ID_R; } } diff --git a/src/main/java/org/springframework/samples/petclinic/dto/BaseDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/BaseDTO.java new file mode 100644 index 000000000..eb08fa003 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/BaseDTO.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2019 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.dto; + +import java.io.Serializable; + +/** + * Simple Data Transfert Object with an id property. Used as a base class for DTO needing + * this property. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class BaseDTO implements Serializable { + + private Integer id; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public boolean isNew() { + return this.id == null; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/NamedDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/NamedDTO.java new file mode 100644 index 000000000..1d3168628 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/NamedDTO.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2019 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.dto; + +/** + * Simple Data Transfert Object with a name property to BaseDTO. Used as a + * base class for DTOs needing these properties. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class NamedDTO extends BaseDTO { + + private String name; + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return this.getName(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof NamedDTO)) + return false; + + NamedDTO namedDTO = (NamedDTO) o; + + return getName().equals(namedDTO.getName()); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/OwnerDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/OwnerDTO.java new file mode 100644 index 000000000..938e095c9 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/OwnerDTO.java @@ -0,0 +1,150 @@ +/* + * Copyright 2012-2019 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.dto; + +import org.springframework.beans.support.MutableSortDefinition; +import org.springframework.beans.support.PropertyComparator; +import org.springframework.core.style.ToStringCreator; +import org.springframework.samples.petclinic.common.CommonAttribute; + +import javax.validation.constraints.Digits; +import javax.validation.constraints.NotEmpty; +import java.util.*; + +/** + * Simple Data Transfert Object representing a owner. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class OwnerDTO extends PersonDTO { + + @NotEmpty + private String address; + + @NotEmpty + private String city; + + @NotEmpty + @Digits(fraction = 0, integer = 10) + private String telephone; + + private Set pets; + + public String getAddress() { + return this.address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getCity() { + return this.city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getTelephone() { + return this.telephone; + } + + public void setTelephone(String telephone) { + this.telephone = telephone; + } + + protected Set getPetsInternal() { + if (this.pets == null) { + this.pets = new HashSet<>(); + } + return this.pets; + } + + public void setPetsInternal(Set pets) { + this.pets = pets; + } + + public List getPets() { + List sortedPets = new ArrayList<>(getPetsInternal()); + PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true)); + return Collections.unmodifiableList(sortedPets); + } + + public void addPet(PetDTO pet) { + + if (pet.isNew() || this.getPets() == null || !this.getPets().contains(pet)) { + 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 PetDTO getPet(String name) { + return getPet(name, false); + } + + /** + * 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 PetDTO getPet(String name, boolean ignoreNew) { + name = name.toLowerCase(); + for (PetDTO 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(CommonAttribute.OWNER_ID, this.getId()) + .append(CommonAttribute.NEW, this.isNew()).append(CommonAttribute.OWNER_LAST_NAME, this.getLastName()) + .append(CommonAttribute.OWNER_FIRST_NAME, this.getFirstName()) + .append(CommonAttribute.OWNER_ADDRESS, this.address).append(CommonAttribute.OWNER_CITY, this.city) + .append(CommonAttribute.OWNER_PHONE, this.telephone).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof OwnerDTO)) + return false; + + OwnerDTO ownerDTO = (OwnerDTO) o; + + if (!getAddress().equals(ownerDTO.getAddress())) + return false; + if (!getCity().equals(ownerDTO.getCity())) + return false; + if (!getTelephone().equals(ownerDTO.getTelephone())) + return false; + return getPets() != null ? getPets().equals(ownerDTO.getPets()) : ownerDTO.getPets() == null; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/PersonDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/PersonDTO.java new file mode 100644 index 000000000..f41818528 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/PersonDTO.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2019 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.dto; + +import javax.validation.constraints.NotEmpty; + +/** + * Simple Data Transfert Object representing a person. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class PersonDTO extends BaseDTO { + + @NotEmpty + private String firstName; + + @NotEmpty + private String lastName; + + public String getFirstName() { + return this.firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return this.lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof PersonDTO)) + return false; + + PersonDTO personDTO = (PersonDTO) o; + + if (!getFirstName().equals(personDTO.getFirstName())) + return false; + return getLastName().equals(personDTO.getLastName()); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/PetDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/PetDTO.java new file mode 100644 index 000000000..c51587db9 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/PetDTO.java @@ -0,0 +1,107 @@ +/* + * Copyright 2012-2019 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.dto; + +import org.springframework.beans.support.MutableSortDefinition; +import org.springframework.beans.support.PropertyComparator; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; +import java.util.*; + +/** + * Simple Data Transfert Object representing a pet. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class PetDTO extends NamedDTO { + + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate birthDate; + + private PetTypeDTO type; + + private OwnerDTO owner; + + private Set visits = new LinkedHashSet<>(); + + public void setBirthDate(LocalDate birthDate) { + this.birthDate = birthDate; + } + + public LocalDate getBirthDate() { + return this.birthDate; + } + + public PetTypeDTO getType() { + return this.type; + } + + public void setType(PetTypeDTO type) { + this.type = type; + } + + public OwnerDTO getOwner() { + return owner; + } + + public void setOwner(OwnerDTO owner) { + this.owner = owner; + } + + protected Set getVisitsInternal() { + if (this.visits == null) { + this.visits = new HashSet<>(); + } + return this.visits; + } + + public void setVisitsInternal(Collection visits) { + this.visits = new LinkedHashSet<>(visits); + } + + public List getVisits() { + List sortedVisits = new ArrayList<>(getVisitsInternal()); + PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false)); + return Collections.unmodifiableList(sortedVisits); + } + + public void addVisit(VisitDTO visit) { + getVisitsInternal().add(visit); + visit.setPetId(this.getId()); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof PetDTO)) + return false; + if (!super.equals(o)) + return false; + + PetDTO petDTO = (PetDTO) o; + + if (!getBirthDate().equals(petDTO.getBirthDate())) + return false; + if (!getType().equals(petDTO.getType())) + return false; + if (getOwner() != null ? !getOwner().getId().equals(petDTO.getOwner().getId()) : petDTO.getOwner() != null) + return false; + return getVisits() != null ? getVisits().equals(petDTO.getVisits()) : petDTO.getVisits() == null; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/PetTypeDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/PetTypeDTO.java new file mode 100644 index 000000000..100c134bc --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/PetTypeDTO.java @@ -0,0 +1,15 @@ +package org.springframework.samples.petclinic.dto; + +/** + * Simple Data Transfert Object representing PetType. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class PetTypeDTO extends NamedDTO { + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/SpecialtyDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/SpecialtyDTO.java new file mode 100644 index 000000000..d209a511a --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/SpecialtyDTO.java @@ -0,0 +1,12 @@ +package org.springframework.samples.petclinic.dto; + +import java.io.Serializable; + +/** + * Simple Data Transfert Object representing a list of specialities. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class SpecialtyDTO extends NamedDTO implements Serializable { + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/VetDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/VetDTO.java new file mode 100644 index 000000000..0b1520b56 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/VetDTO.java @@ -0,0 +1,74 @@ +/* + * Copyright 2012-2019 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.dto; + +import org.springframework.beans.support.MutableSortDefinition; +import org.springframework.beans.support.PropertyComparator; +import org.springframework.samples.petclinic.model.Specialty; + +import javax.xml.bind.annotation.XmlElement; +import java.util.*; + +/** + * Simple Data Transfert Object representing a vet. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class VetDTO extends PersonDTO { + + private Set specialties; + + protected Set getSpecialtiesInternal() { + if (this.specialties == null) { + this.specialties = new HashSet<>(); + } + return this.specialties; + } + + protected void setSpecialtiesInternal(Set specialties) { + this.specialties = specialties; + } + + @XmlElement + public List getSpecialties() { + List sortedSpecs = new ArrayList<>(getSpecialtiesInternal()); + PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true)); + return Collections.unmodifiableList(sortedSpecs); + } + + public int getNrOfSpecialties() { + return getSpecialtiesInternal().size(); + } + + public void addSpecialty(SpecialtyDTO specialty) { + getSpecialtiesInternal().add(specialty); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof VetDTO)) + return false; + if (!super.equals(o)) + return false; + + VetDTO vetDTO = (VetDTO) o; + + return getSpecialties().equals(vetDTO.getSpecialties()); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/VetsDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/VetsDTO.java new file mode 100644 index 000000000..aea942f58 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/VetsDTO.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2019 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.dto; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple Data Transfert Object representing a list of veterinarians. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class VetsDTO { + + private List vets; + + public List getVetList() { + if (vets == null) { + vets = new ArrayList<>(); + } + return vets; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/VisitDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/VisitDTO.java new file mode 100644 index 000000000..d976185b7 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/VisitDTO.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012-2019 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.dto; + +import org.springframework.format.annotation.DateTimeFormat; +import javax.validation.constraints.NotEmpty; +import java.time.LocalDate; + +/** + * Simple Data Transfert Object representing a visit. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class VisitDTO extends BaseDTO { + + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate date; + + @NotEmpty + private String description; + + private Integer petId; + + /** + * Creates a new instance of Visit for the current date + */ + public VisitDTO() { + this.date = LocalDate.now(); + } + + public LocalDate getDate() { + return this.date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Integer getPetId() { + return this.petId; + } + + public void setPetId(Integer petId) { + this.petId = petId; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof VisitDTO)) + return false; + + VisitDTO visitDTO = (VisitDTO) o; + + if (!getDate().equals(visitDTO.getDate())) + return false; + if (!getDescription().equals(visitDTO.getDescription())) + return false; + return getPetId().equals(visitDTO.getPetId()); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java b/src/main/java/org/springframework/samples/petclinic/formatter/PetTypeFormatter.java similarity index 67% rename from src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java rename to src/main/java/org/springframework/samples/petclinic/formatter/PetTypeFormatter.java index 4940bcb38..a93537845 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java +++ b/src/main/java/org/springframework/samples/petclinic/formatter/PetTypeFormatter.java @@ -13,14 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.formatter; import java.text.ParseException; import java.util.Collection; import java.util.Locale; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.Formatter; +import org.springframework.samples.petclinic.dto.PetTypeDTO; +import org.springframework.samples.petclinic.service.PetService; +import org.springframework.samples.petclinic.service.PetTypeService; import org.springframework.stereotype.Component; /** @@ -34,24 +36,23 @@ import org.springframework.stereotype.Component; * @author Michael Isvy */ @Component -public class PetTypeFormatter implements Formatter { +public class PetTypeFormatter implements Formatter { - private final PetRepository pets; + private final PetService petService; - @Autowired - public PetTypeFormatter(PetRepository pets) { - this.pets = pets; + public PetTypeFormatter(PetService petService) { + this.petService = petService; } @Override - public String print(PetType petType, Locale locale) { + public String print(PetTypeDTO petType, Locale locale) { return petType.getName(); } @Override - public PetType parse(String text, Locale locale) throws ParseException { - Collection findPetTypes = this.pets.findPetTypes(); - for (PetType type : findPetTypes) { + public PetTypeDTO parse(String text, Locale locale) throws ParseException { + Collection findPetTypes = this.petService.findPetTypes(); + for (PetTypeDTO type : findPetTypes) { if (type.getName().equals(text)) { return type; } diff --git a/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java b/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java index 088e52e81..cafe7e218 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java +++ b/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java @@ -44,4 +44,16 @@ public class NamedEntity extends BaseEntity { return this.getName(); } + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof NamedEntity)) + return false; + + NamedEntity that = (NamedEntity) o; + + return getName().equals(that.getName()); + } + } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/Owner.java b/src/main/java/org/springframework/samples/petclinic/model/Owner.java similarity index 85% rename from src/main/java/org/springframework/samples/petclinic/owner/Owner.java rename to src/main/java/org/springframework/samples/petclinic/model/Owner.java index 61083bc8d..bc5f2df92 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/Owner.java +++ b/src/main/java/org/springframework/samples/petclinic/model/Owner.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.model; import java.util.ArrayList; import java.util.Collections; @@ -32,7 +32,7 @@ import javax.validation.constraints.NotEmpty; import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.PropertyComparator; import org.springframework.core.style.ToStringCreator; -import org.springframework.samples.petclinic.model.Person; +import org.springframework.samples.petclinic.common.CommonAttribute; /** * Simple JavaBean domain object representing an owner. @@ -104,7 +104,7 @@ public class Owner extends Person { } public void addPet(Pet pet) { - if (pet.isNew()) { + if (!this.getPets().contains(pet)) { getPetsInternal().add(pet); } pet.setOwner(this); @@ -140,11 +140,11 @@ public class Owner extends Person { @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(); + return new ToStringCreator(this).append(CommonAttribute.OWNER_ID, this.getId()) + .append(CommonAttribute.NEW, this.isNew()).append(CommonAttribute.OWNER_LAST_NAME, this.getLastName()) + .append(CommonAttribute.OWNER_FIRST_NAME, this.getFirstName()) + .append(CommonAttribute.OWNER_ADDRESS, this.address).append(CommonAttribute.OWNER_CITY, this.city) + .append(CommonAttribute.OWNER_PHONE, this.telephone).toString(); } } diff --git a/src/main/java/org/springframework/samples/petclinic/model/Person.java b/src/main/java/org/springframework/samples/petclinic/model/Person.java index 15fabacc3..709c3bec3 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/Person.java +++ b/src/main/java/org/springframework/samples/petclinic/model/Person.java @@ -51,4 +51,18 @@ public class Person extends BaseEntity { this.lastName = lastName; } + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof Person)) + return false; + + Person person = (Person) o; + + if (!getFirstName().equals(person.getFirstName())) + return false; + return getLastName().equals(person.getLastName()); + } + } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/Pet.java b/src/main/java/org/springframework/samples/petclinic/model/Pet.java old mode 100755 new mode 100644 similarity index 81% rename from src/main/java/org/springframework/samples/petclinic/owner/Pet.java rename to src/main/java/org/springframework/samples/petclinic/model/Pet.java index 2b68005fd..f6b0b26ed --- a/src/main/java/org/springframework/samples/petclinic/owner/Pet.java +++ b/src/main/java/org/springframework/samples/petclinic/model/Pet.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.model; import java.time.LocalDate; import java.util.ArrayList; @@ -34,8 +34,6 @@ import javax.persistence.Transient; import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.PropertyComparator; import org.springframework.format.annotation.DateTimeFormat; -import org.springframework.samples.petclinic.model.NamedEntity; -import org.springframework.samples.petclinic.visit.Visit; /** * Simple business object representing a pet. @@ -83,7 +81,7 @@ public class Pet extends NamedEntity { return this.owner; } - protected void setOwner(Owner owner) { + public void setOwner(Owner owner) { this.owner = owner; } @@ -109,4 +107,24 @@ public class Pet extends NamedEntity { visit.setPetId(this.getId()); } + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof Pet)) + return false; + if (!super.equals(o)) + return false; + + Pet pet = (Pet) o; + + if (!getBirthDate().equals(pet.getBirthDate())) + return false; + if (!getType().equals(pet.getType())) + return false; + if (getOwner() != null ? !getOwner().equals(pet.getOwner()) : pet.getOwner() != null) + return false; + return getVisits() != null ? getVisits().equals(pet.getVisits()) : pet.getVisits() == null; + } + } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetType.java b/src/main/java/org/springframework/samples/petclinic/model/PetType.java similarity index 86% rename from src/main/java/org/springframework/samples/petclinic/owner/PetType.java rename to src/main/java/org/springframework/samples/petclinic/model/PetType.java index 6f0aa58d3..8453778e8 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetType.java +++ b/src/main/java/org/springframework/samples/petclinic/model/PetType.java @@ -13,13 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.model; import javax.persistence.Entity; import javax.persistence.Table; -import org.springframework.samples.petclinic.model.NamedEntity; - /** * @author Juergen Hoeller Can be Cat, Dog, Hamster... */ @@ -27,4 +25,9 @@ import org.springframework.samples.petclinic.model.NamedEntity; @Table(name = "types") public class PetType extends NamedEntity { + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } + } diff --git a/src/main/java/org/springframework/samples/petclinic/vet/Specialty.java b/src/main/java/org/springframework/samples/petclinic/model/Specialty.java similarity index 88% rename from src/main/java/org/springframework/samples/petclinic/vet/Specialty.java rename to src/main/java/org/springframework/samples/petclinic/model/Specialty.java index ea8ec6ded..c6bcc0e0a 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/Specialty.java +++ b/src/main/java/org/springframework/samples/petclinic/model/Specialty.java @@ -13,15 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.vet; +package org.springframework.samples.petclinic.model; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.Table; -import org.springframework.samples.petclinic.model.NamedEntity; - /** * Models a {@link Vet Vet's} specialty (for example, dentistry). * diff --git a/src/main/java/org/springframework/samples/petclinic/vet/Vet.java b/src/main/java/org/springframework/samples/petclinic/model/Vet.java similarity index 95% rename from src/main/java/org/springframework/samples/petclinic/vet/Vet.java rename to src/main/java/org/springframework/samples/petclinic/model/Vet.java index 014becfce..dc45e5150 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/Vet.java +++ b/src/main/java/org/springframework/samples/petclinic/model/Vet.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.vet; +package org.springframework.samples.petclinic.model; import java.util.ArrayList; import java.util.Collections; @@ -31,7 +31,6 @@ import javax.xml.bind.annotation.XmlElement; import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.PropertyComparator; -import org.springframework.samples.petclinic.model.Person; /** * Simple JavaBean domain object representing a veterinarian. diff --git a/src/main/java/org/springframework/samples/petclinic/vet/Vets.java b/src/main/java/org/springframework/samples/petclinic/model/Vets.java similarity index 95% rename from src/main/java/org/springframework/samples/petclinic/vet/Vets.java rename to src/main/java/org/springframework/samples/petclinic/model/Vets.java index cea665629..5ce52829f 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/Vets.java +++ b/src/main/java/org/springframework/samples/petclinic/model/Vets.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.vet; +package org.springframework.samples.petclinic.model; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/org/springframework/samples/petclinic/visit/Visit.java b/src/main/java/org/springframework/samples/petclinic/model/Visit.java old mode 100755 new mode 100644 similarity index 81% rename from src/main/java/org/springframework/samples/petclinic/visit/Visit.java rename to src/main/java/org/springframework/samples/petclinic/model/Visit.java index df9f25fe0..859ca61a0 --- a/src/main/java/org/springframework/samples/petclinic/visit/Visit.java +++ b/src/main/java/org/springframework/samples/petclinic/model/Visit.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.visit; +package org.springframework.samples.petclinic.model; import java.time.LocalDate; @@ -23,7 +23,6 @@ import javax.persistence.Table; import javax.validation.constraints.NotEmpty; import org.springframework.format.annotation.DateTimeFormat; -import org.springframework.samples.petclinic.model.BaseEntity; /** * Simple JavaBean domain object representing a visit. @@ -77,4 +76,20 @@ public class Visit extends BaseEntity { this.petId = petId; } + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof Visit)) + return false; + + Visit visit = (Visit) o; + + if (!getDate().equals(visit.getDate())) + return false; + if (!getDescription().equals(visit.getDescription())) + return false; + return getPetId().equals(visit.getPetId()); + } + } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java deleted file mode 100644 index 79aa4cd9b..000000000 --- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2012-2019 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.samples.petclinic.visit.VisitRepository; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -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.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.servlet.ModelAndView; - -import javax.validation.Valid; -import java.util.Collection; -import java.util.Map; - -/** - * @author Juergen Hoeller - * @author Ken Krebs - * @author Arjen Poutsma - * @author Michael Isvy - */ -@Controller -class OwnerController { - - private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm"; - - private final OwnerRepository owners; - - private VisitRepository visits; - - public OwnerController(OwnerRepository clinicService, VisitRepository visits) { - this.owners = clinicService; - this.visits = visits; - } - - @InitBinder - public void setAllowedFields(WebDataBinder dataBinder) { - dataBinder.setDisallowedFields("id"); - } - - @GetMapping("/owners/new") - public String initCreationForm(Map model) { - Owner owner = new Owner(); - model.put("owner", owner); - return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; - } - - @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/find") - public String initFindForm(Map model) { - model.put("owner", new Owner()); - return "owners/findOwners"; - } - - @GetMapping("/owners") - public String processFindForm(Owner owner, BindingResult result, Map model) { - - // allow parameterless GET request for /owners to return all records - if (owner.getLastName() == null) { - owner.setLastName(""); // empty string signifies broadest possible search - } - - // find owners by last name - Collection 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"; - } - } - - @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; - } - - @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; - } - -} diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetController.java b/src/main/java/org/springframework/samples/petclinic/owner/PetController.java deleted file mode 100644 index a55e599af..000000000 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetController.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2012-2019 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.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.util.StringUtils; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; -import java.util.Collection; - -/** - * @author Juergen Hoeller - * @author Ken Krebs - * @author Arjen Poutsma - */ -@Controller -@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; - - public PetController(PetRepository pets, OwnerRepository owners) { - this.pets = pets; - this.owners = owners; - } - - @ModelAttribute("types") - public Collection populatePetTypes() { - return this.pets.findPetTypes(); - } - - @ModelAttribute("owner") - public Owner findOwner(@PathVariable("ownerId") int ownerId) { - return this.owners.findById(ownerId); - } - - @InitBinder("owner") - public void initOwnerBinder(WebDataBinder dataBinder) { - dataBinder.setDisallowedFields("id"); - } - - @InitBinder("pet") - public void initPetBinder(WebDataBinder dataBinder) { - dataBinder.setValidator(new PetValidator()); - } - - @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/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}"; - } - } - -} diff --git a/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java similarity index 87% rename from src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java rename to src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java index 0613e928a..14cc90528 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java @@ -13,13 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.repository; import java.util.Collection; +import java.util.List; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; import org.springframework.data.repository.query.Param; +import org.springframework.samples.petclinic.model.Owner; import org.springframework.transaction.annotation.Transactional; /** @@ -32,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional; * @author Juergen Hoeller * @author Sam Brannen * @author Michael Isvy + * @author Paul-Emmanuel DOS SANTOS FACAO */ public interface OwnerRepository extends Repository { @@ -55,6 +58,12 @@ public interface OwnerRepository extends Repository { @Transactional(readOnly = true) Owner findById(@Param("id") Integer id); + /** + * Retrieve all {@link Owner}s from the data store + * @return a Collection of {@link Owner}s (or an empty Collection if none + */ + List findAll(); + /** * Save an {@link Owner} to the data store, either inserting or updating it. * @param owner the {@link Owner} to save diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java similarity index 76% rename from src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java rename to src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java index 9d25b095b..1d52108c9 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.repository; import java.util.List; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; +import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.model.PetType; import org.springframework.transaction.annotation.Transactional; /** @@ -31,6 +33,7 @@ import org.springframework.transaction.annotation.Transactional; * @author Juergen Hoeller * @author Sam Brannen * @author Michael Isvy + * @author Paul-Emmanuel DOS SANTOS FACAO */ public interface PetRepository extends Repository { @@ -47,9 +50,21 @@ public interface PetRepository extends Repository { * @param id the id to search for * @return the {@link Pet} if found */ - @Transactional(readOnly = true) Pet findById(Integer id); + /** + * Retrieve all {@link Pet}d from the data store by owner id. + * @param id the id of owner to search for + * @return a Collection of {@link Pet}s + */ + List findByOwnerId(Integer id); + + /** + * Retrieve all {@link Pet}s from the data store + * @return a Collection of {@link Pet}s (or an empty Collection if none + */ + List findAll(); + /** * Save a {@link Pet} to the data store, either inserting or updating it. * @param pet the {@link Pet} to save diff --git a/src/main/java/org/springframework/samples/petclinic/repository/PetTypeRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/PetTypeRepository.java new file mode 100644 index 000000000..77eb7e6b3 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/PetTypeRepository.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2019 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.repository; + +import org.springframework.data.repository.Repository; +import org.springframework.samples.petclinic.model.PetType; + +import java.util.Collection; +import java.util.List; + +/** + * Repository class for PetType domain objects All method names are compliant + * with Spring Data naming conventions so this interface can easily be extended for Spring + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public interface PetTypeRepository extends Repository { + + /** + * Retrieve a {@link PetType} from the data store by id. + * @param id the id to search for + * @return the {@link PetType} if found + */ + PetType findById(Integer id); + + /** + * Retrieve all {@link PetType}s from the data store + * @return a Collection of {@link PetType}s (or an empty Collection if none + */ + List findAll(); + + /** + * Save a {@link PetType} to the data store, either inserting or updating it. + * @param petType the {@link PetType} to save + */ + void save(PetType petType); + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/SpecialtyRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/SpecialtyRepository.java new file mode 100644 index 000000000..327161809 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/SpecialtyRepository.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2019 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.repository; + +import org.springframework.data.repository.Repository; +import org.springframework.samples.petclinic.model.Specialty; + +import java.util.Collection; +import java.util.List; + +/** + * Repository class for Speciality domain objects All method names are + * compliant with Spring Data naming conventions so this interface can easily be extended + * for Spring + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public interface SpecialtyRepository extends Repository { + + /** + * Retrieve a {@link Specialty} from the data store by id. + * @param id the id to search for + * @return the {@link Specialty} if found + */ + Specialty findById(Integer id); + + /** + * Retrieve all {@link Specialty}s from the data store + * @return a Collection of {@link Specialty}s (or an empty Collection if none + */ + List findAll(); + + /** + * Save a {@link Specialty} to the data store, either inserting or updating it. + * @param specialty the {@link Specialty} to save + */ + void save(Specialty specialty); + +} diff --git a/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java similarity index 75% rename from src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java rename to src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java index 549b1c229..ae585f19f 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.vet; +package org.springframework.samples.petclinic.repository; import java.util.Collection; import org.springframework.cache.annotation.Cacheable; -import org.springframework.dao.DataAccessException; import org.springframework.data.repository.Repository; +import org.springframework.samples.petclinic.model.Vet; import org.springframework.transaction.annotation.Transactional; /** @@ -32,15 +32,29 @@ import org.springframework.transaction.annotation.Transactional; * @author Juergen Hoeller * @author Sam Brannen * @author Michael Isvy + * @author Paul-Emmanuel DOS SANTOS FACAO */ public interface VetRepository extends Repository { + /** + * Retrieve a {@link Vet} from the data store by id. + * @param id the id to search for + * @return the {@link Vet} if found + */ + Vet findById(Integer id); + /** * Retrieve all Vets from the data store. * @return a Collection of Vets */ @Transactional(readOnly = true) @Cacheable("vets") - Collection findAll() throws DataAccessException; + Collection findAll(); + + /** + * Save a {@link Vet} to the data store, either inserting or updating it. + * @param vet the {@link Vet} to save + */ + void save(Vet vet); } diff --git a/src/main/java/org/springframework/samples/petclinic/visit/VisitRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java similarity index 72% rename from src/main/java/org/springframework/samples/petclinic/visit/VisitRepository.java rename to src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java index d5a3334c6..06fe23dd8 100644 --- a/src/main/java/org/springframework/samples/petclinic/visit/VisitRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.visit; +package org.springframework.samples.petclinic.repository; +import java.util.Collection; import java.util.List; -import org.springframework.dao.DataAccessException; import org.springframework.data.repository.Repository; import org.springframework.samples.petclinic.model.BaseEntity; +import org.springframework.samples.petclinic.model.Visit; /** * Repository class for Visit domain objects All method names are compliant @@ -31,6 +32,7 @@ import org.springframework.samples.petclinic.model.BaseEntity; * @author Juergen Hoeller * @author Sam Brannen * @author Michael Isvy + * @author Paul-Emmanuel DOS SANTOS FACAO */ public interface VisitRepository extends Repository { @@ -39,8 +41,21 @@ public interface VisitRepository extends Repository { * @param visit the Visit to save * @see BaseEntity#isNew */ - void save(Visit visit) throws DataAccessException; + void save(Visit visit); + + /** + * Retrieve a {@link Visit} from the data store by id. + * @param id the id to search for + * @return the {@link Visit} if found + */ + Visit findById(Integer id); List findByPetId(Integer petId); + /** + * Retrieve all {@link Visit}s from the data store + * @return a Collection of {@link Visit}s (or an empty Collection if none + */ + List findAll(); + } diff --git a/src/main/java/org/springframework/samples/petclinic/service/BaseService.java b/src/main/java/org/springframework/samples/petclinic/service/BaseService.java new file mode 100644 index 000000000..5b4cdf5de --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/BaseService.java @@ -0,0 +1,58 @@ +package org.springframework.samples.petclinic.service; + +import java.util.List; + +/** + * Interface for all services + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public interface BaseService { + + /** + * Convert Data Transfert Object to Entity Model + * @param dto DTO + * @return Entity Model + */ + E dtoToEntity(D dto); + + /** + * Convert Entity Model to Data Transfert Object + * @param entity Entity Model + * @return DTO + */ + D entityToDTO(E entity); + + /** + * Convert Entities Models Collection to Data Transfert Object Collection + * @param entities Collection of Entity Model + * @return Collection of DTO + */ + List entitiesToDTOS(List entities); + + /** + * Convert Entities Models Collection to Data Transfert Object Collection + * @param dtos Collection of DTO + * @return Collection of Entity Model + */ + List dtosToEntities(List dtos); + + /** + * Get DTO object from repository by his ID + * @param id identify object to be found + * @return + */ + D findById(int id); + + /** + * Get all DTO objects from repository + * @return + */ + List findAll(); + + /** + * Save DTO object to repository + */ + void save(D dto); + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/OwnerService.java b/src/main/java/org/springframework/samples/petclinic/service/OwnerService.java new file mode 100644 index 000000000..675b7b639 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/OwnerService.java @@ -0,0 +1,112 @@ +package org.springframework.samples.petclinic.service; + +import org.modelmapper.ModelMapper; +import org.modelmapper.internal.util.Lists; +import org.springframework.samples.petclinic.dto.OwnerDTO; +import org.springframework.samples.petclinic.dto.PetDTO; +import org.springframework.samples.petclinic.model.Owner; +import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.repository.PetTypeRepository; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Simple Service between Owner entity and OwnerDTO Data Transfert Object. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Service("OwnerService") +public class OwnerService implements BaseService { + + private final OwnerRepository ownerRepository; + + private final PetRepository petRepository; + + private final ModelMapper modelMapper = new ModelMapper(); + + private PetService petService; + + public OwnerService(OwnerRepository ownerRepository, PetRepository petRepository, + PetTypeRepository petTypeRepository, VisitRepository visitRepository) { + this.ownerRepository = ownerRepository; + this.petRepository = petRepository; + petService = new PetService(petRepository, petTypeRepository, visitRepository); + } + + @Override + public Owner dtoToEntity(OwnerDTO dto) { + if (dto != null) { + Owner owner = modelMapper.map(dto, Owner.class); + dto.getPets().forEach(petDTO -> { + Pet pet = modelMapper.map(petDTO, Pet.class); + pet.setOwner(owner); + owner.addPet(pet); + }); + return owner; + } + + return new Owner(); + } + + @Override + public OwnerDTO entityToDTO(Owner entity) { + if (entity != null) { + OwnerDTO ownerDTO = modelMapper.map(entity, OwnerDTO.class); + entity.getPets().forEach(pet -> { + PetDTO petDTO = modelMapper.map(pet, PetDTO.class); + petDTO.setOwner(ownerDTO); + ownerDTO.addPet(petDTO); + }); + return ownerDTO; + } + + return new OwnerDTO(); + } + + @Override + public List entitiesToDTOS(List entities) { + List dtos = new ArrayList<>(); + + entities.forEach(entity -> dtos.add(entityToDTO(entity))); + + return dtos; + } + + @Override + public List dtosToEntities(List dtos) { + List entities = new ArrayList<>(); + + dtos.forEach(dto -> entities.add(dtoToEntity(dto))); + + return entities; + } + + @Override + public OwnerDTO findById(int ownerId) { + Owner owner = ownerRepository.findById(ownerId); + return entityToDTO(owner); + } + + @Override + public List findAll() { + return entitiesToDTOS(ownerRepository.findAll()); + } + + @Override + public void save(OwnerDTO ownerDTO) { + Owner owner = dtoToEntity(ownerDTO); + ownerRepository.save(owner); + } + + public List findByLastName(String lastName) { + Collection owners = ownerRepository.findByLastName(lastName); + return entitiesToDTOS(Lists.from(owners.iterator())); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/PetService.java b/src/main/java/org/springframework/samples/petclinic/service/PetService.java new file mode 100644 index 000000000..20c74b15d --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/PetService.java @@ -0,0 +1,134 @@ +package org.springframework.samples.petclinic.service; + +import org.modelmapper.ModelMapper; +import org.springframework.samples.petclinic.dto.OwnerDTO; +import org.springframework.samples.petclinic.dto.PetDTO; +import org.springframework.samples.petclinic.dto.PetTypeDTO; +import org.springframework.samples.petclinic.model.Owner; +import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.repository.PetTypeRepository; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple Service between Pet entity and PetDTO Data Transfert Object. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Service("PetService") +public class PetService implements BaseService { + + private final PetRepository petRepository; + + private final PetTypeService petTypeService; + + private final PetTypeRepository petTypeRepository; + + private final VisitService visitService; + + private final ModelMapper modelMapper = new ModelMapper(); + + public PetService(PetRepository petRepository, PetTypeRepository petTypeRepository, + VisitRepository visitRepository) { + this.petRepository = petRepository; + this.petTypeRepository = petTypeRepository; + this.visitService = new VisitService(visitRepository); + this.petTypeService = new PetTypeService(petTypeRepository); + } + + @Override + public Pet dtoToEntity(PetDTO dto) { + if (dto != null) { + Pet pet = modelMapper.map(dto, Pet.class); + Owner owner = modelMapper.map(dto.getOwner(), Owner.class); + + dto.getVisits().forEach(visitDTO -> pet.addVisit(visitService.dtoToEntity(visitDTO))); + + dto.getOwner().getPets().forEach(petDTO -> { + if (dto.getId() == null || petDTO.getId().equals(dto.getId())) { + owner.addPet(pet); + } + else { + Pet otherPet = modelMapper.map(petDTO, Pet.class); + otherPet.setOwner(owner); + owner.addPet(otherPet); + } + }); + pet.setOwner(owner); + return pet; + } + + return new Pet(); + } + + @Override + public PetDTO entityToDTO(Pet entity) { + if (entity != null) { + PetDTO petDTO = modelMapper.map(entity, PetDTO.class); + OwnerDTO ownerDTO = modelMapper.map(entity.getOwner(), OwnerDTO.class); + + petRepository.findByOwnerId(ownerDTO.getId()).forEach(pet -> { + PetDTO otherPetDTO = modelMapper.map(pet, PetDTO.class); + otherPetDTO.setOwner(ownerDTO); + ownerDTO.addPet(otherPetDTO); + }); + + entity.getVisits().forEach(visit -> petDTO.addVisit(visitService.entityToDTO(visit))); + + petDTO.setOwner(ownerDTO); + return petDTO; + } + + return new PetDTO(); + } + + @Override + public List entitiesToDTOS(List entities) { + List dtos = new ArrayList<>(); + + entities.forEach(entity -> dtos.add(entityToDTO(entity))); + + return dtos; + } + + @Override + public List dtosToEntities(List dtos) { + List entities = new ArrayList<>(); + + dtos.forEach(dto -> entities.add(dtoToEntity(dto))); + + return entities; + } + + @Override + public PetDTO findById(int petId) { + Pet pet = petRepository.findById(petId); + return entityToDTO(pet); + } + + @Override + public List findAll() { + return entitiesToDTOS(petRepository.findAll()); + } + + @Override + public void save(PetDTO petDTO) { + petRepository.save(dtoToEntity(petDTO)); + } + + public List findByOwnerId(int id) { + return entitiesToDTOS(petRepository.findByOwnerId(id)); + } + + public List findPetTypes() { + List petTypes = petRepository.findPetTypes(); + + return petTypeService.entitiesToDTOS(petTypes); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/PetTypeService.java b/src/main/java/org/springframework/samples/petclinic/service/PetTypeService.java new file mode 100644 index 000000000..23c97f0a9 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/PetTypeService.java @@ -0,0 +1,79 @@ +package org.springframework.samples.petclinic.service; + +import org.modelmapper.ModelMapper; +import org.springframework.samples.petclinic.dto.PetTypeDTO; +import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.repository.PetTypeRepository; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple Service between PetType entity and PetTypeDTO Data Transfert Object. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Service("PerTypeService") +public class PetTypeService implements BaseService { + + private final PetTypeRepository petTypeRepository; + + private final ModelMapper modelMapper = new ModelMapper(); + + public PetTypeService(PetTypeRepository petTypeRepository) { + this.petTypeRepository = petTypeRepository; + } + + @Override + public PetType dtoToEntity(PetTypeDTO dto) { + if (dto != null) { + return modelMapper.map(dto, PetType.class); + } + + return new PetType(); + } + + @Override + public PetTypeDTO entityToDTO(PetType entity) { + if (entity != null) { + return modelMapper.map(entity, PetTypeDTO.class); + } + + return new PetTypeDTO(); + } + + @Override + public List entitiesToDTOS(List entities) { + List dtos = new ArrayList<>(); + + entities.forEach(entity -> dtos.add(entityToDTO(entity))); + + return dtos; + } + + @Override + public List dtosToEntities(List dtos) { + List entities = new ArrayList<>(); + + dtos.forEach(dto -> entities.add(dtoToEntity(dto))); + + return entities; + } + + @Override + public PetTypeDTO findById(int id) { + return entityToDTO(petTypeRepository.findById(id)); + } + + @Override + public List findAll() { + return entitiesToDTOS(petTypeRepository.findAll()); + } + + @Override + public void save(PetTypeDTO dto) { + petTypeRepository.save(dtoToEntity(dto)); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/SpecialtyService.java b/src/main/java/org/springframework/samples/petclinic/service/SpecialtyService.java new file mode 100644 index 000000000..d4eb07cb8 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/SpecialtyService.java @@ -0,0 +1,81 @@ +package org.springframework.samples.petclinic.service; + +import org.modelmapper.ModelMapper; +import org.springframework.samples.petclinic.dto.SpecialtyDTO; +import org.springframework.samples.petclinic.model.Specialty; +import org.springframework.samples.petclinic.repository.SpecialtyRepository; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +/** + * Simple Service between Specialty entity and SpecialtyDTO Data Transfert Object. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Service("SpecialityService") +public class SpecialtyService implements BaseService { + + private final SpecialtyRepository specialtyRepository; + + private final ModelMapper modelMapper = new ModelMapper(); + + public SpecialtyService(SpecialtyRepository specialtyRepository) { + this.specialtyRepository = specialtyRepository; + } + + @Override + public Specialty dtoToEntity(SpecialtyDTO dto) { + if (dto != null) { + return modelMapper.map(dto, Specialty.class); + } + + return new Specialty(); + } + + @Override + public SpecialtyDTO entityToDTO(Specialty entity) { + if (entity != null) { + return modelMapper.map(entity, SpecialtyDTO.class); + } + + return new SpecialtyDTO(); + } + + @Override + public List entitiesToDTOS(List entities) { + List dtos = new ArrayList<>(); + + entities.forEach(entity -> dtos.add(entityToDTO(entity))); + + return dtos; + } + + @Override + public List dtosToEntities(List dtos) { + List entities = new ArrayList<>(); + + dtos.forEach(dto -> entities.add(dtoToEntity(dto))); + + return entities; + } + + @Override + public SpecialtyDTO findById(int id) { + return entityToDTO(specialtyRepository.findById(id)); + } + + @Override + public List findAll() { + return entitiesToDTOS(specialtyRepository.findAll()); + } + + @Override + public void save(SpecialtyDTO dto) { + specialtyRepository.save(dtoToEntity(dto)); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/VetService.java b/src/main/java/org/springframework/samples/petclinic/service/VetService.java new file mode 100644 index 000000000..cc1b59d62 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/VetService.java @@ -0,0 +1,97 @@ +package org.springframework.samples.petclinic.service; + +import org.modelmapper.ModelMapper; +import org.modelmapper.internal.util.Lists; +import org.springframework.samples.petclinic.dto.SpecialtyDTO; +import org.springframework.samples.petclinic.dto.VetDTO; +import org.springframework.samples.petclinic.model.Specialty; +import org.springframework.samples.petclinic.repository.SpecialtyRepository; +import org.springframework.samples.petclinic.repository.VetRepository; +import org.springframework.samples.petclinic.model.Vet; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +/** + * Simple Service between Vet entity and VetDTO Data Transfert Object. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Service("VetService") +public class VetService implements BaseService { + + private final VetRepository vetRepository; + + private final SpecialtyService specialtyService; + + private final ModelMapper modelMapper = new ModelMapper(); + + public VetService(VetRepository vetRepository, SpecialtyRepository specialtyRepository) { + this.vetRepository = vetRepository; + this.specialtyService = new SpecialtyService(specialtyRepository); + } + + @Override + public Vet dtoToEntity(VetDTO dto) { + if (dto != null) { + Vet vet = modelMapper.map(dto, Vet.class); + dto.getSpecialties().forEach(specialtyDTO -> { + Specialty specialty = specialtyService.dtoToEntity(specialtyDTO); + vet.addSpecialty(specialty); + }); + return vet; + } + + return new Vet(); + } + + @Override + public VetDTO entityToDTO(Vet entity) { + if (entity != null) { + VetDTO vetDTO = modelMapper.map(entity, VetDTO.class); + entity.getSpecialties().forEach(specialty -> { + SpecialtyDTO specialtyDTO = specialtyService.entityToDTO(specialty); + vetDTO.addSpecialty(specialtyDTO); + }); + return vetDTO; + } + return new VetDTO(); + } + + @Override + public List entitiesToDTOS(List entities) { + List dtos = new ArrayList<>(); + + entities.forEach(entity -> dtos.add(entityToDTO(entity))); + + return dtos; + } + + @Override + public List dtosToEntities(List dtos) { + List entities = new ArrayList<>(); + + dtos.forEach(dto -> entities.add(dtoToEntity(dto))); + + return entities; + } + + @Override + public VetDTO findById(int id) { + return entityToDTO(vetRepository.findById(id)); + } + + public List findAll() { + Collection vets = vetRepository.findAll(); + return entitiesToDTOS(Lists.from(vets.iterator())); + } + + @Override + public void save(VetDTO dto) { + vetRepository.save(dtoToEntity(dto)); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/VisitService.java b/src/main/java/org/springframework/samples/petclinic/service/VisitService.java new file mode 100644 index 000000000..8f627cf80 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/VisitService.java @@ -0,0 +1,93 @@ +package org.springframework.samples.petclinic.service; + +import org.modelmapper.ModelMapper; +import org.springframework.samples.petclinic.dto.VisitDTO; +import org.springframework.samples.petclinic.model.Visit; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +/** + * Simple Service between Visit entity and VisitDTO Data Transfert Object. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Service("VisitService") +public class VisitService implements BaseService { + + private final VisitRepository visitRepository; + + private final ModelMapper modelMapper = new ModelMapper(); + + public VisitService(VisitRepository visitRepository) { + this.visitRepository = visitRepository; + } + + @Override + public Visit dtoToEntity(VisitDTO dto) { + if (dto != null) { + return modelMapper.map(dto, Visit.class); + } + + return new Visit(); + } + + @Override + public VisitDTO entityToDTO(Visit entity) { + if (entity != null) { + return modelMapper.map(entity, VisitDTO.class); + } + + return new VisitDTO(); + } + + @Override + public List entitiesToDTOS(List entities) { + List dtos = new ArrayList<>(); + + entities.forEach(entity -> dtos.add(entityToDTO(entity))); + + return dtos; + } + + @Override + public List dtosToEntities(List dtos) { + List entities = new ArrayList<>(); + + dtos.forEach(dto -> entities.add(dtoToEntity(dto))); + + return entities; + } + + @Override + public VisitDTO findById(int id) { + return entityToDTO(visitRepository.findById(id)); + } + + @Override + public List findAll() { + return entitiesToDTOS(visitRepository.findAll()); + } + + @Override + public void save(VisitDTO visitDTO) { + Visit visit = dtoToEntity(visitDTO); + visitRepository.save(visit); + } + + public Collection findByPetId(Integer petId) { + Collection visits = visitRepository.findByPetId(petId); + Collection visitDTOS = new HashSet<>(); + + for (Visit visit : visits) { + visitDTOS.add(entityToDTO(visit)); + } + + return visitDTOS; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java b/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java index 0a96582c9..51ba24f22 100755 --- a/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java +++ b/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java @@ -34,9 +34,7 @@ class CacheConfiguration { @Bean public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() { - return cm -> { - cm.createCache("vets", cacheConfiguration()); - }; + return cm -> cm.createCache("vets", cacheConfiguration()); } /** diff --git a/src/main/java/org/springframework/samples/petclinic/validator/PetDTOValidator.java b/src/main/java/org/springframework/samples/petclinic/validator/PetDTOValidator.java new file mode 100644 index 000000000..ede0f9185 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/validator/PetDTOValidator.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2019 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.validator; + +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonError; +import org.springframework.samples.petclinic.dto.PetDTO; +import org.springframework.util.StringUtils; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; + +/** + * Validator for PetDTO forms. + *

+ * We're not using Bean Validation annotations here because it is easier to define such + * validation rule in Java. + *

+ * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class PetDTOValidator implements Validator { + + @Override + public void validate(Object obj, Errors errors) { + PetDTO pet = (PetDTO) obj; + String name = pet.getName(); + // name validation + if (!StringUtils.hasLength(name)) { + errors.rejectValue(CommonAttribute.PET_NAME, CommonError.REQUIRED_ARGS, CommonError.REQUIRED_MESSAGE); + } + + // type validation + if (pet.isNew() && pet.getType() == null) { + errors.rejectValue(CommonAttribute.PET_TYPE, CommonError.REQUIRED_ARGS, CommonError.REQUIRED_MESSAGE); + } + + // birth date validation + if (pet.getBirthDate() == null) { + errors.rejectValue(CommonAttribute.PET_BIRTH_DATE, CommonError.REQUIRED_ARGS, CommonError.REQUIRED_MESSAGE); + } + } + + /** + * This Validator validates *just* Pet instances + */ + @Override + public boolean supports(Class clazz) { + return PetDTO.class.isAssignableFrom(clazz); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetValidator.java b/src/main/java/org/springframework/samples/petclinic/validator/PetValidator.java similarity index 71% rename from src/main/java/org/springframework/samples/petclinic/owner/PetValidator.java rename to src/main/java/org/springframework/samples/petclinic/validator/PetValidator.java index e1370b428..98f4ab025 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetValidator.java +++ b/src/main/java/org/springframework/samples/petclinic/validator/PetValidator.java @@ -13,8 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.validator; +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonError; +import org.springframework.samples.petclinic.model.Pet; import org.springframework.util.StringUtils; import org.springframework.validation.Errors; import org.springframework.validation.Validator; @@ -28,28 +31,27 @@ import org.springframework.validation.Validator; * * @author Ken Krebs * @author Juergen Hoeller + * @author Paul-Emmanuel DOS SANTOS FACAO */ public class PetValidator implements Validator { - 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); + errors.rejectValue(CommonAttribute.PET_NAME, CommonError.REQUIRED_ARGS, CommonError.REQUIRED_MESSAGE); } // type validation if (pet.isNew() && pet.getType() == null) { - errors.rejectValue("type", REQUIRED, REQUIRED); + errors.rejectValue(CommonAttribute.PET_TYPE, CommonError.REQUIRED_ARGS, CommonError.REQUIRED_MESSAGE); } // birth date validation if (pet.getBirthDate() == null) { - errors.rejectValue("birthDate", REQUIRED, REQUIRED); + errors.rejectValue(CommonAttribute.PET_BIRTH_DATE, CommonError.REQUIRED_ARGS, CommonError.REQUIRED_MESSAGE); } } diff --git a/src/main/wro/wro.xml b/src/main/wro/wro.xml index 590156d7e..d4f23be37 100644 --- a/src/main/wro/wro.xml +++ b/src/main/wro/wro.xml @@ -1,6 +1,7 @@ - + classpath:META-INF/resources/webjars/bootstrap/3.3.6/less/bootstrap.less /petclinic.less - + diff --git a/src/test/java/org/springframework/samples/petclinic/PetclinicIntegrationTests.java b/src/test/java/org/springframework/samples/petclinic/PetclinicIntegrationTests.java index 226db01fe..90736badb 100644 --- a/src/test/java/org/springframework/samples/petclinic/PetclinicIntegrationTests.java +++ b/src/test/java/org/springframework/samples/petclinic/PetclinicIntegrationTests.java @@ -19,7 +19,7 @@ package org.springframework.samples.petclinic; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.samples.petclinic.vet.VetRepository; +import org.springframework.samples.petclinic.repository.VetRepository; @SpringBootTest class PetclinicIntegrationTests { diff --git a/src/test/java/org/springframework/samples/petclinic/controller/OwnerControllerTests.java b/src/test/java/org/springframework/samples/petclinic/controller/OwnerControllerTests.java new file mode 100644 index 000000000..ac1018907 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/controller/OwnerControllerTests.java @@ -0,0 +1,244 @@ +/* + * Copyright 2012-2019 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.controller; + +import java.time.LocalDate; +import java.util.Collections; +import java.util.List; + +import org.assertj.core.util.Lists; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonEndPoint; +import org.springframework.samples.petclinic.common.CommonView; +import org.springframework.samples.petclinic.dto.OwnerDTO; +import org.springframework.samples.petclinic.dto.PetDTO; +import org.springframework.samples.petclinic.dto.PetTypeDTO; +import org.springframework.samples.petclinic.dto.VisitDTO; +import org.springframework.samples.petclinic.service.OwnerService; +import org.springframework.samples.petclinic.service.VisitService; +import org.springframework.test.web.servlet.MockMvc; + +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +/** + * Test class for {@link OwnerController} + * + * @author Colin But + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@WebMvcTest(OwnerController.class) +class OwnerControllerTests { + + private static final int TEST_OWNER_ID = 1; + + @Autowired + private MockMvc mockMvc; + + @MockBean + private OwnerService owners; + + @MockBean + private VisitService visits; + + private OwnerDTO george; + + @BeforeEach + void setup() { + george = new OwnerDTO(); + george.setId(TEST_OWNER_ID); + george.setFirstName("George"); + george.setLastName("Franklin"); + george.setAddress("110 W. Liberty St."); + george.setCity("Madison"); + george.setTelephone("6085551023"); + PetDTO max = new PetDTO(); + PetTypeDTO dog = new PetTypeDTO(); + dog.setName("dog"); + max.setId(1); + max.setType(dog); + max.setName("Max"); + max.setBirthDate(LocalDate.now()); + george.setPetsInternal(Collections.singleton(max)); + given(this.owners.findById(TEST_OWNER_ID)).willReturn(george); + VisitDTO visit = new VisitDTO(); + visit.setDate(LocalDate.now()); + given(this.visits.findByPetId(max.getId())).willReturn(Collections.singletonList(visit)); + } + + @Test + @Tag("initCreationForm") + void testInitCreationForm() throws Exception { + mockMvc.perform(get(CommonEndPoint.OWNERS_NEW)).andExpect(status().isOk()) + .andExpect(model().attributeExists(CommonAttribute.OWNER)) + .andExpect(view().name(CommonView.OWNER_CREATE_OR_UPDATE)); + } + + @Test + @Tag("processCreationForm") + void testProcessCreationFormSuccess() throws Exception { + mockMvc.perform(post("/owners/new").param(CommonAttribute.OWNER_FIRST_NAME, "Joe") + .param(CommonAttribute.OWNER_LAST_NAME, "Bloggs") + .param(CommonAttribute.OWNER_ADDRESS, "123 Caramel Street").param(CommonAttribute.OWNER_CITY, "London") + .param(CommonAttribute.OWNER_PHONE, "01316761638")).andExpect(status().is3xxRedirection()); + } + + @Test + @Tag("processCreationForm") + void testProcessCreationFormHasErrors() throws Exception { + mockMvc.perform(post(CommonEndPoint.OWNERS_NEW).param(CommonAttribute.OWNER_FIRST_NAME, "Joe") + .param(CommonAttribute.OWNER_LAST_NAME, "Bloggs").param(CommonAttribute.OWNER_CITY, "London")) + .andExpect(status().isOk()).andExpect(model().attributeHasErrors(CommonAttribute.OWNER)) + .andExpect(model().attributeHasFieldErrors(CommonAttribute.OWNER, CommonAttribute.OWNER_ADDRESS)) + .andExpect(model().attributeHasFieldErrors(CommonAttribute.OWNER, CommonAttribute.OWNER_PHONE)) + .andExpect(view().name(CommonView.OWNER_CREATE_OR_UPDATE)); + } + + @Test + @Tag("initFindForm") + void testInitFindForm() throws Exception { + mockMvc.perform(get(CommonEndPoint.OWNERS_FIND)).andExpect(status().isOk()) + .andExpect(model().attributeExists(CommonAttribute.OWNER)) + .andExpect(view().name(CommonView.OWNER_FIND_OWNERS)); + } + + @Test + @Tag("processFindForm") + void testProcessFindFormSuccess() throws Exception { + given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new OwnerDTO())); + + mockMvc.perform(get(CommonEndPoint.OWNERS)).andExpect(status().isOk()) + .andExpect(view().name(CommonView.OWNER_OWNERS_LIST)); + } + + @Test + @Tag("processFindForm") + void testProcessFindFormByLastName() throws Exception { + given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george)); + + mockMvc.perform(get(CommonEndPoint.OWNERS).param(CommonAttribute.OWNER_LAST_NAME, "Franklin")) + .andExpect(status().is3xxRedirection()) + .andExpect(view().name(CommonView.OWNER_OWNERS_R + TEST_OWNER_ID)); + } + + @Test + @Tag("processFindForm") + void testProcessFindFormNoOwnersFound() throws Exception { + mockMvc.perform(get(CommonEndPoint.OWNERS).param(CommonAttribute.OWNER_LAST_NAME, "Unknown Surname")) + .andExpect(status().isOk()) + .andExpect(model().attributeHasFieldErrors(CommonAttribute.OWNER, CommonAttribute.OWNER_LAST_NAME)) + .andExpect(model().attributeHasFieldErrorCode(CommonAttribute.OWNER, CommonAttribute.OWNER_LAST_NAME, + "notFound")) + .andExpect(view().name(CommonView.OWNER_FIND_OWNERS)); + } + + @Test + @Tag("initUpdateOwnerForm") + void testInitUpdateOwnerForm() throws Exception { + mockMvc.perform(get(CommonEndPoint.OWNERS_ID_EDIT, TEST_OWNER_ID)).andExpect(status().isOk()) + .andExpect(model().attributeExists(CommonAttribute.OWNER)) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_LAST_NAME, is("Franklin")))) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_FIRST_NAME, is("George")))) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_ADDRESS, is("110 W. Liberty St.")))) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_CITY, is("Madison")))) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_PHONE, is("6085551023")))) + .andExpect(view().name(CommonView.OWNER_CREATE_OR_UPDATE)); + } + + @Test + @Tag("processUpdateOwnerForm") + void testProcessUpdateOwnerFormSuccess() throws Exception { + mockMvc.perform(post(CommonEndPoint.OWNERS_ID_EDIT, TEST_OWNER_ID) + .param(CommonAttribute.OWNER_FIRST_NAME, "Joe").param(CommonAttribute.OWNER_LAST_NAME, "Bloggs") + .param(CommonAttribute.OWNER_ADDRESS, "123 Caramel Street").param(CommonAttribute.OWNER_CITY, "London") + .param(CommonAttribute.OWNER_PHONE, "01616291589")).andExpect(status().is3xxRedirection()) + .andExpect(view().name(CommonView.OWNER_OWNERS_ID_R)); + } + + @Test + @Tag("processUpdateOwnerForm") + void testProcessUpdateOwnerFormHasErrors() throws Exception { + mockMvc.perform( + post(CommonEndPoint.OWNERS_ID_EDIT, TEST_OWNER_ID).param(CommonAttribute.OWNER_FIRST_NAME, "Joe") + .param(CommonAttribute.OWNER_LAST_NAME, "Bloggs").param(CommonAttribute.OWNER_CITY, "London")) + .andExpect(status().isOk()).andExpect(model().attributeHasErrors(CommonAttribute.OWNER)) + .andExpect(model().attributeHasFieldErrors(CommonAttribute.OWNER, CommonAttribute.OWNER_ADDRESS)) + .andExpect(model().attributeHasFieldErrors(CommonAttribute.OWNER, CommonAttribute.OWNER_PHONE)) + .andExpect(view().name(CommonView.OWNER_CREATE_OR_UPDATE)); + } + + @Test + @Tag("processUpdateOwnerForm") + void testShowOwner() throws Exception { + mockMvc.perform(get(CommonEndPoint.OWNERS_ID, TEST_OWNER_ID)).andExpect(status().isOk()) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_LAST_NAME, is("Franklin")))) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_FIRST_NAME, is("George")))) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_ADDRESS, is("110 W. Liberty St.")))) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_CITY, is("Madison")))) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_PHONE, is("6085551023")))) + .andExpect( + model().attribute(CommonAttribute.OWNER, hasProperty(CommonAttribute.OWNER_PETS, not(empty())))) + .andExpect(model().attribute(CommonAttribute.OWNER, + hasProperty(CommonAttribute.OWNER_PETS, new BaseMatcher>() { + + @Override + public boolean matches(Object item) { + @SuppressWarnings("unchecked") + List pets = (List) item; + PetDTO pet = pets.get(0); + if (pet.getVisits().isEmpty()) { + return false; + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText("Max did not have any visits"); + } + }))) + .andExpect(view().name(CommonView.OWNER_DETAILS)); + } + +} diff --git a/src/test/java/org/springframework/samples/petclinic/controller/PetControllerTests.java b/src/test/java/org/springframework/samples/petclinic/controller/PetControllerTests.java new file mode 100644 index 000000000..717507c5b --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/controller/PetControllerTests.java @@ -0,0 +1,142 @@ +/* + * Copyright 2012-2019 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.controller; + +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonEndPoint; +import org.springframework.samples.petclinic.common.CommonError; +import org.springframework.samples.petclinic.common.CommonView; +import org.springframework.samples.petclinic.dto.OwnerDTO; +import org.springframework.samples.petclinic.dto.PetDTO; +import org.springframework.samples.petclinic.dto.PetTypeDTO; +import org.springframework.samples.petclinic.formatter.PetTypeFormatter; +import org.springframework.samples.petclinic.service.OwnerService; +import org.springframework.samples.petclinic.service.PetService; +import org.springframework.samples.petclinic.service.PetTypeService; +import org.springframework.test.web.servlet.MockMvc; + +/** + * Test class for the {@link PetController} + * + * @author Colin But + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@WebMvcTest(value = PetController.class, + includeFilters = @ComponentScan.Filter(value = PetTypeFormatter.class, type = FilterType.ASSIGNABLE_TYPE)) +class PetControllerTests { + + private static final int TEST_OWNER_ID = 1; + + private static final int TEST_PET_ID = 1; + + @Autowired + private MockMvc mockMvc; + + @MockBean + private PetService petService; + + @MockBean + private PetTypeService petTypeService; + + @MockBean + private OwnerService ownerService; + + @BeforeEach + void setup() { + PetTypeDTO cat = new PetTypeDTO(); + cat.setId(3); + cat.setName("hamster"); + + given(this.ownerService.findById(TEST_OWNER_ID)).willReturn(new OwnerDTO()); + given(this.petService.findById(TEST_PET_ID)).willReturn(new PetDTO()); + given(this.petService.findPetTypes()).willReturn(Lists.newArrayList(cat)); + } + + @Test + @Tag("initCreationForm") + void testInitCreationForm() throws Exception { + mockMvc.perform(get(CommonEndPoint.OWNERS_ID + CommonEndPoint.PETS_NEW, TEST_OWNER_ID)) + .andExpect(status().isOk()).andExpect(view().name(CommonView.PET_CREATE_OR_UPDATE)) + .andExpect(model().attributeExists(CommonAttribute.PET)); + } + + @Test + @Tag("processCreationForm") + void testProcessCreationFormSuccess() throws Exception { + mockMvc.perform(post(CommonEndPoint.OWNERS_ID + CommonEndPoint.PETS_NEW, TEST_OWNER_ID) + .param(CommonAttribute.PET_NAME, "Betty").param(CommonAttribute.PET_TYPE, "hamster") + .param(CommonAttribute.PET_BIRTH_DATE, "2015-02-12")).andExpect(status().is3xxRedirection()) + .andExpect(view().name(CommonView.OWNER_OWNERS_ID_R)); + } + + @Test + @Tag("processCreationForm") + void testProcessCreationFormHasErrors() throws Exception { + mockMvc.perform(post(CommonEndPoint.OWNERS_ID + CommonEndPoint.PETS_NEW, TEST_OWNER_ID) + .param(CommonAttribute.PET_NAME, "Betty").param(CommonAttribute.PET_BIRTH_DATE, "2015-02-12")) + .andExpect(model().attributeHasNoErrors(CommonAttribute.OWNER)) + .andExpect(model().attributeHasErrors(CommonAttribute.PET)) + .andExpect(model().attributeHasFieldErrors(CommonAttribute.PET, CommonAttribute.PET_TYPE)) + .andExpect(model().attributeHasFieldErrorCode(CommonAttribute.PET, CommonAttribute.PET_TYPE, + CommonError.REQUIRED_ARGS)) + .andExpect(status().isOk()).andExpect(view().name(CommonView.PET_CREATE_OR_UPDATE)); + } + + @Test + @Tag("initUpdateForm") + void testInitUpdateForm() throws Exception { + mockMvc.perform(get(CommonEndPoint.OWNERS_ID + CommonEndPoint.PETS_ID_EDIT, TEST_OWNER_ID, TEST_PET_ID)) + .andExpect(status().isOk()).andExpect(model().attributeExists(CommonAttribute.PET)) + .andExpect(view().name(CommonView.PET_CREATE_OR_UPDATE)); + } + + @Test + @Tag("processUpdateForm") + void testProcessUpdateFormSuccess() throws Exception { + mockMvc.perform(post(CommonEndPoint.OWNERS_ID + CommonEndPoint.PETS_ID_EDIT, TEST_OWNER_ID, TEST_PET_ID) + .param(CommonAttribute.PET_NAME, "Betty").param(CommonAttribute.PET_TYPE, "hamster") + .param(CommonAttribute.PET_BIRTH_DATE, "2015-02-12")).andExpect(status().is3xxRedirection()) + .andExpect(view().name(CommonView.OWNER_OWNERS_ID_R)); + } + + @Test + @Tag("processUpdateForm") + void testProcessUpdateFormHasErrors() throws Exception { + mockMvc.perform(post(CommonEndPoint.OWNERS_ID + CommonEndPoint.PETS_ID_EDIT, TEST_OWNER_ID, TEST_PET_ID) + .param(CommonAttribute.PET_NAME, "Betty").param(CommonAttribute.PET_BIRTH_DATE, "2015-02-12")) + .andExpect(model().attributeHasNoErrors(CommonAttribute.OWNER)) + .andExpect(model().attributeHasErrors(CommonAttribute.PET)).andExpect(status().isOk()) + .andExpect(view().name(CommonView.PET_CREATE_OR_UPDATE)); + } + +} diff --git a/src/test/java/org/springframework/samples/petclinic/vet/VetControllerTests.java b/src/test/java/org/springframework/samples/petclinic/controller/VetControllerTests.java similarity index 67% rename from src/test/java/org/springframework/samples/petclinic/vet/VetControllerTests.java rename to src/test/java/org/springframework/samples/petclinic/controller/VetControllerTests.java index fd537bee2..c3eef01b1 100644 --- a/src/test/java/org/springframework/samples/petclinic/vet/VetControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/controller/VetControllerTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.samples.petclinic.vet; +package org.springframework.samples.petclinic.controller; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -26,16 +26,26 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import org.assertj.core.util.Lists; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonEndPoint; +import org.springframework.samples.petclinic.common.CommonView; +import org.springframework.samples.petclinic.dto.SpecialtyDTO; +import org.springframework.samples.petclinic.dto.VetDTO; +import org.springframework.samples.petclinic.service.VetService; +import org.springframework.samples.petclinic.model.Specialty; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; /** * Test class for the {@link VetController} + * + * @author Paul-Emmanuel DOS SANTOS FACAO */ @WebMvcTest(VetController.class) class VetControllerTests { @@ -44,35 +54,39 @@ class VetControllerTests { private MockMvc mockMvc; @MockBean - private VetRepository vets; + private VetService vetService; @BeforeEach void setup() { - Vet james = new Vet(); + VetDTO james = new VetDTO(); james.setFirstName("James"); james.setLastName("Carter"); james.setId(1); - Vet helen = new Vet(); + VetDTO helen = new VetDTO(); helen.setFirstName("Helen"); helen.setLastName("Leary"); helen.setId(2); - Specialty radiology = new Specialty(); + SpecialtyDTO radiology = new SpecialtyDTO(); radiology.setId(1); radiology.setName("radiology"); helen.addSpecialty(radiology); - given(this.vets.findAll()).willReturn(Lists.newArrayList(james, helen)); + given(this.vetService.findAll()).willReturn(Lists.newArrayList(james, helen)); } @Test + @Tag("showVetList") void testShowVetListHtml() throws Exception { - mockMvc.perform(get("/vets.html")).andExpect(status().isOk()).andExpect(model().attributeExists("vets")) - .andExpect(view().name("vets/vetList")); + mockMvc.perform(get(CommonEndPoint.VETS_HTML)).andExpect(status().isOk()) + .andExpect(model().attributeExists(CommonAttribute.VETS)) + .andExpect(view().name(CommonView.VET_VETS_LIST)); } @Test + @Tag("showResourcesVetList") void testShowResourcesVetList() throws Exception { - ResultActions actions = mockMvc.perform(get("/vets").accept(MediaType.APPLICATION_JSON)) + ResultActions actions = mockMvc.perform(get(CommonEndPoint.VETS).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); + actions.andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.vetList[0].id").value(1)); } diff --git a/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java b/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerTests.java similarity index 58% rename from src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java rename to src/test/java/org/springframework/samples/petclinic/controller/VisitControllerTests.java index 84bee72df..718bab0f0 100644 --- a/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.controller; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -24,11 +24,17 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.samples.petclinic.visit.VisitRepository; +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonEndPoint; +import org.springframework.samples.petclinic.common.CommonView; +import org.springframework.samples.petclinic.dto.PetDTO; +import org.springframework.samples.petclinic.service.PetService; +import org.springframework.samples.petclinic.service.VisitService; import org.springframework.test.web.servlet.MockMvc; /** @@ -45,34 +51,37 @@ class VisitControllerTests { private MockMvc mockMvc; @MockBean - private VisitRepository visits; + private VisitService visitService; @MockBean - private PetRepository pets; + private PetService petService; @BeforeEach void init() { - given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); + given(this.petService.findById(TEST_PET_ID)).willReturn(new PetDTO()); } @Test + @Tag("initNewVisitForm") void testInitNewVisitForm() throws Exception { - mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)).andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdateVisitForm")); + mockMvc.perform(get(CommonEndPoint.VISITS_NEW, TEST_PET_ID)).andExpect(status().isOk()) + .andExpect(view().name(CommonView.VISIT_CREATE_OR_UPDATE)); } @Test + @Tag("processNewVisitForm") void testProcessNewVisitFormSuccess() throws Exception { - mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George") - .param("description", "Visit Description")).andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); + mockMvc.perform(post(CommonEndPoint.VISITS_NEW, TEST_PET_ID).param(CommonAttribute.NAME, "George") + .param(CommonAttribute.DESCRIPTION, "Visit Description")).andExpect(status().is3xxRedirection()) + .andExpect(view().name(CommonView.OWNER_OWNERS_ID_R)); } @Test + @Tag("processNewVisitForm") void testProcessNewVisitFormHasErrors() throws Exception { - mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George")) - .andExpect(model().attributeHasErrors("visit")).andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdateVisitForm")); + mockMvc.perform(post(CommonEndPoint.VISITS_NEW, TEST_PET_ID).param(CommonAttribute.NAME, "George")) + .andExpect(model().attributeHasErrors(CommonAttribute.VISIT)).andExpect(status().isOk()) + .andExpect(view().name(CommonView.VISIT_CREATE_OR_UPDATE)); } } diff --git a/src/test/java/org/springframework/samples/petclinic/formater/PetTypeDTOFormatterTests.java b/src/test/java/org/springframework/samples/petclinic/formater/PetTypeDTOFormatterTests.java new file mode 100644 index 000000000..a9e8f2e72 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/formater/PetTypeDTOFormatterTests.java @@ -0,0 +1,98 @@ +/* + * Copyright 2012-2019 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.formater; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.samples.petclinic.dto.PetTypeDTO; +import org.springframework.samples.petclinic.formatter.PetTypeFormatter; +import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.service.PetService; +import org.springframework.samples.petclinic.service.PetTypeService; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; + +/** + * Test class for {@link PetTypeFormatter} + * + * @author Colin But + */ +@ExtendWith(MockitoExtension.class) +class PetTypeDTOFormatterTests { + + @Mock + private PetService petService; + + private PetTypeFormatter petTypeFormatter; + + @BeforeEach + void setup() { + this.petTypeFormatter = new PetTypeFormatter(petService); + } + + @Test + void testPrint() { + PetTypeDTO petType = new PetTypeDTO(); + petType.setName("Hamster"); + String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH); + assertThat(petTypeName).isEqualTo("Hamster"); + } + + @Test + void shouldParse() throws ParseException { + given(this.petService.findPetTypes()).willReturn(makePetTypes()); + PetTypeDTO petType = petTypeFormatter.parse("Bird", Locale.ENGLISH); + assertThat(petType.getName()).isEqualTo("Bird"); + } + + @Test + void shouldThrowParseException() { + given(this.petService.findPetTypes()).willReturn(makePetTypes()); + Assertions.assertThrows(ParseException.class, () -> petTypeFormatter.parse("Fish", Locale.ENGLISH)); + } + + /** + * Helper method to produce some sample pet types just for test purpose + * @return {@link Collection} of {@link PetType} + */ + private List makePetTypes() { + List petTypes = new ArrayList<>(); + petTypes.add(new PetTypeDTO() { + { + setName("Dog"); + } + }); + petTypes.add(new PetTypeDTO() { + { + setName("Bird"); + } + }); + return petTypes; + } + +} diff --git a/src/test/java/org/springframework/samples/petclinic/owner/PetTypeFormatterTests.java b/src/test/java/org/springframework/samples/petclinic/formater/PetTypeFormatterTests.java similarity index 64% rename from src/test/java/org/springframework/samples/petclinic/owner/PetTypeFormatterTests.java rename to src/test/java/org/springframework/samples/petclinic/formater/PetTypeFormatterTests.java index adb96b69d..902048f72 100644 --- a/src/test/java/org/springframework/samples/petclinic/owner/PetTypeFormatterTests.java +++ b/src/test/java/org/springframework/samples/petclinic/formater/PetTypeFormatterTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.samples.petclinic.owner; +package org.springframework.samples.petclinic.formater; import java.text.ParseException; import java.util.ArrayList; @@ -28,6 +28,11 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.samples.petclinic.dto.PetTypeDTO; +import org.springframework.samples.petclinic.formatter.PetTypeFormatter; +import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.service.PetService; +import org.springframework.samples.petclinic.service.PetTypeService; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -41,18 +46,18 @@ import static org.mockito.BDDMockito.given; class PetTypeFormatterTests { @Mock - private PetRepository pets; + private PetService petService; private PetTypeFormatter petTypeFormatter; @BeforeEach void setup() { - this.petTypeFormatter = new PetTypeFormatter(pets); + this.petTypeFormatter = new PetTypeFormatter(petService); } @Test void testPrint() { - PetType petType = new PetType(); + PetTypeDTO petType = new PetTypeDTO(); petType.setName("Hamster"); String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH); assertThat(petTypeName).isEqualTo("Hamster"); @@ -60,31 +65,29 @@ class PetTypeFormatterTests { @Test void shouldParse() throws ParseException { - given(this.pets.findPetTypes()).willReturn(makePetTypes()); - PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH); + given(this.petService.findPetTypes()).willReturn(makePetTypes()); + PetTypeDTO petType = petTypeFormatter.parse("Bird", Locale.ENGLISH); assertThat(petType.getName()).isEqualTo("Bird"); } @Test - void shouldThrowParseException() throws ParseException { - given(this.pets.findPetTypes()).willReturn(makePetTypes()); - Assertions.assertThrows(ParseException.class, () -> { - petTypeFormatter.parse("Fish", Locale.ENGLISH); - }); + void shouldThrowParseException() { + given(this.petService.findPetTypes()).willReturn(makePetTypes()); + Assertions.assertThrows(ParseException.class, () -> petTypeFormatter.parse("Fish", Locale.ENGLISH)); } /** * Helper method to produce some sample pet types just for test purpose * @return {@link Collection} of {@link PetType} */ - private List makePetTypes() { - List petTypes = new ArrayList<>(); - petTypes.add(new PetType() { + private List makePetTypes() { + List petTypes = new ArrayList<>(); + petTypes.add(new PetTypeDTO() { { setName("Dog"); } }); - petTypes.add(new PetType() { + petTypes.add(new PetTypeDTO() { { setName("Bird"); } diff --git a/src/test/java/org/springframework/samples/petclinic/vet/VetTests.java b/src/test/java/org/springframework/samples/petclinic/model/VetTests.java similarity index 95% rename from src/test/java/org/springframework/samples/petclinic/vet/VetTests.java rename to src/test/java/org/springframework/samples/petclinic/model/VetTests.java index d8df78b85..45066fe9c 100644 --- a/src/test/java/org/springframework/samples/petclinic/vet/VetTests.java +++ b/src/test/java/org/springframework/samples/petclinic/model/VetTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.vet; +package org.springframework.samples.petclinic.model; import org.junit.jupiter.api.Test; import org.springframework.util.SerializationUtils; diff --git a/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java b/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java deleted file mode 100644 index 1d6249c5d..000000000 --- a/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2012-2019 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 java.util.Collections; -import java.util.List; - -import org.assertj.core.util.Lists; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.samples.petclinic.visit.Visit; -import org.springframework.samples.petclinic.visit.VisitRepository; -import org.springframework.test.web.servlet.MockMvc; - -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; - -/** - * Test class for {@link OwnerController} - * - * @author Colin But - */ -@WebMvcTest(OwnerController.class) -class OwnerControllerTests { - - private static final int TEST_OWNER_ID = 1; - - @Autowired - private MockMvc mockMvc; - - @MockBean - private OwnerRepository owners; - - @MockBean - private VisitRepository visits; - - private Owner george; - - @BeforeEach - void setup() { - george = new Owner(); - george.setId(TEST_OWNER_ID); - george.setFirstName("George"); - george.setLastName("Franklin"); - george.setAddress("110 W. Liberty St."); - george.setCity("Madison"); - george.setTelephone("6085551023"); - Pet max = new Pet(); - PetType dog = new PetType(); - dog.setName("dog"); - max.setId(1); - max.setType(dog); - max.setName("Max"); - max.setBirthDate(LocalDate.now()); - george.setPetsInternal(Collections.singleton(max)); - given(this.owners.findById(TEST_OWNER_ID)).willReturn(george); - Visit visit = new Visit(); - visit.setDate(LocalDate.now()); - given(this.visits.findByPetId(max.getId())).willReturn(Collections.singletonList(visit)); - } - - @Test - void testInitCreationForm() throws Exception { - mockMvc.perform(get("/owners/new")).andExpect(status().isOk()).andExpect(model().attributeExists("owner")) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } - - @Test - void testProcessCreationFormSuccess() throws Exception { - mockMvc.perform(post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs") - .param("address", "123 Caramel Street").param("city", "London").param("telephone", "01316761638")) - .andExpect(status().is3xxRedirection()); - } - - @Test - void testProcessCreationFormHasErrors() throws Exception { - mockMvc.perform( - post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs").param("city", "London")) - .andExpect(status().isOk()).andExpect(model().attributeHasErrors("owner")) - .andExpect(model().attributeHasFieldErrors("owner", "address")) - .andExpect(model().attributeHasFieldErrors("owner", "telephone")) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } - - @Test - void testInitFindForm() throws Exception { - mockMvc.perform(get("/owners/find")).andExpect(status().isOk()).andExpect(model().attributeExists("owner")) - .andExpect(view().name("owners/findOwners")); - } - - @Test - void testProcessFindFormSuccess() throws Exception { - given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner())); - mockMvc.perform(get("/owners")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList")); - } - - @Test - void testProcessFindFormByLastName() throws Exception { - given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george)); - mockMvc.perform(get("/owners").param("lastName", "Franklin")).andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID)); - } - - @Test - void testProcessFindFormNoOwnersFound() throws Exception { - mockMvc.perform(get("/owners").param("lastName", "Unknown Surname")).andExpect(status().isOk()) - .andExpect(model().attributeHasFieldErrors("owner", "lastName")) - .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) - .andExpect(view().name("owners/findOwners")); - } - - @Test - void testInitUpdateOwnerForm() throws Exception { - mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)).andExpect(status().isOk()) - .andExpect(model().attributeExists("owner")) - .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) - .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) - .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) - .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) - .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } - - @Test - void testProcessUpdateOwnerFormSuccess() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") - .param("lastName", "Bloggs").param("address", "123 Caramel Street").param("city", "London") - .param("telephone", "01616291589")).andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); - } - - @Test - void testProcessUpdateOwnerFormHasErrors() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") - .param("lastName", "Bloggs").param("city", "London")).andExpect(status().isOk()) - .andExpect(model().attributeHasErrors("owner")) - .andExpect(model().attributeHasFieldErrors("owner", "address")) - .andExpect(model().attributeHasFieldErrors("owner", "telephone")) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } - - @Test - void testShowOwner() throws Exception { - mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)).andExpect(status().isOk()) - .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) - .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) - .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) - .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) - .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) - .andExpect(model().attribute("owner", hasProperty("pets", not(empty())))) - .andExpect(model().attribute("owner", hasProperty("pets", new BaseMatcher>() { - - @Override - public boolean matches(Object item) { - @SuppressWarnings("unchecked") - List pets = (List) item; - Pet pet = pets.get(0); - if (pet.getVisits().isEmpty()) { - return false; - } - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("Max did not have any visits"); - } - }))).andExpect(view().name("owners/ownerDetails")); - } - -} diff --git a/src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java b/src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java deleted file mode 100755 index 47c444a78..000000000 --- a/src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2012-2019 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 static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; - -import org.assertj.core.util.Lists; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.FilterType; -import org.springframework.test.web.servlet.MockMvc; - -/** - * Test class for the {@link PetController} - * - * @author Colin But - */ -@WebMvcTest(value = PetController.class, - includeFilters = @ComponentScan.Filter(value = PetTypeFormatter.class, type = FilterType.ASSIGNABLE_TYPE)) -class PetControllerTests { - - private static final int TEST_OWNER_ID = 1; - - private static final int TEST_PET_ID = 1; - - @Autowired - private MockMvc mockMvc; - - @MockBean - private PetRepository pets; - - @MockBean - private OwnerRepository owners; - - @BeforeEach - void setup() { - PetType cat = new PetType(); - cat.setId(3); - cat.setName("hamster"); - given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat)); - given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner()); - given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); - - } - - @Test - void testInitCreationForm() throws Exception { - mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID)).andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdatePetForm")).andExpect(model().attributeExists("pet")); - } - - @Test - void testProcessCreationFormSuccess() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty") - .param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); - } - - @Test - void testProcessCreationFormHasErrors() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty").param("birthDate", - "2015-02-12")).andExpect(model().attributeHasNoErrors("owner")) - .andExpect(model().attributeHasErrors("pet")).andExpect(model().attributeHasFieldErrors("pet", "type")) - .andExpect(model().attributeHasFieldErrorCode("pet", "type", "required")).andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdatePetForm")); - } - - @Test - void testInitUpdateForm() throws Exception { - mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)) - .andExpect(status().isOk()).andExpect(model().attributeExists("pet")) - .andExpect(view().name("pets/createOrUpdatePetForm")); - } - - @Test - void testProcessUpdateFormSuccess() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty") - .param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); - } - - @Test - void testProcessUpdateFormHasErrors() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty") - .param("birthDate", "2015/02/12")).andExpect(model().attributeHasNoErrors("owner")) - .andExpect(model().attributeHasErrors("pet")).andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdatePetForm")); - } - -} diff --git a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java b/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java index a7f3d9d24..6088c8ae0 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java +++ b/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java @@ -25,15 +25,15 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.ComponentScan; -import org.springframework.samples.petclinic.owner.Owner; -import org.springframework.samples.petclinic.owner.OwnerRepository; -import org.springframework.samples.petclinic.owner.Pet; -import org.springframework.samples.petclinic.owner.PetRepository; -import org.springframework.samples.petclinic.owner.PetType; -import org.springframework.samples.petclinic.vet.Vet; -import org.springframework.samples.petclinic.vet.VetRepository; -import org.springframework.samples.petclinic.visit.Visit; -import org.springframework.samples.petclinic.visit.VisitRepository; +import org.springframework.samples.petclinic.model.Owner; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.model.Vet; +import org.springframework.samples.petclinic.repository.VetRepository; +import org.springframework.samples.petclinic.model.Visit; +import org.springframework.samples.petclinic.repository.VisitRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -112,10 +112,10 @@ class ClinicServiceTests { owner.setCity("Wollongong"); owner.setTelephone("4444444444"); this.owners.save(owner); - assertThat(owner.getId().longValue()).isNotEqualTo(0); + assertThat(owner.getId().longValue()).isNotZero(); owners = this.owners.findByLastName("Schultz"); - assertThat(owners.size()).isEqualTo(found + 1); + assertThat(owners).hasSize(found + 1); } @Test @@ -176,7 +176,7 @@ class ClinicServiceTests { @Test @Transactional - void shouldUpdatePetName() throws Exception { + void shouldUpdatePetName() { Pet pet7 = this.pets.findById(7); String oldName = pet7.getName(); @@ -216,7 +216,7 @@ class ClinicServiceTests { } @Test - void shouldFindVisitsByPetId() throws Exception { + void shouldFindVisitsByPetId() { Collection visits = this.visits.findByPetId(7); assertThat(visits).hasSize(2); Visit[] visitArr = visits.toArray(new Visit[visits.size()]); diff --git a/src/test/java/org/springframework/samples/petclinic/service/OwnerServiceTest.java b/src/test/java/org/springframework/samples/petclinic/service/OwnerServiceTest.java new file mode 100644 index 000000000..0857538ab --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/service/OwnerServiceTest.java @@ -0,0 +1,231 @@ +package org.springframework.samples.petclinic.service; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.samples.petclinic.dto.OwnerDTO; +import org.springframework.samples.petclinic.dto.PetDTO; +import org.springframework.samples.petclinic.dto.PetTypeDTO; +import org.springframework.samples.petclinic.model.Owner; +import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.repository.PetTypeRepository; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@Slf4j +@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class)) +class OwnerServiceTest { + + private final static Integer OWNER_ID = 11; + + private final static String OWNER_FIRST_NAME = "Sam"; + + private final static String OWNER_LAST_NAME = "Schultz"; + + private final static String OWNER_ADDRESS = "4, Evans Street"; + + private final static String OWNER_CITY = "Wollongong"; + + private final static String OWNER_PHONE = "1234567890"; + + private final static Integer PET_ID = 11; + + private final static String PET_NAME = "bowser"; + + private final static String PET_BIRTH_DATE = "2020-07-11"; + + @Autowired + private OwnerRepository ownerRepository; + + @Autowired + private PetRepository petRepository; + + @Autowired + private PetTypeRepository petTypeRepository; + + @Autowired + private VisitRepository visitRepository; + + private PetService petService; + + private OwnerService ownerService; + + private static Owner owner; + + private static OwnerDTO ownerDTO; + + private static Pet pet; + + private static PetDTO petDTO; + + @BeforeEach + void beforeEach() { + petService = new PetService(petRepository, petTypeRepository, visitRepository); + ownerService = new OwnerService(ownerRepository, petRepository, petTypeRepository, visitRepository); + PetTypeService petTypeService = new PetTypeService(petTypeRepository); + Collection petTypeDTOS = petService.findPetTypes(); + PetTypeDTO petTypeDTO = petTypeDTOS.stream().findFirst().get(); + PetType petType = petTypeService.dtoToEntity(petTypeDTO); + pet = new Pet(); + pet.setId(PET_ID); + pet.setName(PET_NAME); + pet.setType(petType); + pet.setBirthDate(LocalDate.parse(PET_BIRTH_DATE)); + petDTO = new PetDTO(); + petDTO.setId(PET_ID); + petDTO.setName(PET_NAME); + petDTO.setType(petTypeDTO); + petDTO.setBirthDate(LocalDate.parse(PET_BIRTH_DATE)); + + owner = new Owner(); + owner.setId(OWNER_ID); + owner.setFirstName(OWNER_FIRST_NAME); + owner.setLastName(OWNER_LAST_NAME); + owner.setAddress(OWNER_ADDRESS); + owner.setCity(OWNER_CITY); + owner.setTelephone(OWNER_PHONE); + owner.addPet(pet); + ownerDTO = new OwnerDTO(); + ownerDTO.setId(OWNER_ID); + ownerDTO.setFirstName(OWNER_FIRST_NAME); + ownerDTO.setLastName(OWNER_LAST_NAME); + ownerDTO.setAddress(OWNER_ADDRESS); + ownerDTO.setCity(OWNER_CITY); + ownerDTO.setTelephone(OWNER_PHONE); + ownerDTO.addPet(petDTO); + } + + @Test + @Tag("dtoToEntity") + @DisplayName("Verify the convertion from DTO to Entity") + void dtoToEntity() { + Owner found = ownerService.dtoToEntity(ownerDTO); + + assertThat(found.getId()).isEqualTo(owner.getId()); + assertThat(found.getFirstName()).isEqualTo(owner.getFirstName()); + assertThat(found.getLastName()).isEqualTo(owner.getLastName()); + assertThat(found.getAddress()).isEqualTo(owner.getAddress()); + assertThat(found.getCity()).isEqualTo(owner.getCity()); + assertThat(found.getTelephone()).isEqualTo(owner.getTelephone()); + + assertThat(found.getPets().size()).isEqualTo(owner.getPets().size()); + + for (Pet pet : found.getPets()) { + assertThat(owner.getPets()).extracting("id").contains(pet.getId()); + } + + } + + @Test + @Tag("entityToDTO") + @DisplayName("Verify the convertion from Entity to DTO") + void entityToDTO() { + OwnerDTO found = ownerService.entityToDTO(owner); + + assertThat(found.getId()).isEqualTo(ownerDTO.getId()); + assertThat(found.getFirstName()).isEqualTo(ownerDTO.getFirstName()); + assertThat(found.getLastName()).isEqualTo(ownerDTO.getLastName()); + assertThat(found.getAddress()).isEqualTo(ownerDTO.getAddress()); + assertThat(found.getCity()).isEqualTo(ownerDTO.getCity()); + assertThat(found.getTelephone()).isEqualTo(ownerDTO.getTelephone()); + assertThat(found.getPets().size()).isEqualTo(ownerDTO.getPets().size()); + + for (PetDTO petDTO : found.getPets()) { + assertThat(ownerDTO.getPets()).extracting("id").contains(petDTO.getId()); + } + } + + @Test + @Tag("dtosToEntities") + @DisplayName("Verify the convertion from DTOs list to Entities list") + void dtosToEntities() { + List ownerDTOS = ownerService.findAll(); + List expected = new ArrayList<>(); + ownerDTOS.forEach(dto -> expected.add(ownerService.dtoToEntity(dto))); + + List found = ownerService.dtosToEntities(ownerDTOS); + + assertThat(found).hasSameSizeAs(expected).containsAll(expected); + } + + @Test + @Tag("entitiesToDTOS") + @DisplayName("Verify the convertion from Entities list to DTOs list") + void entitiesToDTOS() { + List expected = ownerService.findAll(); + List owners = new ArrayList<>(); + expected.forEach(dto -> owners.add(ownerService.dtoToEntity(dto))); + + List found = ownerService.entitiesToDTOS(owners); + + assertThat(found).hasSameSizeAs(expected).containsAll(expected); + } + + @Test + @Tag("findById") + @DisplayName("Verify that we get OwnerDTO by his ID") + void findById() { + List allDTO = ownerService.findAll(); + OwnerDTO expected = allDTO.get(2); + + assertThat(ownerService.findById(expected.getId())).isEqualTo(expected); + } + + @Test + @Tag("findByLastName") + @DisplayName("Verify that we get OwnerDTO by his LastName") + void findByLastName() { + OwnerDTO expected = ownerService.findById(1); + + Optional found = ownerService.findByLastName(expected.getLastName()).stream().findFirst(); + + found.ifPresent(dto -> assertThat(dto).isEqualToComparingFieldByField(expected)); + } + + @Test + @Tag("findAll") + @DisplayName("Verify that the OwnerDTO list contain all previous elements and the new saved one") + void findAll() { + List expected = ownerService.findAll(); + + assertThat(expected).doesNotContain(ownerDTO); + ownerService.save(ownerDTO); + + List found = ownerService.findAll(); + + assertThat(found).hasSize(expected.size() + 1) + .usingElementComparatorOnFields("lastName", "firstName", "address", "city", "telephone") + .contains(ownerDTO).containsAnyElementsOf(expected); + + } + + @Test + @Tag("save") + @DisplayName("Verify that all OwnerDTO list contain the new saved one") + void save() { + assertThat(ownerService.findAll()).doesNotContain(ownerDTO); + + ownerService.save(ownerDTO); + List found = ownerService.findAll(); + + assertThat(found).usingElementComparatorOnFields("lastName", "firstName", "address", "city", "telephone") + .contains(ownerDTO); + } + +} diff --git a/src/test/java/org/springframework/samples/petclinic/service/PetServiceTest.java b/src/test/java/org/springframework/samples/petclinic/service/PetServiceTest.java new file mode 100644 index 000000000..1eab22b6f --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/service/PetServiceTest.java @@ -0,0 +1,176 @@ +package org.springframework.samples.petclinic.service; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.samples.petclinic.dto.OwnerDTO; +import org.springframework.samples.petclinic.dto.PetDTO; +import org.springframework.samples.petclinic.dto.PetTypeDTO; +import org.springframework.samples.petclinic.model.Owner; +import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.repository.PetTypeRepository; +import org.springframework.samples.petclinic.repository.VetRepository; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@Slf4j +@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class)) +class PetServiceTest { + + private final static Integer OWNER_ID = 5; + + private final static Integer PET_ID = 14; + + private final static String PET_NAME = "bowser"; + + private final static String PET_BIRTH_DATE = "2020-07-11"; + + @Autowired + private OwnerService ownerService; + + @Autowired + private PetRepository petRepository; + + @Autowired + private PetTypeRepository petTypeRepository; + + @Autowired + private VisitRepository visitRepository; + + private PetService petService; + + private static Owner owner; + + private static Pet pet; + + private static PetDTO petDTO; + + @BeforeEach + void beforeEach() { + this.petService = new PetService(petRepository, petTypeRepository, visitRepository); + + PetTypeService petTypeService = new PetTypeService(petTypeRepository); + Collection petTypeDTOS = petService.findPetTypes(); + PetTypeDTO petTypeDTO = petTypeDTOS.stream().findFirst().get(); + PetType petType = petTypeService.dtoToEntity(petTypeDTO); + pet = new Pet(); + pet.setId(PET_ID); + pet.setName(PET_NAME); + pet.setType(petType); + pet.setBirthDate(LocalDate.parse(PET_BIRTH_DATE)); + petDTO = new PetDTO(); + petDTO.setId(PET_ID); + petDTO.setName(PET_NAME); + petDTO.setType(petTypeDTO); + petDTO.setBirthDate(LocalDate.parse(PET_BIRTH_DATE)); + + OwnerDTO ownerDTO = ownerService.findById(OWNER_ID); + ownerDTO.addPet(petDTO); + + pet.setOwner(ownerService.dtoToEntity(ownerDTO)); + petDTO.setOwner(ownerDTO); + } + + @Test + @Tag("dtoToEntity") + @DisplayName("Verify the convertion from DTO to Entity") + void dtoToEntity() { + Pet found = petService.dtoToEntity(petDTO); + + assertThat(found.getId()).isEqualTo(pet.getId()); + assertThat(found.getName()).isEqualTo(pet.getName()); + assertThat(found.getBirthDate()).isEqualTo(pet.getBirthDate()); + assertThat(found.getType()).isEqualTo(pet.getType()); + assertThat(found.getOwner().getId()).isEqualTo(pet.getOwner().getId()); + assertThat(found.getVisits()).isEqualTo(pet.getVisits()); + } + + @Test + @Tag("entityToDTO") + @DisplayName("Verify the convertion from Entity to DTO") + void entityToDTO() { + PetDTO found = petService.entityToDTO(pet); + + assertThat(found.getId()).isEqualTo(petDTO.getId()); + assertThat(found.getName()).isEqualTo(petDTO.getName()); + assertThat(found.getBirthDate()).isEqualTo(petDTO.getBirthDate()); + assertThat(found.getType()).isEqualTo(petDTO.getType()); + assertThat(found.getOwner().getId()).isEqualTo(petDTO.getOwner().getId()); + assertThat(found.getVisits()).isEqualTo(petDTO.getVisits()); + } + + @Test + @Tag("dtosToEntities") + @DisplayName("Verify the convertion from DTOs list to Entities list") + void dtosToEntities() { + List expected = petRepository.findAll(); + List allDTO = petService.findAll(); + + List found = petService.dtosToEntities(allDTO); + + assertThat(found).hasSameSizeAs(expected).isEqualTo(expected); + } + + @Test + @Tag("entitiesToDTOS") + @DisplayName("Verify the convertion from Entity to DTO") + void entitiesToDTOS() { + List allEntity = petRepository.findAll(); + List expected = petService.findAll(); + + List found = petService.entitiesToDTOS(allEntity); + + assertThat(found).hasSameSizeAs(expected).isEqualTo(expected); + } + + @Test + @Tag("findById") + @DisplayName("Verify that we get PetDTO by his ID") + void findById() { + List allDTO = petService.findAll(); + PetDTO expected = allDTO.get(2); + + assertThat(petService.findById(expected.getId())).isEqualTo(expected); + } + + @Test + @Tag("findAll") + @DisplayName("Verify that the PetDTO list contain all previous elements and the new saved one") + void findAll() { + List expected = petService.findAll(); + + assertThat(expected).doesNotContain(petDTO); + petService.save(petDTO); + + List found = petService.findAll(); + + assertThat(found).hasSize(expected.size() + 1).contains(petDTO).containsAll(expected); + + } + + @Test + @Tag("save") + @DisplayName("Verify that all PetDTO list contain the new saved one") + void save() { + assertThat(petService.findAll()).doesNotContain(petDTO); + + petService.save(petDTO); + + assertThat(petService.findAll()).containsAnyOf(petDTO); + } + +} diff --git a/src/test/java/org/springframework/samples/petclinic/service/VetServiceTest.java b/src/test/java/org/springframework/samples/petclinic/service/VetServiceTest.java new file mode 100644 index 000000000..f1c833820 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/service/VetServiceTest.java @@ -0,0 +1,142 @@ +package org.springframework.samples.petclinic.service; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.samples.petclinic.dto.VetDTO; +import org.springframework.samples.petclinic.model.Vet; +import org.springframework.samples.petclinic.repository.SpecialtyRepository; +import org.springframework.samples.petclinic.repository.VetRepository; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@Slf4j +@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class)) +class VetServiceTest { + + private final static Integer VET_ID = 11; + + private final static String VET_FIRST_NAME = "Sam"; + + private final static String VET_LAST_NAME = "Schultz"; + + @Autowired + private VetRepository vetRepository; + + @Autowired + private SpecialtyRepository specialtyRepository; + + private VetService vetService; + + private static Vet vet; + + private static VetDTO vetDTO; + + @BeforeEach + void beforeEach() { + vetService = new VetService(vetRepository, specialtyRepository); + vet = new Vet(); + vet.setId(VET_ID); + vet.setFirstName(VET_FIRST_NAME); + vet.setLastName(VET_LAST_NAME); + vetDTO = new VetDTO(); + vetDTO.setId(VET_ID); + vetDTO.setFirstName(VET_FIRST_NAME); + vetDTO.setLastName(VET_LAST_NAME); + + } + + @Test + @Tag("dtoToEntity") + @DisplayName("Verify the convertion from DTO to Entity") + void dtoToEntity() { + Vet found = vetService.dtoToEntity(vetDTO); + + assertThat(found.getId()).isEqualTo(vet.getId()); + assertThat(found.getFirstName()).isEqualTo(vet.getFirstName()); + assertThat(found.getLastName()).isEqualTo(vet.getLastName()); + } + + @Test + @Tag("entityToDTO") + @DisplayName("Verify the convertion from Entity to DTO") + void entityToDTO() { + VetDTO found = vetService.entityToDTO(vet); + + assertThat(found.getId()).isEqualTo(vetDTO.getId()); + assertThat(found.getFirstName()).isEqualTo(vetDTO.getFirstName()); + assertThat(found.getLastName()).isEqualTo(vetDTO.getLastName()); + } + + @Test + @DisplayName("Verify the convertion from DTOs list to Entities list") + @Tag("dtosToEntities") + void dtosToEntities() { + List vetDTOS = vetService.findAll(); + List expected = new ArrayList<>(); + vetDTOS.forEach(dto -> expected.add(vetService.dtoToEntity(dto))); + + Collection found = vetService.dtosToEntities(vetDTOS); + + assertThat(found).hasSameSizeAs(expected).isEqualTo(expected); + } + + @Test + @Tag("entitiesToDTOS") + @DisplayName("Verify the convertion from Entities list to DTOs list") + void entitiesToDTOS() { + List expected = vetService.findAll(); + List vets = new ArrayList<>(); + expected.forEach(dto -> vets.add(vetService.dtoToEntity(dto))); + + List found = vetService.entitiesToDTOS(vets); + + assertThat(found).hasSameSizeAs(expected).isEqualTo(expected); + } + + @Test + @Tag("findById") + @DisplayName("Verify that we get VetDTO by his ID") + void findById() { + List allDTO = vetService.findAll(); + VetDTO expected = allDTO.get(2); + + assertThat(vetService.findById(expected.getId())).isEqualTo(expected); + } + + @Test + @Tag("findAll") + @DisplayName("Verify that the VetDTO list contain all previous elements and the new saved one") + void findAll() { + List expected = vetService.findAll(); + + assertThat(expected).doesNotContain(vetDTO); + vetService.save(vetDTO); + + List found = vetService.findAll(); + + assertThat(found).contains(vetDTO).containsAll(expected); + } + + @Test + @Tag("save") + @DisplayName("Verify that all VetDTO list contain the new saved one") + void save() { + assertThat(vetService.findAll()).doesNotContain(vetDTO); + + vetService.save(vetDTO); + + assertThat(vetService.findAll()).contains(vetDTO); + } + +} diff --git a/src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java b/src/test/java/org/springframework/samples/petclinic/validator/ValidatorTests.java similarity index 94% rename from src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java rename to src/test/java/org/springframework/samples/petclinic/validator/ValidatorTests.java index 8d754900d..f22b9d6b4 100644 --- a/src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java +++ b/src/test/java/org/springframework/samples/petclinic/validator/ValidatorTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.validator; import java.util.Locale; import java.util.Set; @@ -24,6 +24,7 @@ import javax.validation.Validator; import org.junit.jupiter.api.Test; import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.samples.petclinic.model.Person; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import static org.assertj.core.api.Assertions.assertThat;