Aggiunte in configurazioni di avvio:

-Aggiunti profili local e prod modificabili nel campo Environment
-Password db criptata (la secret key si trova nel campo Arguments)

N.B. la secret key è uguale al nome del profilo che si sta utilizzando
This commit is contained in:
Daniele De Marco 2020-04-15 11:18:47 +02:00
parent 381ffe33bf
commit 8c3caf06e8
41 changed files with 2594 additions and 2600 deletions

11
pom.xml
View file

@ -11,7 +11,9 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version> <version>2.2.5.RELEASE</version>
</parent> </parent>
<name>petclinic</name> <name>petclinic</name>
<properties> <properties>
@ -20,7 +22,6 @@
<java.version>1.8</java.version> <java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Web dependencies --> <!-- Web dependencies -->
<webjars-bootstrap.version>3.3.6</webjars-bootstrap.version> <webjars-bootstrap.version>3.3.6</webjars-bootstrap.version>
<webjars-jquery-ui.version>1.11.4</webjars-jquery-ui.version> <webjars-jquery-ui.version>1.11.4</webjars-jquery-ui.version>
@ -65,6 +66,12 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<!-- Jasypt implementation -->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!-- Databases - postgresql implementation --> <!-- Databases - postgresql implementation -->
<dependency> <dependency>
@ -72,6 +79,7 @@
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
</dependency> </dependency>
<!-- caching --> <!-- caching -->
<dependency> <dependency>
<groupId>javax.cache</groupId> <groupId>javax.cache</groupId>
@ -372,5 +380,4 @@
</build> </build>
</profile> </profile>
</profiles> </profiles>
</project> </project>

View file

@ -1,35 +1,38 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic; package org.springframework.samples.petclinic;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
/** import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties;
* PetClinic Spring Boot Application.
* /**
* @author Dave Syer * PetClinic Spring Boot Application.
* *
*/ * @author Dave Syer
@SpringBootApplication(proxyBeanMethods = false) *
public class PetClinicApplication { */
@SpringBootApplication(proxyBeanMethods = false)
public static void main(String[] args) { @EnableEncryptableProperties
SpringApplication.run(PetClinicApplication.class, args); public class PetClinicApplication {
}
public static void main(String[] args) {
} SpringApplication.run(PetClinicApplication.class, args);
}
}

View file

@ -1,51 +1,51 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import java.io.Serializable; import java.io.Serializable;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
/** /**
* Simple JavaBean domain object with an id property. Used as a base class for objects * Simple JavaBean domain object with an id property. Used as a base class for objects
* needing this property. * needing this property.
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
@MappedSuperclass @MappedSuperclass
public class BaseEntity implements Serializable { public class BaseEntity implements Serializable {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id; private Integer id;
public Integer getId() { public Integer getId() {
return id; return id;
} }
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public boolean isNew() { public boolean isNew() {
return this.id == null; return this.id == null;
} }
} }

View file

@ -1,47 +1,47 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
/** /**
* Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. Used as * Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. Used as
* a base class for objects needing these properties. * a base class for objects needing these properties.
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
@MappedSuperclass @MappedSuperclass
public class NamedEntity extends BaseEntity { public class NamedEntity extends BaseEntity {
@Column(name = "name") @Column(name = "name")
private String name; private String name;
public String getName() { public String getName() {
return this.name; return this.name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
@Override @Override
public String toString() { public String toString() {
return this.getName(); return this.getName();
} }
} }

View file

@ -1,54 +1,54 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
/** /**
* Simple JavaBean domain object representing an person. * Simple JavaBean domain object representing an person.
* *
* @author Ken Krebs * @author Ken Krebs
*/ */
@MappedSuperclass @MappedSuperclass
public class Person extends BaseEntity { public class Person extends BaseEntity {
@Column(name = "first_name") @Column(name = "first_name")
@NotEmpty @NotEmpty
private String firstName; private String firstName;
@Column(name = "last_name") @Column(name = "last_name")
@NotEmpty @NotEmpty
private String lastName; private String lastName;
public String getFirstName() { public String getFirstName() {
return this.firstName; return this.firstName;
} }
public void setFirstName(String firstName) { public void setFirstName(String firstName) {
this.firstName = firstName; this.firstName = firstName;
} }
public String getLastName() { public String getLastName() {
return this.lastName; return this.lastName;
} }
public void setLastName(String lastName) { public void setLastName(String lastName) {
this.lastName = lastName; this.lastName = lastName;
} }
} }

View file

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

View file

@ -1,150 +1,150 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.persistence.CascadeType; import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.validation.constraints.Digits; import javax.validation.constraints.Digits;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.samples.petclinic.model.Person; import org.springframework.samples.petclinic.model.Person;
/** /**
* Simple JavaBean domain object representing an owner. * Simple JavaBean domain object representing an owner.
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
@Entity @Entity
@Table(name = "owners") @Table(name = "owners")
public class Owner extends Person { public class Owner extends Person {
@Column(name = "address") @Column(name = "address")
@NotEmpty @NotEmpty
private String address; private String address;
@Column(name = "city") @Column(name = "city")
@NotEmpty @NotEmpty
private String city; private String city;
@Column(name = "telephone") @Column(name = "telephone")
@NotEmpty @NotEmpty
@Digits(fraction = 0, integer = 10) @Digits(fraction = 0, integer = 10)
private String telephone; private String telephone;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner") @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
private Set<Pet> pets; private Set<Pet> pets;
public String getAddress() { public String getAddress() {
return this.address; return this.address;
} }
public void setAddress(String address) { public void setAddress(String address) {
this.address = address; this.address = address;
} }
public String getCity() { public String getCity() {
return this.city; return this.city;
} }
public void setCity(String city) { public void setCity(String city) {
this.city = city; this.city = city;
} }
public String getTelephone() { public String getTelephone() {
return this.telephone; return this.telephone;
} }
public void setTelephone(String telephone) { public void setTelephone(String telephone) {
this.telephone = telephone; this.telephone = telephone;
} }
protected Set<Pet> getPetsInternal() { protected Set<Pet> getPetsInternal() {
if (this.pets == null) { if (this.pets == null) {
this.pets = new HashSet<>(); this.pets = new HashSet<>();
} }
return this.pets; return this.pets;
} }
protected void setPetsInternal(Set<Pet> pets) { protected void setPetsInternal(Set<Pet> pets) {
this.pets = pets; this.pets = pets;
} }
public List<Pet> getPets() { public List<Pet> getPets() {
List<Pet> sortedPets = new ArrayList<>(getPetsInternal()); List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true)); PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedPets); return Collections.unmodifiableList(sortedPets);
} }
public void addPet(Pet pet) { public void addPet(Pet pet) {
if (pet.isNew()) { if (pet.isNew()) {
getPetsInternal().add(pet); getPetsInternal().add(pet);
} }
pet.setOwner(this); pet.setOwner(this);
} }
/** /**
* Return the Pet with the given name, or null if none found for this Owner. * Return the Pet with the given name, or null if none found for this Owner.
* @param name to test * @param name to test
* @return true if pet name is already in use * @return true if pet name is already in use
*/ */
public Pet getPet(String name) { public Pet getPet(String name) {
return getPet(name, false); return getPet(name, false);
} }
/** /**
* Return the Pet with the given name, or null if none found for this Owner. * Return the Pet with the given name, or null if none found for this Owner.
* @param name to test * @param name to test
* @return true if pet name is already in use * @return true if pet name is already in use
*/ */
public Pet getPet(String name, boolean ignoreNew) { public Pet getPet(String name, boolean ignoreNew) {
name = name.toLowerCase(); name = name.toLowerCase();
for (Pet pet : getPetsInternal()) { for (Pet pet : getPetsInternal()) {
if (!ignoreNew || !pet.isNew()) { if (!ignoreNew || !pet.isNew()) {
String compName = pet.getName(); String compName = pet.getName();
compName = compName.toLowerCase(); compName = compName.toLowerCase();
if (compName.equals(name)) { if (compName.equals(name)) {
return pet; return pet;
} }
} }
} }
return null; return null;
} }
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this)
.append("id", this.getId()).append("new", this.isNew()).append("lastName", this.getLastName()) .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("firstName", this.getFirstName()).append("address", this.address).append("city", this.city)
.append("telephone", this.telephone).toString(); .append("telephone", this.telephone).toString();
} }
} }

View file

