有人可以告诉我如何摆脱BeanCreationException吗?
在向Owner.java中添加两个变量之后,我得到了BeanCreationException,如下所示:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER) private Set<Pet> pets; //I added the following two variable declarations @Transient private Set<Pet> cats = new HashSet<Pet>(); @Transient private Set<Pet> dogs = new HashSet<Pet>();
我还添加了用于猫和狗的getter和setter方法,以及将猫和狗作为宠物子集填充的方法,如下所示:
public void parsePets() { for (Pet pet : getPetsInternal()) { if (pet.getType().getName().equals("cat")) {cats.add(pet);} else if (pet.getType().getName().equals("dog")) {dogs.add(pet);} } } protected Set<Pet> getPetsInternal() { if (this.pets == null) {this.pets = new HashSet<Pet>();} return this.pets; }
当我在Eclipse中在服务器上运行方式为…运行时,应用程序无法初始化,并显示以下错误消息:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0' defined in class path resource [spring/business-config.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [spring/business-config.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: petclinic] Unable to build EntityManagerFactory ... Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: owners, for columns: [org.hibernate.mapping.Column(cats)]
这是business-config.xml的代码。
我可以消除错误消息,并通过注释掉所做的更改来使应用程序运行,但是当我需要猫和狗各不相同时,我剩下的问题是三个列表(宠物,猫,狗)是相同的宠物的子集。下面的代码消除了错误消息,但创建了三个不相同的相同列表:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER) private Set<Pet> pets; //I added next two variables // @Transient @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER) private Set<Pet> cats;// = new HashSet<Pet>(); // @Transient @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER) private Set<Pet> dogs;// = new HashSet<Pet>();
根据公理会的要求,除了添加猫和狗之外,我无法真正注释所有内容,因为宠物,猫和狗是从OwnerController.java中调用的,如下所示:
@RequestMapping(value = "/owners", method = RequestMethod.GET) public String processFindForm(@RequestParam("ownerID") String ownerId, Owner owner, BindingResult result, Map<String, Object> model) { Collection<Owner> results = this.clinicService.findOwnerByLastName(""); model.put("selections", results); int ownrId = Integer.parseInt(ownerId); Owner sel_owner = this.clinicService.findOwnerById(ownrId);//jim added this sel_owner.parsePets(); model.put("sel_owner",sel_owner); return "owners/ownersList"; }
根据Sotirios的请求,这是我的实体类Owner.java:
@Entity @Table(name = "owners") public class Owner extends Person { @Column(name = "address") @NotEmpty private String address; @Column(name = "city") @NotEmpty private String city; @Column(name = "telephone") @NotEmpty @Digits(fraction = 0, integer = 10) private String telephone; @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER) private Set<Pet> pets; //I added next two variables @Transient @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER) private Set<Pet> cats = new HashSet<Pet>(); @Transient @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER) private Set<Pet> dogs = new HashSet<Pet>(); //end of 2 variables I added public String getAddress() {return this.address;} public void setAddress(String address) {this.address = address;} public String getCity() {return this.city;} public void setCity(String city) {this.city = city;} public String getTelephone() {return this.telephone;} public void setTelephone(String telephone) {this.telephone = telephone;} protected void setPetsInternal(Set<Pet> pets) {this.pets = pets;} // Call this from OwnerController before returning data to page. public void parsePets() { for (Pet pet : getPetsInternal()) { if (pet.getType().getName().equals("cat")) { cats.add(pet); System.out.println(pet.getType().getName()); System.out.println("cats.size() is: "+cats.size()); System.out.println("added a cat to cats"); } else if (pet.getType().getName().equals("dog")) { dogs.add(pet); System.out.println(pet.getType().getName()); System.out.println("dogs.size() is: "+dogs.size()); System.out.println("added a dog to dogs"); } // add as many as you want System.out.println("----------------------------------------------"); } } public Set<Pet> getCats() { System.out.println("about to return cats"); for (Pet cat : cats) {System.out.println("counting a "+cat.getType()+" in cats.");} System.out.println("cats.size() is: "+cats.size()); return cats; } public Set<Pet> getDogs() { System.out.println("about to return dogs"); for (Pet dog : dogs) {System.out.println("counting a "+dog.getType()+" in dogs.");} System.out.println("dogs.size() is: "+dogs.size()); return dogs; } //end section I added protected Set<Pet> getPetsInternal() { if (this.pets == null) {this.pets = new HashSet<Pet>();} return this.pets; } public List<Pet> getPets() { List<Pet> sortedPets = new ArrayList<Pet>(getPetsInternal()); PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true)); return Collections.unmodifiableList(sortedPets); } public void addPet(Pet pet) { getPetsInternal().add(pet); pet.setOwner(this); } public Pet getPet(String name) {return getPet(name, false);} public Pet getPet(String name, boolean ignoreNew) { name = name.toLowerCase(); for (Pet pet : getPetsInternal()) { if (!ignoreNew || !pet.isNew()) { String compName = pet.getName(); compName = compName.toLowerCase(); if (compName.equals(name)) { return pet; } } } return null; } @Override public String toString() { return new ToStringCreator(this) .append("id", this.getId()) .append("new", this.isNew()) .append("lastName", this.getLastName()) .append("firstName", this.getFirstName()) .append("address", this.address) .append("city", this.city) .append("telephone", this.telephone) .toString(); } }
为什么单独的列表必须是实例变量?!为什么不简单地创建一个getCats方法(和其他方法)并简单地过滤pets集合呢?试图映射所有内容,恕我直言,事情变得过于复杂。
getCats
pets
@Entity @Table(name = "owners") public class Owner extends Person { @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER) private Set<Pet> pets; public Set<Pet> getCats() { Set<Pet> cats = new HashSet<Pet>(); for (Pet pet : getPetsInternal()) { if (pet.getType().getName().equals("cat")) { cats.add(pet); } } return cats; } }
缺点是每次需要时都会重新创建集合。您可以使用Google Guava之类的工具来简化此操作,并创建一个过滤器列表。
@Entity @Table(name = "owners") public class Owner extends Person { @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch=FetchType.EAGER) private Set<Pet> pets; public Set<Pet> getCats() { return Sets.filter(getPetsInternal(), new Predicate<Pet>() { public boolean apply(Pet pet) { return pet.getType().getName().equals("cat") } }); } }
您还可以在parsePets方法内部进行操作并使用它进行注释,@PostLoad以便在所有者从数据库中检索到该方法之后将调用该方法。
parsePets
@PostLoad