【问题标题】:BeanCreationException after adding two variables添加两个变量后的BeanCreationException
【发布时间】:2013-12-01 00:26:50
【问题描述】:

有人可以告诉我如何通过 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)]

这里是the code for 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>();   

根据 axiopisty 的要求,我不能真正注释掉除了添加猫和狗之外的所有内容,因为宠物、猫和狗是从 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();
    }
}

【问题讨论】:

  • 请使用“将猫和狗填充为宠物子集的方法”更新您的 OP。另外,如果您注释掉您添加的所有代码,减去添加的 @Transient 猫和狗,会发生什么?
  • @axiopisty 我把填充猫和狗的方法放在我上面的原始帖子中。我还添加了 OwnerController.java 中的 processFindForm() 方法来说明为什么我不能注释掉我添加的所有内容减去添加的猫和狗。你还需要什么别的吗?您还有其他想法吗?
  • 请发布您的整个实体类。
  • @SotiriosDelimanolis 我刚刚添加了整个实体类作为对上面原始帖子的编辑。你还需要什么?
  • @SotiriosDelimanolis 我是否向您提供了您需要的信息?我希望从同一个基础表中派生三个单独过滤的列表,但是几天来我一直被如何做到这一点所困扰。

标签: java spring hibernate jpa


【解决方案1】:

为什么单独的列表必须是实例变量?!为什么不简单地创建一个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 对其进行注释,以便在从数据库中检索所有者后调用该方法。

【讨论】:

  • 为什么它需要是一个实例变量?根据豆规格。属性基于 get/set 名称而不是实例变量的存在。所以getCats 会暴露一个名为cats 的属性,即使实例变量会被称为fooBarBaz...
【解决方案2】:

我建议,您可以在您的实体中使用@Access(AccessType.FIELD),它可能会解决问题。

【讨论】:

    猜你喜欢
    • 2022-12-07
    • 2011-04-18
    • 2015-05-03
    • 2019-04-14
    • 1970-01-01
    • 2023-03-20
    • 2021-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多