@ -1,145 +1,145 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import org.springframework.samples.petclinic.visit.VisitRepository; import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ken Krebs * @author Ken Krebs
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Michael Isvy * @author Michael Isvy
*/ */
@Controller @Controller
class OwnerController { class OwnerController {
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm"; private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
private final OwnerRepository owners; private final OwnerRepository owners;
private VisitRepository visits; private VisitRepository visits;
public OwnerController(OwnerRepository clinicService, VisitRepository visits) { public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
this.owners = clinicService; this.owners = clinicService;
this.visits = visits; this.visits = visits;
} }
@InitBinder @InitBinder
public void setAllowedFields(WebDataBinder dataBinder) { public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id"); dataBinder.setDisallowedFields("id");
} }
@GetMapping("/owners/new") @GetMapping("/owners/new")
public String initCreationForm(Map<String, Object> model) { public String initCreationForm(Map<String, Object> model) {
Owner owner = new Owner(); Owner owner = new Owner();
model.put("owner", owner); model.put("owner", owner);
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} }
@PostMapping("/owners/new") @PostMapping("/owners/new")
public String processCreationForm(@Valid Owner owner, BindingResult result) { public String processCreationForm(@Valid Owner owner, BindingResult result) {
if (result.hasErrors()) { if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} }
else { else {
this.owners.save(owner); this.owners.save(owner);
return "redirect:/owners/" + owner.getId(); return "redirect:/owners/" + owner.getId();
} }
} }
@GetMapping("/owners/find") @GetMapping("/owners/find")
public String initFindForm(Map<String, Object> model) { public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner()); model.put("owner", new Owner());
return "owners/findOwners"; return "owners/findOwners";
} }
@GetMapping("/owners") @GetMapping("/owners")
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) { public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
// allow parameterless GET request for /owners to return all records // allow parameterless GET request for /owners to return all records
if (owner.getLastName() == null) { if (owner.getLastName() == null) {
owner.setLastName(""); // empty string signifies broadest possible search owner.setLastName(""); // empty string signifies broadest possible search
} }
// find owners by last name // find owners by last name
Collection<Owner> results = this.owners.findByLastName(owner.getLastName()); Collection<Owner> results = this.owners.findByLastName(owner.getLastName());
if (results.isEmpty()) { if (results.isEmpty()) {
// no owners found // no owners found
result.rejectValue("lastName", "notFound", "not found"); result.rejectValue("lastName", "notFound", "not found");
return "owners/findOwners"; return "owners/findOwners";
} }
else if (results.size() == 1) { else if (results.size() == 1) {
// 1 owner found // 1 owner found
owner = results.iterator().next(); owner = results.iterator().next();
return "redirect:/owners/" + owner.getId(); return "redirect:/owners/" + owner.getId();
} }
else { else {
// multiple owners found // multiple owners found
model.put("selections", results); model.put("selections", results);
return "owners/ownersList"; return "owners/ownersList";
} }
} }
@GetMapping("/owners/{ownerId}/edit") @GetMapping("/owners/{ownerId}/edit")
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
Owner owner = this.owners.findById(ownerId); Owner owner = this.owners.findById(ownerId);
model.addAttribute(owner); model.addAttribute(owner);
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} }
@PostMapping("/owners/{ownerId}/edit") @PostMapping("/owners/{ownerId}/edit")
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result,
@PathVariable("ownerId") int ownerId) { @PathVariable("ownerId") int ownerId) {
if (result.hasErrors()) { if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} }
else { else {
owner.setId(ownerId); owner.setId(ownerId);
this.owners.save(owner); this.owners.save(owner);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
/** /**
* Custom handler for displaying an owner. * Custom handler for displaying an owner.
* @param ownerId the ID of the owner to display * @param ownerId the ID of the owner to display
* @return a ModelMap with the model attributes for the view * @return a ModelMap with the model attributes for the view
*/ */
@GetMapping("/owners/{ownerId}") @GetMapping("/owners/{ownerId}")
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
ModelAndView mav = new ModelAndView("owners/ownerDetails"); ModelAndView mav = new ModelAndView("owners/ownerDetails");
Owner owner = this.owners.findById(ownerId); Owner owner = this.owners.findById(ownerId);
for (Pet pet : owner.getPets()) { for (Pet pet : owner.getPets()) {
pet.setVisitsInternal(visits.findByPetId(pet.getId())); pet.setVisitsInternal(visits.findByPetId(pet.getId()));
} }
mav.addObject(owner); mav.addObject(owner);
return mav; return mav;
} }
} }

View file

@ -1,64 +1,64 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.util.Collection; import java.util.Collection;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
/** /**
* Repository class for <code>Owner</code> domain objects All method names are compliant * Repository class for <code>Owner</code> domain objects All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring * with Spring Data naming conventions so this interface can easily be extended for Spring
* Data. See: * Data. See:
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface OwnerRepository extends Repository<Owner, Integer> { public interface OwnerRepository extends Repository<Owner, Integer> {
/** /**
* Retrieve {@link Owner}s from the data store by last name, returning all owners * Retrieve {@link Owner}s from the data store by last name, returning all owners
* whose last name <i>starts</i> with the given name. * whose last name <i>starts</i> with the given name.
* @param lastName Value to search for * @param lastName Value to search for
* @return a Collection of matching {@link Owner}s (or an empty Collection if none * @return a Collection of matching {@link Owner}s (or an empty Collection if none
* found) * found)
*/ */
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%") @Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
@Transactional(readOnly = true) @Transactional(readOnly = true)
Collection<Owner> findByLastName(@Param("lastName") String lastName); Collection<Owner> findByLastName(@Param("lastName") String lastName);
/** /**
* Retrieve an {@link Owner} from the data store by id. * Retrieve an {@link Owner} from the data store by id.
* @param id the id to search for * @param id the id to search for
* @return the {@link Owner} if found * @return the {@link Owner} if found
*/ */
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id") @Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
@Transactional(readOnly = true) @Transactional(readOnly = true)
Owner findById(@Param("id") Integer id); Owner findById(@Param("id") Integer id);
/** /**
* Save an {@link Owner} to the data store, either inserting or updating it. * Save an {@link Owner} to the data store, either inserting or updating it.
* @param owner the {@link Owner} to save * @param owner the {@link Owner} to save
*/ */
void save(Owner owner); void save(Owner owner);
} }

View file

@ -1,112 +1,112 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Transient; import javax.persistence.Transient;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.samples.petclinic.model.NamedEntity; import org.springframework.samples.petclinic.model.NamedEntity;
import org.springframework.samples.petclinic.visit.Visit; import org.springframework.samples.petclinic.visit.Visit;
/** /**
* Simple business object representing a pet. * Simple business object representing a pet.
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
*/ */
@Entity @Entity
@Table(name = "pets") @Table(name = "pets")
public class Pet extends NamedEntity { public class Pet extends NamedEntity {
@Column(name = "birth_date") @Column(name = "birth_date")
@DateTimeFormat(pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDate; private LocalDate birthDate;
@ManyToOne @ManyToOne
@JoinColumn(name = "type_id") @JoinColumn(name = "type_id")
private PetType type; private PetType type;
@ManyToOne @ManyToOne
@JoinColumn(name = "owner_id") @JoinColumn(name = "owner_id")
private Owner owner; private Owner owner;
@Transient @Transient
private Set<Visit> visits = new LinkedHashSet<>(); private Set<Visit> visits = new LinkedHashSet<>();
public void setBirthDate(LocalDate birthDate) { public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate; this.birthDate = birthDate;
} }
public LocalDate getBirthDate() { public LocalDate getBirthDate() {
return this.birthDate; return this.birthDate;
} }
public PetType getType() { public PetType getType() {
return this.type; return this.type;
} }
public void setType(PetType type) { public void setType(PetType type) {
this.type = type; this.type = type;
} }
public Owner getOwner() { public Owner getOwner() {
return this.owner; return this.owner;
} }
protected void setOwner(Owner owner) { protected void setOwner(Owner owner) {
this.owner = owner; this.owner = owner;
} }
protected Set<Visit> getVisitsInternal() { protected Set<Visit> getVisitsInternal() {
if (this.visits == null) { if (this.visits == null) {
this.visits = new HashSet<>(); this.visits = new HashSet<>();
} }
return this.visits; return this.visits;
} }
protected void setVisitsInternal(Collection<Visit> visits) { protected void setVisitsInternal(Collection<Visit> visits) {
this.visits = new LinkedHashSet<>(visits); this.visits = new LinkedHashSet<>(visits);
} }
public List<Visit> getVisits() { public List<Visit> getVisits() {
List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal()); List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal());
PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false)); PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false));
return Collections.unmodifiableList(sortedVisits); return Collections.unmodifiableList(sortedVisits);
} }
public void addVisit(Visit visit) { public void addVisit(Visit visit) {
getVisitsInternal().add(visit); getVisitsInternal().add(visit);
visit.setPetId(this.getId()); visit.setPetId(this.getId());
} }
} }

View file

@ -1,113 +1,113 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collection; import java.util.Collection;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ken Krebs * @author Ken Krebs
* @author Arjen Poutsma * @author Arjen Poutsma
*/ */
@Controller @Controller
@RequestMapping("/owners/{ownerId}") @RequestMapping("/owners/{ownerId}")
class PetController { class PetController {
private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm"; private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
private final PetRepository pets; private final PetRepository pets;
private final OwnerRepository owners; private final OwnerRepository owners;
public PetController(PetRepository pets, OwnerRepository owners) { public PetController(PetRepository pets, OwnerRepository owners) {
this.pets = pets; this.pets = pets;
this.owners = owners; this.owners = owners;
} }
@ModelAttribute("types") @ModelAttribute("types")
public Collection<PetType> populatePetTypes() { public Collection<PetType> populatePetTypes() {
return this.pets.findPetTypes(); return this.pets.findPetTypes();
} }
@ModelAttribute("owner") @ModelAttribute("owner")
public Owner findOwner(@PathVariable("ownerId") int ownerId) { public Owner findOwner(@PathVariable("ownerId") int ownerId) {
return this.owners.findById(ownerId); return this.owners.findById(ownerId);
} }
@InitBinder("owner") @InitBinder("owner")
public void initOwnerBinder(WebDataBinder dataBinder) { public void initOwnerBinder(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id"); dataBinder.setDisallowedFields("id");
} }
@InitBinder("pet") @InitBinder("pet")
public void initPetBinder(WebDataBinder dataBinder) { public void initPetBinder(WebDataBinder dataBinder) {
dataBinder.setValidator(new PetValidator()); dataBinder.setValidator(new PetValidator());
} }
@GetMapping("/pets/new") @GetMapping("/pets/new")
public String initCreationForm(Owner owner, ModelMap model) { public String initCreationForm(Owner owner, ModelMap model) {
Pet pet = new Pet(); Pet pet = new Pet();
owner.addPet(pet); owner.addPet(pet);
model.put("pet", pet); model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} }
@PostMapping("/pets/new") @PostMapping("/pets/new")
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) { 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) { if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) {
result.rejectValue("name", "duplicate", "already exists"); result.rejectValue("name", "duplicate", "already exists");
} }
owner.addPet(pet); owner.addPet(pet);
if (result.hasErrors()) { if (result.hasErrors()) {
model.put("pet", pet); model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} }
else { else {
this.pets.save(pet); this.pets.save(pet);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
@GetMapping("/pets/{petId}/edit") @GetMapping("/pets/{petId}/edit")
public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) { public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) {
Pet pet = this.pets.findById(petId); Pet pet = this.pets.findById(petId);
model.put("pet", pet); model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} }
@PostMapping("/pets/{petId}/edit") @PostMapping("/pets/{petId}/edit")
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) { public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) {
if (result.hasErrors()) { if (result.hasErrors()) {
pet.setOwner(owner); pet.setOwner(owner);
model.put("pet", pet); model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} }
else { else {
owner.addPet(pet); owner.addPet(pet);
this.pets.save(pet); this.pets.save(pet);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
} }

View file

@ -1,59 +1,59 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.util.List; import java.util.List;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
/** /**
* Repository class for <code>Pet</code> domain objects All method names are compliant * Repository class for <code>Pet</code> domain objects All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring * with Spring Data naming conventions so this interface can easily be extended for Spring
* Data. See: * Data. See:
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface PetRepository extends Repository<Pet, Integer> { public interface PetRepository extends Repository<Pet, Integer> {
/** /**
* Retrieve all {@link PetType}s from the data store. * Retrieve all {@link PetType}s from the data store.
* @return a Collection of {@link PetType}s. * @return a Collection of {@link PetType}s.
*/ */
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name") @Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
@Transactional(readOnly = true) @Transactional(readOnly = true)
List<PetType> findPetTypes(); List<PetType> findPetTypes();
/** /**
* Retrieve a {@link Pet} from the data store by id. * Retrieve a {@link Pet} from the data store by id.
* @param id the id to search for * @param id the id to search for
* @return the {@link Pet} if found * @return the {@link Pet} if found
*/ */
@Transactional(readOnly = true) @Transactional(readOnly = true)
Pet findById(Integer id); Pet findById(Integer id);
/** /**
* Save a {@link Pet} to the data store, either inserting or updating it. * Save a {@link Pet} to the data store, either inserting or updating it.
* @param pet the {@link Pet} to save * @param pet the {@link Pet} to save
*/ */
void save(Pet pet); void save(Pet pet);
} }

View file

@ -1,30 +1,30 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.samples.petclinic.model.NamedEntity; import org.springframework.samples.petclinic.model.NamedEntity;
/** /**
* @author Juergen Hoeller Can be Cat, Dog, Hamster... * @author Juergen Hoeller Can be Cat, Dog, Hamster...
*/ */
@Entity @Entity
@Table(name = "types") @Table(name = "types")
public class PetType extends NamedEntity { public class PetType extends NamedEntity {
} }

View file

@ -1,62 +1,62 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.text.ParseException; import java.text.ParseException;
import java.util.Collection; import java.util.Collection;
import java.util.Locale; import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.Formatter; import org.springframework.format.Formatter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting * Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting
* from Spring 3.0, Formatters have come as an improvement in comparison to legacy * from Spring 3.0, Formatters have come as an improvement in comparison to legacy
* PropertyEditors. See the following links for more details: - The Spring ref doc: * PropertyEditors. See the following links for more details: - The Spring ref doc:
* https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format * https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format
* *
* @author Mark Fisher * @author Mark Fisher
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Michael Isvy * @author Michael Isvy
*/ */
@Component @Component
public class PetTypeFormatter implements Formatter<PetType> { public class PetTypeFormatter implements Formatter<PetType> {
private final PetRepository pets; private final PetRepository pets;
@Autowired @Autowired
public PetTypeFormatter(PetRepository pets) { public PetTypeFormatter(PetRepository pets) {
this.pets = pets; this.pets = pets;
} }
@Override @Override
public String print(PetType petType, Locale locale) { public String print(PetType petType, Locale locale) {
return petType.getName(); return petType.getName();
} }
@Override @Override
public PetType parse(String text, Locale locale) throws ParseException { public PetType parse(String text, Locale locale) throws ParseException {
Collection<PetType> findPetTypes = this.pets.findPetTypes(); Collection<PetType> findPetTypes = this.pets.findPetTypes();
for (PetType type : findPetTypes) { for (PetType type : findPetTypes) {
if (type.getName().equals(text)) { if (type.getName().equals(text)) {
return type; return type;
} }
} }
throw new ParseException("type not found: " + text, 0); throw new ParseException("type not found: " + text, 0);
} }
} }

View file

@ -1,64 +1,64 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
/** /**
* <code>Validator</code> for <code>Pet</code> forms. * <code>Validator</code> for <code>Pet</code> forms.
* <p> * <p>
* We're not using Bean Validation annotations here because it is easier to define such * We're not using Bean Validation annotations here because it is easier to define such
* validation rule in Java. * validation rule in Java.
* </p> * </p>
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
public class PetValidator implements Validator { public class PetValidator implements Validator {
private static final String REQUIRED = "required"; private static final String REQUIRED = "required";
@Override @Override
public void validate(Object obj, Errors errors) { public void validate(Object obj, Errors errors) {
Pet pet = (Pet) obj; Pet pet = (Pet) obj;
String name = pet.getName(); String name = pet.getName();
// name validation // name validation
if (!StringUtils.hasLength(name)) { if (!StringUtils.hasLength(name)) {
errors.rejectValue("name", REQUIRED, REQUIRED); errors.rejectValue("name", REQUIRED, REQUIRED);
} }
// type validation // type validation
if (pet.isNew() && pet.getType() == null) { if (pet.isNew() && pet.getType() == null) {
errors.rejectValue("type", REQUIRED, REQUIRED); errors.rejectValue("type", REQUIRED, REQUIRED);
} }
// birth date validation // birth date validation
if (pet.getBirthDate() == null) { if (pet.getBirthDate() == null) {
errors.rejectValue("birthDate", REQUIRED, REQUIRED); errors.rejectValue("birthDate", REQUIRED, REQUIRED);
} }
} }
/** /**
* This Validator validates *just* Pet instances * This Validator validates *just* Pet instances
*/ */
@Override @Override
public boolean supports(Class<?> clazz) { public boolean supports(Class<?> clazz) {
return Pet.class.isAssignableFrom(clazz); return Pet.class.isAssignableFrom(clazz);
} }
} }

View file

@ -1,92 +1,92 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.util.Map; import java.util.Map;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.samples.petclinic.visit.Visit; import org.springframework.samples.petclinic.visit.Visit;
import org.springframework.samples.petclinic.visit.VisitRepository; import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ken Krebs * @author Ken Krebs
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Michael Isvy * @author Michael Isvy
* @author Dave Syer * @author Dave Syer
*/ */
@Controller @Controller
class VisitController { class VisitController {
private final VisitRepository visits; private final VisitRepository visits;
private final PetRepository pets; private final PetRepository pets;
public VisitController(VisitRepository visits, PetRepository pets) { public VisitController(VisitRepository visits, PetRepository pets) {
this.visits = visits; this.visits = visits;
this.pets = pets; this.pets = pets;
} }
@InitBinder @InitBinder
public void setAllowedFields(WebDataBinder dataBinder) { public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id"); dataBinder.setDisallowedFields("id");
} }
/** /**
* Called before each and every @RequestMapping annotated method. 2 goals: - Make sure * 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 * 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) * Pet object always has an id (Even though id is not part of the form fields)
* @param petId * @param petId
* @return Pet * @return Pet
*/ */
@ModelAttribute("visit") @ModelAttribute("visit")
public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) { public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) {
Pet pet = this.pets.findById(petId); Pet pet = this.pets.findById(petId);
pet.setVisitsInternal(this.visits.findByPetId(petId)); pet.setVisitsInternal(this.visits.findByPetId(petId));
model.put("pet", pet); model.put("pet", pet);
Visit visit = new Visit(); Visit visit = new Visit();
pet.addVisit(visit); pet.addVisit(visit);
return visit; return visit;
} }
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called // Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
@GetMapping("/owners/*/pets/{petId}/visits/new") @GetMapping("/owners/*/pets/{petId}/visits/new")
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) { public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
return "pets/createOrUpdateVisitForm"; return "pets/createOrUpdateVisitForm";
} }
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called // Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
@PostMapping("/owners/{ownerId}/pets/{petId}/visits/new") @PostMapping("/owners/{ownerId}/pets/{petId}/visits/new")
public String processNewVisitForm(@Valid Visit visit, BindingResult result) { public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
if (result.hasErrors()) { if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm"; return "pets/createOrUpdateVisitForm";
} }
else { else {
this.visits.save(visit); this.visits.save(visit);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
} }

View file

@ -1,55 +1,55 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.system; package org.springframework.samples.petclinic.system;
import javax.cache.configuration.MutableConfiguration; import javax.cache.configuration.MutableConfiguration;
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer; import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
* Cache configuration intended for caches providing the JCache API. This configuration * Cache configuration intended for caches providing the JCache API. This configuration
* creates the used cache for the application and enables statistics that become * creates the used cache for the application and enables statistics that become
* accessible via JMX. * accessible via JMX.
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableCaching @EnableCaching
class CacheConfiguration { class CacheConfiguration {
@Bean @Bean
public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() { public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {
return cm -> { return cm -> {
cm.createCache("vets", cacheConfiguration()); cm.createCache("vets", cacheConfiguration());
}; };
} }
/** /**
* Create a simple configuration that enable statistics via the JCache programmatic * Create a simple configuration that enable statistics via the JCache programmatic
* configuration API. * configuration API.
* <p> * <p>
* Within the configuration object that is provided by the JCache API standard, there * Within the configuration object that is provided by the JCache API standard, there
* is only a very limited set of configuration options. The really relevant * is only a very limited set of configuration options. The really relevant
* configuration options (like the size limit) must be set via a configuration * configuration options (like the size limit) must be set via a configuration
* mechanism that is provided by the selected JCache implementation. * mechanism that is provided by the selected JCache implementation.
*/ */
private javax.cache.configuration.Configuration<Object, Object> cacheConfiguration() { private javax.cache.configuration.Configuration<Object, Object> cacheConfiguration() {
return new MutableConfiguration<>().setStatisticsEnabled(true); return new MutableConfiguration<>().setStatisticsEnabled(true);
} }
} }

View file

@ -1,37 +1,37 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.system; package org.springframework.samples.petclinic.system;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
/** /**
* Controller used to showcase what happens when an exception is thrown * Controller used to showcase what happens when an exception is thrown
* *
* @author Michael Isvy * @author Michael Isvy
* <p/> * <p/>
* Also see how a view that resolves to "error" has been added ("error.html"). * Also see how a view that resolves to "error" has been added ("error.html").
*/ */
@Controller @Controller
class CrashController { class CrashController {
@GetMapping("/oups") @GetMapping("/oups")
public String triggerException() { public String triggerException() {
throw new RuntimeException( throw new RuntimeException(
"Expected: controller used to showcase what " + "happens when an exception is thrown"); "Expected: controller used to showcase what " + "happens when an exception is thrown");
} }
} }

View file

@ -1,30 +1,30 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.system; package org.springframework.samples.petclinic.system;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@Controller @Controller
class WelcomeController { class WelcomeController {
@GetMapping("/") @GetMapping("/")
public String welcome() { public String welcome() {
return "welcome"; return "welcome";
} }
} }

View file

@ -1,34 +1,34 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.vet; package org.springframework.samples.petclinic.vet;
import java.io.Serializable; import java.io.Serializable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.samples.petclinic.model.NamedEntity; import org.springframework.samples.petclinic.model.NamedEntity;
/** /**
* Models a {@link Vet Vet's} specialty (for example, dentistry). * Models a {@link Vet Vet's} specialty (for example, dentistry).
* *
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
@Entity @Entity
@Table(name = "specialties") @Table(name = "specialties")
public class Specialty extends NamedEntity implements Serializable { public class Specialty extends NamedEntity implements Serializable {
} }

View file

@ -1,79 +1,79 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.vet; package org.springframework.samples.petclinic.vet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.ManyToMany; import javax.persistence.ManyToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.samples.petclinic.model.Person; import org.springframework.samples.petclinic.model.Person;
/** /**
* Simple JavaBean domain object representing a veterinarian. * Simple JavaBean domain object representing a veterinarian.
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Arjen Poutsma * @author Arjen Poutsma
*/ */
@Entity @Entity
@Table(name = "vets") @Table(name = "vets")
public class Vet extends Person { public class Vet extends Person {
@ManyToMany(fetch = FetchType.EAGER) @ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"),
inverseJoinColumns = @JoinColumn(name = "specialty_id")) inverseJoinColumns = @JoinColumn(name = "specialty_id"))
private Set<Specialty> specialties; private Set<Specialty> specialties;
protected Set<Specialty> getSpecialtiesInternal() { protected Set<Specialty> getSpecialtiesInternal() {
if (this.specialties == null) { if (this.specialties == null) {
this.specialties = new HashSet<>(); this.specialties = new HashSet<>();
} }
return this.specialties; return this.specialties;
} }
protected void setSpecialtiesInternal(Set<Specialty> specialties) { protected void setSpecialtiesInternal(Set<Specialty> specialties) {
this.specialties = specialties; this.specialties = specialties;
} }
@XmlElement @XmlElement
public List<Specialty> getSpecialties() { public List<Specialty> getSpecialties() {
List<Specialty> sortedSpecs = new ArrayList<>(getSpecialtiesInternal()); List<Specialty> sortedSpecs = new ArrayList<>(getSpecialtiesInternal());
PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true)); PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedSpecs); return Collections.unmodifiableList(sortedSpecs);
} }
public int getNrOfSpecialties() { public int getNrOfSpecialties() {
return getSpecialtiesInternal().size(); return getSpecialtiesInternal().size();
} }
public void addSpecialty(Specialty specialty) { public void addSpecialty(Specialty specialty) {
getSpecialtiesInternal().add(specialty); getSpecialtiesInternal().add(specialty);
} }
} }

View file

@ -1,58 +1,58 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.vet; package org.springframework.samples.petclinic.vet;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map; import java.util.Map;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Mark Fisher * @author Mark Fisher
* @author Ken Krebs * @author Ken Krebs
* @author Arjen Poutsma * @author Arjen Poutsma
*/ */
@Controller @Controller
class VetController { class VetController {
private final VetRepository vets; private final VetRepository vets;
public VetController(VetRepository clinicService) { public VetController(VetRepository clinicService) {
this.vets = clinicService; this.vets = clinicService;
} }
@GetMapping("/vets.html") @GetMapping("/vets.html")
public String showVetList(Map<String, Object> model) { public String showVetList(Map<String, Object> model) {
// Here we are returning an object of type 'Vets' rather than a collection of Vet // Here we are returning an object of type 'Vets' rather than a collection of Vet
// objects so it is simpler for Object-Xml mapping // objects so it is simpler for Object-Xml mapping
Vets vets = new Vets(); Vets vets = new Vets();
vets.getVetList().addAll(this.vets.findAll()); vets.getVetList().addAll(this.vets.findAll());
model.put("vets", vets); model.put("vets", vets);
return "vets/vetList"; return "vets/vetList";
} }
@GetMapping({ "/vets" }) @GetMapping({ "/vets" })
public @ResponseBody Vets showResourcesVetList() { public @ResponseBody Vets showResourcesVetList() {
// Here we are returning an object of type 'Vets' rather than a collection of Vet // Here we are returning an object of type 'Vets' rather than a collection of Vet
// objects so it is simpler for JSon/Object mapping // objects so it is simpler for JSon/Object mapping
Vets vets = new Vets(); Vets vets = new Vets();
vets.getVetList().addAll(this.vets.findAll()); vets.getVetList().addAll(this.vets.findAll());
return vets; return vets;
} }
} }

View file

@ -1,46 +1,46 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.vet; package org.springframework.samples.petclinic.vet;
import java.util.Collection; import java.util.Collection;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
/** /**
* Repository class for <code>Vet</code> domain objects All method names are compliant * Repository class for <code>Vet</code> domain objects All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring * with Spring Data naming conventions so this interface can easily be extended for Spring
* Data. See: * Data. See:
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface VetRepository extends Repository<Vet, Integer> { public interface VetRepository extends Repository<Vet, Integer> {
/** /**
* Retrieve all <code>Vet</code>s from the data store. * Retrieve all <code>Vet</code>s from the data store.
* @return a <code>Collection</code> of <code>Vet</code>s * @return a <code>Collection</code> of <code>Vet</code>s
*/ */
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable("vets") @Cacheable("vets")
Collection<Vet> findAll() throws DataAccessException; Collection<Vet> findAll() throws DataAccessException;
} }

View file

@ -1,43 +1,43 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.vet; package org.springframework.samples.petclinic.vet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
/** /**
* Simple domain object representing a list of veterinarians. Mostly here to be used for * Simple domain object representing a list of veterinarians. Mostly here to be used for
* the 'vets' {@link org.springframework.web.servlet.view.xml.MarshallingView}. * the 'vets' {@link org.springframework.web.servlet.view.xml.MarshallingView}.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
*/ */
@XmlRootElement @XmlRootElement
public class Vets { public class Vets {
private List<Vet> vets; private List<Vet> vets;
@XmlElement @XmlElement
public List<Vet> getVetList() { public List<Vet> getVetList() {
if (vets == null) { if (vets == null) {
vets = new ArrayList<>(); vets = new ArrayList<>();
} }
return vets; return vets;
} }
} }

View file

@ -1,80 +1,80 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.visit; package org.springframework.samples.petclinic.visit;
import java.time.LocalDate; import java.time.LocalDate;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.samples.petclinic.model.BaseEntity;
/** /**
* Simple JavaBean domain object representing a visit. * Simple JavaBean domain object representing a visit.
* *
* @author Ken Krebs * @author Ken Krebs
* @author Dave Syer * @author Dave Syer
*/ */
@Entity @Entity
@Table(name = "visits") @Table(name = "visits")
public class Visit extends BaseEntity { public class Visit extends BaseEntity {
@Column(name = "visit_date") @Column(name = "visit_date")
@DateTimeFormat(pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date; private LocalDate date;
@NotEmpty @NotEmpty
@Column(name = "description") @Column(name = "description")
private String description; private String description;
@Column(name = "pet_id") @Column(name = "pet_id")
private Integer petId; private Integer petId;
/** /**
* Creates a new instance of Visit for the current date * Creates a new instance of Visit for the current date
*/ */
public Visit() { public Visit() {
this.date = LocalDate.now(); this.date = LocalDate.now();
} }
public LocalDate getDate() { public LocalDate getDate() {
return this.date; return this.date;
} }
public void setDate(LocalDate date) { public void setDate(LocalDate date) {
this.date = date; this.date = date;
} }
public String getDescription() { public String getDescription() {
return this.description; return this.description;
} }
public void setDescription(String description) { public void setDescription(String description) {
this.description = description; this.description = description;
} }
public Integer getPetId() { public Integer getPetId() {
return this.petId; return this.petId;
} }
public void setPetId(Integer petId) { public void setPetId(Integer petId) {
this.petId = petId; this.petId = petId;
} }
} }

View file

@ -1,46 +1,46 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.visit; package org.springframework.samples.petclinic.visit;
import java.util.List; import java.util.List;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.samples.petclinic.model.BaseEntity;
/** /**
* Repository class for <code>Visit</code> domain objects All method names are compliant * Repository class for <code>Visit</code> domain objects All method names are compliant
* with Spring Data naming conventions so this interface can easily be extended for Spring * with Spring Data naming conventions so this interface can easily be extended for Spring
* Data. See: * Data. See:
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface VisitRepository extends Repository<Visit, Integer> { public interface VisitRepository extends Repository<Visit, Integer> {
/** /**
* Save a <code>Visit</code> to the data store, either inserting or updating it. * Save a <code>Visit</code> to the data store, either inserting or updating it.
* @param visit the <code>Visit</code> to save * @param visit the <code>Visit</code> to save
* @see BaseEntity#isNew * @see BaseEntity#isNew
*/ */
void save(Visit visit) throws DataAccessException; void save(Visit visit) throws DataAccessException;
List<Visit> findByPetId(Integer petId); List<Visit> findByPetId(Integer petId);
} }

View file

@ -1,24 +1,6 @@
# default connection pool
spring.datasource.hikari.connectionTimeout=20000
spring.datasource.hikari.maximumPoolSize=5
# PostgreSQL connection and inizialization
spring.datasource.url=jdbc:postgresql://localhost:5432/petclinic
spring.datasource.username=postgres
spring.datasource.password=pass
spring.datasource.sql-script-encoding= UTF-8
spring.datasource.schema=classpath*:db/postgres/schema.sql
spring.datasource.data=classpath*:db/postgres/data.sql
spring.datasource.initialization-mode=always
# Web # Web
spring.thymeleaf.mode=HTML spring.thymeleaf.mode=HTML
# JPA
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.open-in-view=false
# Internationalization # Internationalization
spring.messages.basename=messages/messages spring.messages.basename=messages/messages

View file

@ -1,36 +1,36 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic; package org.springframework.samples.petclinic;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.samples.petclinic.vet.VetRepository; import org.springframework.samples.petclinic.vet.VetRepository;
@SpringBootTest @SpringBootTest
class PetclinicIntegrationTests { class PetclinicIntegrationTests {
@Autowired @Autowired
private VetRepository vets; private VetRepository vets;
@Test @Test
void testFindAll() throws Exception { void testFindAll() throws Exception {
vets.findAll(); vets.findAll();
vets.findAll(); // served from cache vets.findAll(); // served from cache
} }
} }

View file

@ -56,7 +56,8 @@ class ValidatorTests {
assertThat(violation.getPropertyPath().toString()).isEqualTo("firstName"); assertThat(violation.getPropertyPath().toString()).isEqualTo("firstName");
assertThat(violation.getMessage()).isEqualTo("must not be empty"); assertThat(violation.getMessage()).isEqualTo("must not be empty");
} }
/*My test*/
/* My test */
@Test @Test
void validateWhenFirstNameNotEmpty() { void validateWhenFirstNameNotEmpty() {
@ -70,7 +71,8 @@ class ValidatorTests {
assertThat(constraintViolations).hasSize(0); assertThat(constraintViolations).hasSize(0);
} }
/*My test*/
/* My test */
@Test @Test
void shouldNotValidateWhenLastNameEmpty() { void shouldNotValidateWhenLastNameEmpty() {

View file

@ -1,199 +1,199 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.assertj.core.util.Lists; import org.assertj.core.util.Lists;
import org.hamcrest.BaseMatcher; import org.hamcrest.BaseMatcher;
import org.hamcrest.Description; import org.hamcrest.Description;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.samples.petclinic.visit.Visit; import org.springframework.samples.petclinic.visit.Visit;
import org.springframework.samples.petclinic.visit.VisitRepository; import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.mockito.BDDMockito.given; 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.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 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.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
/** /**
* Test class for {@link OwnerController} * Test class for {@link OwnerController}
* *
* @author Colin But * @author Colin But
*/ */
@WebMvcTest(OwnerController.class) @WebMvcTest(OwnerController.class)
class OwnerControllerTests { class OwnerControllerTests {
private static final int TEST_OWNER_ID = 1; private static final int TEST_OWNER_ID = 1;
@Autowired @Autowired
private MockMvc mockMvc; private MockMvc mockMvc;
@MockBean @MockBean
private OwnerRepository owners; private OwnerRepository owners;
@MockBean @MockBean
private VisitRepository visits; private VisitRepository visits;
private Owner george; private Owner george;
@BeforeEach @BeforeEach
void setup() { void setup() {
george = new Owner(); george = new Owner();
george.setId(TEST_OWNER_ID); george.setId(TEST_OWNER_ID);
george.setFirstName("George"); george.setFirstName("George");
george.setLastName("Franklin"); george.setLastName("Franklin");
george.setAddress("110 W. Liberty St."); george.setAddress("110 W. Liberty St.");
george.setCity("Madison"); george.setCity("Madison");
george.setTelephone("6085551023"); george.setTelephone("6085551023");
Pet max = new Pet(); Pet max = new Pet();
PetType dog = new PetType(); PetType dog = new PetType();
dog.setName("dog"); dog.setName("dog");
max.setId(1); max.setId(1);
max.setType(dog); max.setType(dog);
max.setName("Max"); max.setName("Max");
max.setBirthDate(LocalDate.now()); max.setBirthDate(LocalDate.now());
george.setPetsInternal(Collections.singleton(max)); george.setPetsInternal(Collections.singleton(max));
given(this.owners.findById(TEST_OWNER_ID)).willReturn(george); given(this.owners.findById(TEST_OWNER_ID)).willReturn(george);
Visit visit = new Visit(); Visit visit = new Visit();
visit.setDate(LocalDate.now()); visit.setDate(LocalDate.now());
given(this.visits.findByPetId(max.getId())).willReturn(Collections.singletonList(visit)); given(this.visits.findByPetId(max.getId())).willReturn(Collections.singletonList(visit));
} }
@Test @Test
void testInitCreationForm() throws Exception { void testInitCreationForm() throws Exception {
mockMvc.perform(get("/owners/new")).andExpect(status().isOk()).andExpect(model().attributeExists("owner")) mockMvc.perform(get("/owners/new")).andExpect(status().isOk()).andExpect(model().attributeExists("owner"))
.andExpect(view().name("owners/createOrUpdateOwnerForm")); .andExpect(view().name("owners/createOrUpdateOwnerForm"));
} }
@Test @Test
void testProcessCreationFormSuccess() throws Exception { void testProcessCreationFormSuccess() throws Exception {
mockMvc.perform(post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs") mockMvc.perform(post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs")
.param("address", "123 Caramel Street").param("city", "London").param("telephone", "01316761638")) .param("address", "123 Caramel Street").param("city", "London").param("telephone", "01316761638"))
.andExpect(status().is3xxRedirection()); .andExpect(status().is3xxRedirection());
} }
@Test @Test
void testProcessCreationFormHasErrors() throws Exception { void testProcessCreationFormHasErrors() throws Exception {
mockMvc.perform( mockMvc.perform(
post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs").param("city", "London")) post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs").param("city", "London"))
.andExpect(status().isOk()).andExpect(model().attributeHasErrors("owner")) .andExpect(status().isOk()).andExpect(model().attributeHasErrors("owner"))
.andExpect(model().attributeHasFieldErrors("owner", "address")) .andExpect(model().attributeHasFieldErrors("owner", "address"))
.andExpect(model().attributeHasFieldErrors("owner", "telephone")) .andExpect(model().attributeHasFieldErrors("owner", "telephone"))
.andExpect(view().name("owners/createOrUpdateOwnerForm")); .andExpect(view().name("owners/createOrUpdateOwnerForm"));
} }
@Test @Test
void testInitFindForm() throws Exception { void testInitFindForm() throws Exception {
mockMvc.perform(get("/owners/find")).andExpect(status().isOk()).andExpect(model().attributeExists("owner")) mockMvc.perform(get("/owners/find")).andExpect(status().isOk()).andExpect(model().attributeExists("owner"))
.andExpect(view().name("owners/findOwners")); .andExpect(view().name("owners/findOwners"));
} }
@Test @Test
void testProcessFindFormSuccess() throws Exception { void testProcessFindFormSuccess() throws Exception {
given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner())); given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner()));
mockMvc.perform(get("/owners")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList")); mockMvc.perform(get("/owners")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList"));
} }
@Test @Test
void testProcessFindFormByLastName() throws Exception { void testProcessFindFormByLastName() throws Exception {
given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george)); given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george));
mockMvc.perform(get("/owners").param("lastName", "Franklin")).andExpect(status().is3xxRedirection()) mockMvc.perform(get("/owners").param("lastName", "Franklin")).andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID)); .andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
} }
@Test @Test
void testProcessFindFormNoOwnersFound() throws Exception { void testProcessFindFormNoOwnersFound() throws Exception {
mockMvc.perform(get("/owners").param("lastName", "Unknown Surname")).andExpect(status().isOk()) mockMvc.perform(get("/owners").param("lastName", "Unknown Surname")).andExpect(status().isOk())
.andExpect(model().attributeHasFieldErrors("owner", "lastName")) .andExpect(model().attributeHasFieldErrors("owner", "lastName"))
.andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound"))
.andExpect(view().name("owners/findOwners")); .andExpect(view().name("owners/findOwners"));
} }
@Test @Test
void testInitUpdateOwnerForm() throws Exception { void testInitUpdateOwnerForm() throws Exception {
mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)).andExpect(status().isOk()) mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)).andExpect(status().isOk())
.andExpect(model().attributeExists("owner")) .andExpect(model().attributeExists("owner"))
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
.andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) .andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
.andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St."))))
.andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) .andExpect(model().attribute("owner", hasProperty("city", is("Madison"))))
.andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023"))))
.andExpect(view().name("owners/createOrUpdateOwnerForm")); .andExpect(view().name("owners/createOrUpdateOwnerForm"));
} }
@Test @Test
void testProcessUpdateOwnerFormSuccess() throws Exception { void testProcessUpdateOwnerFormSuccess() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe")
.param("lastName", "Bloggs").param("address", "123 Caramel Street").param("city", "London") .param("lastName", "Bloggs").param("address", "123 Caramel Street").param("city", "London")
.param("telephone", "01616291589")).andExpect(status().is3xxRedirection()) .param("telephone", "01616291589")).andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/{ownerId}")); .andExpect(view().name("redirect:/owners/{ownerId}"));
} }
@Test @Test
void testProcessUpdateOwnerFormHasErrors() throws Exception { void testProcessUpdateOwnerFormHasErrors() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe")
.param("lastName", "Bloggs").param("city", "London")).andExpect(status().isOk()) .param("lastName", "Bloggs").param("city", "London")).andExpect(status().isOk())
.andExpect(model().attributeHasErrors("owner")) .andExpect(model().attributeHasErrors("owner"))
.andExpect(model().attributeHasFieldErrors("owner", "address")) .andExpect(model().attributeHasFieldErrors("owner", "address"))
.andExpect(model().attributeHasFieldErrors("owner", "telephone")) .andExpect(model().attributeHasFieldErrors("owner", "telephone"))
.andExpect(view().name("owners/createOrUpdateOwnerForm")); .andExpect(view().name("owners/createOrUpdateOwnerForm"));
} }
@Test @Test
void testShowOwner() throws Exception { void testShowOwner() throws Exception {
mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)).andExpect(status().isOk()) mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)).andExpect(status().isOk())
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
.andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) .andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
.andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St."))))
.andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) .andExpect(model().attribute("owner", hasProperty("city", is("Madison"))))
.andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023"))))
.andExpect(model().attribute("owner", hasProperty("pets", not(empty())))) .andExpect(model().attribute("owner", hasProperty("pets", not(empty()))))
.andExpect(model().attribute("owner", hasProperty("pets", new BaseMatcher<List<Pet>>() { .andExpect(model().attribute("owner", hasProperty("pets", new BaseMatcher<List<Pet>>() {
@Override @Override
public boolean matches(Object item) { public boolean matches(Object item) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<Pet> pets = (List<Pet>) item; List<Pet> pets = (List<Pet>) item;
Pet pet = pets.get(0); Pet pet = pets.get(0);
if (pet.getVisits().isEmpty()) { if (pet.getVisits().isEmpty()) {
return false; return false;
} }
return true; return true;
} }
@Override @Override
public void describeTo(Description description) { public void describeTo(Description description) {
description.appendText("Max did not have any visits"); description.appendText("Max did not have any visits");
} }
}))).andExpect(view().name("owners/ownerDetails")); }))).andExpect(view().name("owners/ownerDetails"));
} }
} }

View file

@ -1,113 +1,113 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import static org.mockito.BDDMockito.given; 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.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 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.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import org.assertj.core.util.Lists; import org.assertj.core.util.Lists;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.FilterType;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
/** /**
* Test class for the {@link PetController} * Test class for the {@link PetController}
* *
* @author Colin But * @author Colin But
*/ */
@WebMvcTest(value = PetController.class, @WebMvcTest(value = PetController.class,
includeFilters = @ComponentScan.Filter(value = PetTypeFormatter.class, type = FilterType.ASSIGNABLE_TYPE)) includeFilters = @ComponentScan.Filter(value = PetTypeFormatter.class, type = FilterType.ASSIGNABLE_TYPE))
class PetControllerTests { class PetControllerTests {
private static final int TEST_OWNER_ID = 1; private static final int TEST_OWNER_ID = 1;
private static final int TEST_PET_ID = 1; private static final int TEST_PET_ID = 1;
@Autowired @Autowired
private MockMvc mockMvc; private MockMvc mockMvc;
@MockBean @MockBean
private PetRepository pets; private PetRepository pets;
@MockBean @MockBean
private OwnerRepository owners; private OwnerRepository owners;
@BeforeEach @BeforeEach
void setup() { void setup() {
PetType cat = new PetType(); PetType cat = new PetType();
cat.setId(3); cat.setId(3);
cat.setName("hamster"); cat.setName("hamster");
given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat)); given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat));
given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner()); given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner());
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
} }
@Test @Test
void testInitCreationForm() throws Exception { void testInitCreationForm() throws Exception {
mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID)).andExpect(status().isOk()) mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID)).andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdatePetForm")).andExpect(model().attributeExists("pet")); .andExpect(view().name("pets/createOrUpdatePetForm")).andExpect(model().attributeExists("pet"));
} }
@Test @Test
void testProcessCreationFormSuccess() throws Exception { void testProcessCreationFormSuccess() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty") mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty")
.param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection()) .param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/{ownerId}")); .andExpect(view().name("redirect:/owners/{ownerId}"));
} }
@Test @Test
void testProcessCreationFormHasErrors() throws Exception { void testProcessCreationFormHasErrors() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty").param("birthDate", mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty").param("birthDate",
"2015-02-12")).andExpect(model().attributeHasNoErrors("owner")) "2015-02-12")).andExpect(model().attributeHasNoErrors("owner"))
.andExpect(model().attributeHasErrors("pet")).andExpect(model().attributeHasFieldErrors("pet", "type")) .andExpect(model().attributeHasErrors("pet")).andExpect(model().attributeHasFieldErrors("pet", "type"))
.andExpect(model().attributeHasFieldErrorCode("pet", "type", "required")).andExpect(status().isOk()) .andExpect(model().attributeHasFieldErrorCode("pet", "type", "required")).andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdatePetForm")); .andExpect(view().name("pets/createOrUpdatePetForm"));
} }
@Test @Test
void testInitUpdateForm() throws Exception { void testInitUpdateForm() throws Exception {
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)) mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
.andExpect(status().isOk()).andExpect(model().attributeExists("pet")) .andExpect(status().isOk()).andExpect(model().attributeExists("pet"))
.andExpect(view().name("pets/createOrUpdatePetForm")); .andExpect(view().name("pets/createOrUpdatePetForm"));
} }
@Test @Test
void testProcessUpdateFormSuccess() throws Exception { void testProcessUpdateFormSuccess() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty") 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()) .param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/{ownerId}")); .andExpect(view().name("redirect:/owners/{ownerId}"));
} }
@Test @Test
void testProcessUpdateFormHasErrors() throws Exception { void testProcessUpdateFormHasErrors() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty") 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")) .param("birthDate", "2015/02/12")).andExpect(model().attributeHasNoErrors("owner"))
.andExpect(model().attributeHasErrors("pet")).andExpect(status().isOk()) .andExpect(model().attributeHasErrors("pet")).andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdatePetForm")); .andExpect(view().name("pets/createOrUpdatePetForm"));
} }
} }

View file

@ -1,95 +1,95 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.text.ParseException; import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
/** /**
* Test class for {@link PetTypeFormatter} * Test class for {@link PetTypeFormatter}
* *
* @author Colin But * @author Colin But
*/ */
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class PetTypeFormatterTests { class PetTypeFormatterTests {
@Mock @Mock
private PetRepository pets; private PetRepository pets;
private PetTypeFormatter petTypeFormatter; private PetTypeFormatter petTypeFormatter;
@BeforeEach @BeforeEach
void setup() { void setup() {
this.petTypeFormatter = new PetTypeFormatter(pets); this.petTypeFormatter = new PetTypeFormatter(pets);
} }
@Test @Test
void testPrint() { void testPrint() {
PetType petType = new PetType(); PetType petType = new PetType();
petType.setName("Hamster"); petType.setName("Hamster");
String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH); String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH);
assertThat(petTypeName).isEqualTo("Hamster"); assertThat(petTypeName).isEqualTo("Hamster");
} }
@Test @Test
void shouldParse() throws ParseException { void shouldParse() throws ParseException {
given(this.pets.findPetTypes()).willReturn(makePetTypes()); given(this.pets.findPetTypes()).willReturn(makePetTypes());
PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH); PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH);
assertThat(petType.getName()).isEqualTo("Bird"); assertThat(petType.getName()).isEqualTo("Bird");
} }
@Test @Test
void shouldThrowParseException() throws ParseException { void shouldThrowParseException() throws ParseException {
given(this.pets.findPetTypes()).willReturn(makePetTypes()); given(this.pets.findPetTypes()).willReturn(makePetTypes());
Assertions.assertThrows(ParseException.class, () -> { Assertions.assertThrows(ParseException.class, () -> {
petTypeFormatter.parse("Fish", Locale.ENGLISH); petTypeFormatter.parse("Fish", Locale.ENGLISH);
}); });
} }
/** /**
* Helper method to produce some sample pet types just for test purpose * Helper method to produce some sample pet types just for test purpose
* @return {@link Collection} of {@link PetType} * @return {@link Collection} of {@link PetType}
*/ */
private List<PetType> makePetTypes() { private List<PetType> makePetTypes() {
List<PetType> petTypes = new ArrayList<>(); List<PetType> petTypes = new ArrayList<>();
petTypes.add(new PetType() { petTypes.add(new PetType() {
{ {
setName("Dog"); setName("Dog");
} }
}); });
petTypes.add(new PetType() { petTypes.add(new PetType() {
{ {
setName("Bird"); setName("Bird");
} }
}); });
return petTypes; return petTypes;
} }
} }

View file

@ -1,78 +1,78 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import static org.mockito.BDDMockito.given; 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.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 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.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.samples.petclinic.visit.VisitRepository; import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
/** /**
* Test class for {@link VisitController} * Test class for {@link VisitController}
* *
* @author Colin But * @author Colin But
*/ */
@WebMvcTest(VisitController.class) @WebMvcTest(VisitController.class)
class VisitControllerTests { class VisitControllerTests {
private static final int TEST_PET_ID = 1; private static final int TEST_PET_ID = 1;
@Autowired @Autowired
private MockMvc mockMvc; private MockMvc mockMvc;
@MockBean @MockBean
private VisitRepository visits; private VisitRepository visits;
@MockBean @MockBean
private PetRepository pets; private PetRepository pets;
@BeforeEach @BeforeEach
void init() { void init() {
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
} }
@Test @Test
void testInitNewVisitForm() throws Exception { void testInitNewVisitForm() throws Exception {
mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)).andExpect(status().isOk()) mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)).andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdateVisitForm")); .andExpect(view().name("pets/createOrUpdateVisitForm"));
} }
@Test @Test
void testProcessNewVisitFormSuccess() throws Exception { void testProcessNewVisitFormSuccess() throws Exception {
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George") mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George")
.param("description", "Visit Description")).andExpect(status().is3xxRedirection()) .param("description", "Visit Description")).andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/{ownerId}")); .andExpect(view().name("redirect:/owners/{ownerId}"));
} }
@Test @Test
void testProcessNewVisitFormHasErrors() throws Exception { void testProcessNewVisitFormHasErrors() throws Exception {
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George")) mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George"))
.andExpect(model().attributeHasErrors("visit")).andExpect(status().isOk()) .andExpect(model().attributeHasErrors("visit")).andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdateVisitForm")); .andExpect(view().name("pets/createOrUpdateVisitForm"));
} }
} }

View file

@ -1,227 +1,227 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.service; package org.springframework.samples.petclinic.service;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Collection; import java.util.Collection;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.samples.petclinic.owner.Owner; import org.springframework.samples.petclinic.owner.Owner;
import org.springframework.samples.petclinic.owner.OwnerRepository; import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.samples.petclinic.owner.Pet; import org.springframework.samples.petclinic.owner.Pet;
import org.springframework.samples.petclinic.owner.PetRepository; import org.springframework.samples.petclinic.owner.PetRepository;
import org.springframework.samples.petclinic.owner.PetType; import org.springframework.samples.petclinic.owner.PetType;
import org.springframework.samples.petclinic.vet.Vet; import org.springframework.samples.petclinic.vet.Vet;
import org.springframework.samples.petclinic.vet.VetRepository; import org.springframework.samples.petclinic.vet.VetRepository;
import org.springframework.samples.petclinic.visit.Visit; import org.springframework.samples.petclinic.visit.Visit;
import org.springframework.samples.petclinic.visit.VisitRepository; import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
/** /**
* Integration test of the Service and the Repository layer. * Integration test of the Service and the Repository layer.
* <p> * <p>
* ClinicServiceSpringDataJpaTests subclasses benefit from the following services provided * ClinicServiceSpringDataJpaTests subclasses benefit from the following services provided
* by the Spring TestContext Framework: * by the Spring TestContext Framework:
* </p> * </p>
* <ul> * <ul>
* <li><strong>Spring IoC container caching</strong> which spares us unnecessary set up * <li><strong>Spring IoC container caching</strong> which spares us unnecessary set up
* time between test execution.</li> * time between test execution.</li>
* <li><strong>Dependency Injection</strong> of test fixture instances, meaning that we * <li><strong>Dependency Injection</strong> of test fixture instances, meaning that we
* don't need to perform application context lookups. See the use of * don't need to perform application context lookups. See the use of
* {@link Autowired @Autowired} on the <code>{@link * {@link Autowired @Autowired} on the <code>{@link
* ClinicServiceTests#clinicService clinicService}</code> instance variable, which uses * ClinicServiceTests#clinicService clinicService}</code> instance variable, which uses
* autowiring <em>by type</em>. * autowiring <em>by type</em>.
* <li><strong>Transaction management</strong>, meaning each test method is executed in * <li><strong>Transaction management</strong>, meaning each test method is executed in
* its own transaction, which is automatically rolled back by default. Thus, even if tests * its own transaction, which is automatically rolled back by default. Thus, even if tests
* insert or otherwise change database state, there is no need for a teardown or cleanup * insert or otherwise change database state, there is no need for a teardown or cleanup
* script. * script.
* <li>An {@link org.springframework.context.ApplicationContext ApplicationContext} is * <li>An {@link org.springframework.context.ApplicationContext ApplicationContext} is
* also inherited and can be used for explicit bean lookup if necessary.</li> * also inherited and can be used for explicit bean lookup if necessary.</li>
* </ul> * </ul>
* *
* @author Ken Krebs * @author Ken Krebs
* @author Rod Johnson * @author Rod Johnson
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
* @author Dave Syer * @author Dave Syer
*/ */
@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class)) @DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class))
class ClinicServiceTests { class ClinicServiceTests {
@Autowired @Autowired
protected OwnerRepository owners; protected OwnerRepository owners;
@Autowired @Autowired
protected PetRepository pets; protected PetRepository pets;
@Autowired @Autowired
protected VisitRepository visits; protected VisitRepository visits;
@Autowired @Autowired
protected VetRepository vets; protected VetRepository vets;
@Test @Test
void shouldFindOwnersByLastName() { void shouldFindOwnersByLastName() {
Collection<Owner> owners = this.owners.findByLastName("Davis"); Collection<Owner> owners = this.owners.findByLastName("Davis");
assertThat(owners).hasSize(2); assertThat(owners).hasSize(2);
owners = this.owners.findByLastName("Daviss"); owners = this.owners.findByLastName("Daviss");
assertThat(owners).isEmpty(); assertThat(owners).isEmpty();
} }
@Test @Test
void shouldFindSingleOwnerWithPet() { void shouldFindSingleOwnerWithPet() {
Owner owner = this.owners.findById(1); Owner owner = this.owners.findById(1);
assertThat(owner.getLastName()).startsWith("Franklin"); assertThat(owner.getLastName()).startsWith("Franklin");
assertThat(owner.getPets()).hasSize(1); assertThat(owner.getPets()).hasSize(1);
assertThat(owner.getPets().get(0).getType()).isNotNull(); assertThat(owner.getPets().get(0).getType()).isNotNull();
assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat"); assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat");
} }
@Test @Test
@Transactional @Transactional
void shouldInsertOwner() { void shouldInsertOwner() {
Collection<Owner> owners = this.owners.findByLastName("Schultz"); Collection<Owner> owners = this.owners.findByLastName("Schultz");
int found = owners.size(); int found = owners.size();
Owner owner = new Owner(); Owner owner = new Owner();
owner.setFirstName("Sam"); owner.setFirstName("Sam");
owner.setLastName("Schultz"); owner.setLastName("Schultz");
owner.setAddress("4, Evans Street"); owner.setAddress("4, Evans Street");
owner.setCity("Wollongong"); owner.setCity("Wollongong");
owner.setTelephone("4444444444"); owner.setTelephone("4444444444");
this.owners.save(owner); this.owners.save(owner);
assertThat(owner.getId().longValue()).isNotEqualTo(0); assertThat(owner.getId().longValue()).isNotEqualTo(0);
owners = this.owners.findByLastName("Schultz"); owners = this.owners.findByLastName("Schultz");
assertThat(owners.size()).isEqualTo(found + 1); assertThat(owners.size()).isEqualTo(found + 1);
} }
@Test @Test
@Transactional @Transactional
void shouldUpdateOwner() { void shouldUpdateOwner() {
Owner owner = this.owners.findById(1); Owner owner = this.owners.findById(1);
String oldLastName = owner.getLastName(); String oldLastName = owner.getLastName();
String newLastName = oldLastName + "X"; String newLastName = oldLastName + "X";
owner.setLastName(newLastName); owner.setLastName(newLastName);
this.owners.save(owner); this.owners.save(owner);
// retrieving new name from database // retrieving new name from database
owner = this.owners.findById(1); owner = this.owners.findById(1);
assertThat(owner.getLastName()).isEqualTo(newLastName); assertThat(owner.getLastName()).isEqualTo(newLastName);
} }
@Test @Test
void shouldFindPetWithCorrectId() { void shouldFindPetWithCorrectId() {
Pet pet7 = this.pets.findById(7); Pet pet7 = this.pets.findById(7);
assertThat(pet7.getName()).startsWith("Samantha"); assertThat(pet7.getName()).startsWith("Samantha");
assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean"); assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean");
} }
@Test @Test
void shouldFindAllPetTypes() { void shouldFindAllPetTypes() {
Collection<PetType> petTypes = this.pets.findPetTypes(); Collection<PetType> petTypes = this.pets.findPetTypes();
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1); PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
assertThat(petType1.getName()).isEqualTo("cat"); assertThat(petType1.getName()).isEqualTo("cat");
PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4); PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4);
assertThat(petType4.getName()).isEqualTo("snake"); assertThat(petType4.getName()).isEqualTo("snake");
} }
@Test @Test
@Transactional @Transactional
void shouldInsertPetIntoDatabaseAndGenerateId() { void shouldInsertPetIntoDatabaseAndGenerateId() {
Owner owner6 = this.owners.findById(6); Owner owner6 = this.owners.findById(6);
int found = owner6.getPets().size(); int found = owner6.getPets().size();
Pet pet = new Pet(); Pet pet = new Pet();
pet.setName("bowser"); pet.setName("bowser");
Collection<PetType> types = this.pets.findPetTypes(); Collection<PetType> types = this.pets.findPetTypes();
pet.setType(EntityUtils.getById(types, PetType.class, 2)); pet.setType(EntityUtils.getById(types, PetType.class, 2));
pet.setBirthDate(LocalDate.now()); pet.setBirthDate(LocalDate.now());
owner6.addPet(pet); owner6.addPet(pet);
assertThat(owner6.getPets().size()).isEqualTo(found + 1); assertThat(owner6.getPets().size()).isEqualTo(found + 1);
this.pets.save(pet); this.pets.save(pet);
this.owners.save(owner6); this.owners.save(owner6);
owner6 = this.owners.findById(6); owner6 = this.owners.findById(6);
assertThat(owner6.getPets().size()).isEqualTo(found + 1); assertThat(owner6.getPets().size()).isEqualTo(found + 1);
// checks that id has been generated // checks that id has been generated
assertThat(pet.getId()).isNotNull(); assertThat(pet.getId()).isNotNull();
} }
@Test @Test
@Transactional @Transactional
void shouldUpdatePetName() throws Exception { void shouldUpdatePetName() throws Exception {
Pet pet7 = this.pets.findById(7); Pet pet7 = this.pets.findById(7);
String oldName = pet7.getName(); String oldName = pet7.getName();
String newName = oldName + "X"; String newName = oldName + "X";
pet7.setName(newName); pet7.setName(newName);
this.pets.save(pet7); this.pets.save(pet7);
pet7 = this.pets.findById(7); pet7 = this.pets.findById(7);
assertThat(pet7.getName()).isEqualTo(newName); assertThat(pet7.getName()).isEqualTo(newName);
} }
@Test @Test
void shouldFindVets() { void shouldFindVets() {
Collection<Vet> vets = this.vets.findAll(); Collection<Vet> vets = this.vets.findAll();
Vet vet = EntityUtils.getById(vets, Vet.class, 3); Vet vet = EntityUtils.getById(vets, Vet.class, 3);
assertThat(vet.getLastName()).isEqualTo("Douglas"); assertThat(vet.getLastName()).isEqualTo("Douglas");
assertThat(vet.getNrOfSpecialties()).isEqualTo(2); assertThat(vet.getNrOfSpecialties()).isEqualTo(2);
assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry"); assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry");
assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery"); assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery");
} }
@Test @Test
@Transactional @Transactional
void shouldAddNewVisitForPet() { void shouldAddNewVisitForPet() {
Pet pet7 = this.pets.findById(7); Pet pet7 = this.pets.findById(7);
int found = pet7.getVisits().size(); int found = pet7.getVisits().size();
Visit visit = new Visit(); Visit visit = new Visit();
pet7.addVisit(visit); pet7.addVisit(visit);
visit.setDescription("test"); visit.setDescription("test");
this.visits.save(visit); this.visits.save(visit);
this.pets.save(pet7); this.pets.save(pet7);
pet7 = this.pets.findById(7); pet7 = this.pets.findById(7);
assertThat(pet7.getVisits().size()).isEqualTo(found + 1); assertThat(pet7.getVisits().size()).isEqualTo(found + 1);
assertThat(visit.getId()).isNotNull(); assertThat(visit.getId()).isNotNull();
} }
@Test @Test
void shouldFindVisitsByPetId() throws Exception { void shouldFindVisitsByPetId() throws Exception {
Collection<Visit> visits = this.visits.findByPetId(7); Collection<Visit> visits = this.visits.findByPetId(7);
assertThat(visits).hasSize(2); assertThat(visits).hasSize(2);
Visit[] visitArr = visits.toArray(new Visit[visits.size()]); Visit[] visitArr = visits.toArray(new Visit[visits.size()]);
assertThat(visitArr[0].getDate()).isNotNull(); assertThat(visitArr[0].getDate()).isNotNull();
assertThat(visitArr[0].getPetId()).isEqualTo(7); assertThat(visitArr[0].getPetId()).isEqualTo(7);
} }
} }

View file

@ -1,53 +1,53 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.service; package org.springframework.samples.petclinic.service;
import java.util.Collection; import java.util.Collection;
import org.springframework.orm.ObjectRetrievalFailureException; import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.samples.petclinic.model.BaseEntity;
/** /**
* Utility methods for handling entities. Separate from the BaseEntity class mainly * Utility methods for handling entities. Separate from the BaseEntity class mainly
* because of dependency on the ORM-associated ObjectRetrievalFailureException. * because of dependency on the ORM-associated ObjectRetrievalFailureException.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @see org.springframework.samples.petclinic.model.BaseEntity * @see org.springframework.samples.petclinic.model.BaseEntity
* @since 29.10.2003 * @since 29.10.2003
*/ */
public abstract class EntityUtils { public abstract class EntityUtils {
/** /**
* Look up the entity of the given class with the given id in the given collection. * Look up the entity of the given class with the given id in the given collection.
* @param entities the collection to search * @param entities the collection to search
* @param entityClass the entity class to look up * @param entityClass the entity class to look up
* @param entityId the entity id to look up * @param entityId the entity id to look up
* @return the found entity * @return the found entity
* @throws ObjectRetrievalFailureException if the entity was not found * @throws ObjectRetrievalFailureException if the entity was not found
*/ */
public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId) public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId)
throws ObjectRetrievalFailureException { throws ObjectRetrievalFailureException {
for (T entity : entities) { for (T entity : entities) {
if (entity.getId() == entityId && entityClass.isInstance(entity)) { if (entity.getId() == entityId && entityClass.isInstance(entity)) {
return entity; return entity;
} }
} }
throw new ObjectRetrievalFailureException(entityClass, entityId); throw new ObjectRetrievalFailureException(entityClass, entityId);
} }
} }

View file

@ -1,51 +1,51 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.system; package org.springframework.samples.petclinic.system;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 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.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
/** /**
* Test class for {@link CrashController} * Test class for {@link CrashController}
* *
* @author Colin But * @author Colin But
*/ */
// Waiting https://github.com/spring-projects/spring-boot/issues/5574 // Waiting https://github.com/spring-projects/spring-boot/issues/5574
@Disabled @Disabled
@WebMvcTest(controllers = CrashController.class) @WebMvcTest(controllers = CrashController.class)
class CrashControllerTests { class CrashControllerTests {
@Autowired @Autowired
private MockMvc mockMvc; private MockMvc mockMvc;
@Test @Test
void testTriggerException() throws Exception { void testTriggerException() throws Exception {
mockMvc.perform(get("/oups")).andExpect(view().name("exception")) mockMvc.perform(get("/oups")).andExpect(view().name("exception"))
.andExpect(model().attributeExists("exception")).andExpect(forwardedUrl("exception")) .andExpect(model().attributeExists("exception")).andExpect(forwardedUrl("exception"))
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
} }

View file

@ -1,80 +1,80 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.vet; package org.springframework.samples.petclinic.vet;
import static org.mockito.BDDMockito.given; 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.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 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.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import org.assertj.core.util.Lists; import org.assertj.core.util.Lists;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.ResultActions;
/** /**
* Test class for the {@link VetController} * Test class for the {@link VetController}
*/ */
@WebMvcTest(VetController.class) @WebMvcTest(VetController.class)
class VetControllerTests { class VetControllerTests {
@Autowired @Autowired
private MockMvc mockMvc; private MockMvc mockMvc;
@MockBean @MockBean
private VetRepository vets; private VetRepository vets;
@BeforeEach @BeforeEach
void setup() { void setup() {
Vet james = new Vet(); Vet james = new Vet();
james.setFirstName("James"); james.setFirstName("James");
james.setLastName("Carter"); james.setLastName("Carter");
james.setId(1); james.setId(1);
Vet helen = new Vet(); Vet helen = new Vet();
helen.setFirstName("Helen"); helen.setFirstName("Helen");
helen.setLastName("Leary"); helen.setLastName("Leary");
helen.setId(2); helen.setId(2);
Specialty radiology = new Specialty(); Specialty radiology = new Specialty();
radiology.setId(1); radiology.setId(1);
radiology.setName("radiology"); radiology.setName("radiology");
helen.addSpecialty(radiology); helen.addSpecialty(radiology);
given(this.vets.findAll()).willReturn(Lists.newArrayList(james, helen)); given(this.vets.findAll()).willReturn(Lists.newArrayList(james, helen));
} }
@Test @Test
void testShowVetListHtml() throws Exception { void testShowVetListHtml() throws Exception {
mockMvc.perform(get("/vets.html")).andExpect(status().isOk()).andExpect(model().attributeExists("vets")) mockMvc.perform(get("/vets.html")).andExpect(status().isOk()).andExpect(model().attributeExists("vets"))
.andExpect(view().name("vets/vetList")); .andExpect(view().name("vets/vetList"));
} }
@Test @Test
void testShowResourcesVetList() throws Exception { void testShowResourcesVetList() throws Exception {
ResultActions actions = mockMvc.perform(get("/vets").accept(MediaType.APPLICATION_JSON)) ResultActions actions = mockMvc.perform(get("/vets").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()); .andExpect(status().isOk());
actions.andExpect(content().contentType(MediaType.APPLICATION_JSON)) actions.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.vetList[0].id").value(1)); .andExpect(jsonPath("$.vetList[0].id").value(1));
} }
} }

View file

@ -1,40 +1,40 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.vet; package org.springframework.samples.petclinic.vet;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.util.SerializationUtils; import org.springframework.util.SerializationUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* @author Dave Syer * @author Dave Syer
*/ */
class VetTests { class VetTests {
@Test @Test
void testSerialization() { void testSerialization() {
Vet vet = new Vet(); Vet vet = new Vet();
vet.setFirstName("Zaphod"); vet.setFirstName("Zaphod");
vet.setLastName("Beeblebrox"); vet.setLastName("Beeblebrox");
vet.setId(123); vet.setId(123);
Vet other = (Vet) SerializationUtils.deserialize(SerializationUtils.serialize(vet)); Vet other = (Vet) SerializationUtils.deserialize(SerializationUtils.serialize(vet));
assertThat(other.getFirstName()).isEqualTo(vet.getFirstName()); assertThat(other.getFirstName()).isEqualTo(vet.getFirstName());
assertThat(other.getLastName()).isEqualTo(vet.getLastName()); assertThat(other.getLastName()).isEqualTo(vet.getLastName());
assertThat(other.getId()).isEqualTo(vet.getId()); assertThat(other.getId()).isEqualTo(vet.getId());
} }
} }