7

JPA、JSF、EJB、Derbyを使用してアプリケーションを構築しています。この時点では、アプリケーションはまだ小さいです。アプリケーションに新製品を追加するためのフォームがあります。データベースにデータを追加するときは、アプリケーションまたはサーバーを再起動するまでスムーズに進みます。取得したサーバーまたはアプリのいずれかを再起動してもjava.lang.StackOverflowError、製品dbで表されるデータをデータベースに照会できますが、製品を作成することはできません。現在、データベースには5つのエントリしかありませんが、これが非常に早い段階で発生することを懸念しています。

これはEjbです(簡単にするためにGetter、setter、コンストラクターは削除されています)。

@Stateless
public class ProductEJB{

    @PersistenceContext(unitName = "luavipuPU")
    private EntityManager em;

    public List<Product> findAllProducts()
    {
        TypedQuery<Product> query = em.createNamedQuery("findAllProducts", Product.class);
        return query.getResultList();
    }

    public Product findProductById(int productId)
    {
        return em.find(Product.class, productId);
    }

    public Product createProduct(Product product)
    {
        product.setDateAdded(productCreationDate());
        em.persist(product);
        return product;        
    }    

    public void updateProduct(Product product)
    {
        em.merge(product);
    }

    public void deleteProduct(Product product)
    {
        product = em.find(Product.class, product.getProduct_id());
        em.remove(em.merge(product));
    }

これはProductControllerです(簡単にするためにGetter、setter、コンストラクターは削除されています):

    @Named
@RequestScoped
public class ProductController {

    @EJB
    private ProductEJB productEjb;
    @EJB
    private CategoryEJB categoryEjb;

    private Product product = new Product();
    private List<Product> productList = new ArrayList<Product>();

    private Category category;
    private List<Category> categoryList = new ArrayList<Category>();

    public String doCreateProduct()
    {
        product = productEjb.createProduct(product);
        productList = productEjb.findAllProducts();
        return "listProduct?faces-redirect=true";
    }

    public String doDeleteProduct()
    {
        productEjb.deleteProduct(product);
        return "deleteProduct?faces-redirect=true";
    }

    public String cancelDeleteAction()
    {
        return "listProduct?faces-redirect=true";
    }


    @PostConstruct
    public void init()
    {
        categoryList = categoryEjb.findAllCategory();
        productList = productEjb.findAllProducts();        
    }

カテゴリエンティティ(簡単にするために、Getters、setters、hash()、およびコンストラクターは削除されました):

@Entity
@NamedQueries({
    @NamedQuery(name= "findAllCategory", query="SELECT c FROM Category c")        
})
public class Category implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id @GeneratedValue(strategy= GenerationType.AUTO)
    private int category_id;
    private String name;
    private String description;
    @OneToMany(mappedBy = "category_fk")
        private List<Product> product_fk;

 // readObject() and writeObject() 

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException
    {
        // default deserializer
        ois.defaultReadObject();

        // read the attributes
        category_id = ois.readInt();
        name = (String)ois.readObject();
        description = (String)ois.readObject();

    }

    private void writeObject(ObjectOutputStream oos) throws IOException, ClassNotFoundException
    {
        // default serializer
        oos.defaultWriteObject();

        // write the attributes
        oos.writeInt(category_id);
        oos.writeObject(name);
        oos.writeObject(description);


       }

 @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Category other = (Category) obj;
        if (this.category_id != other.category_id) {
            return false;
        }
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }
        if ((this.description == null) ? (other.description != null) : !this.description.equals(other.description)) {
            return false;
        }
        if (this.product_fk != other.product_fk && (this.product_fk == null || !this.product_fk.equals(other.product_fk))) {
            return false;
        }
        return true;
    }

製品エンティティ(簡単にするために、Getters、setters、hash()、およびコンストラクターは削除されました):

@Entity
@NamedQueries({
    @NamedQuery(name="findAllProducts", query = "SELECT p from Product p")

})
public class Product implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id @GeneratedValue(strategy= GenerationType.AUTO)
    private int product_id;
    private String name;
    private String description;
    protected byte[] imageFile;
    private Float price;
    @Temporal(TemporalType.TIMESTAMP)
    private Date dateAdded;        
    @ManyToOne
    private Category category_fk;
    @ManyToOne
    private SaleDetails saleDetails_fk;

    // readObject() and writeObject() methods

    private void readObject (ObjectInputStream ois)throws IOException, ClassNotFoundException
    {
        // default deserialization
        ois.defaultReadObject();

        // read the attributes
        product_id = ois.readInt();
        name = (String)ois.readObject();
        description = (String)ois.readObject();

        for(int i=0; i<imageFile.length; i++ )
        {
            imageFile[i]=ois.readByte();
        }

        price = ois.readFloat();
        dateAdded = (Date)ois.readObject();
        category_fk = (Category)ois.readObject();
        saleDetails_fk = (SaleDetails)ois.readObject();

    }

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final Product other = (Product) obj;
    if (this.product_id != other.product_id) {
        return false;
    }
    if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
        return false;
    }
    if ((this.description == null) ? (other.description != null) : !this.description.equals(other.description)) {
        return false;
    }
    if (!Arrays.equals(this.imageFile, other.imageFile)) {
        return false;
    }
    if (this.price != other.price && (this.price == null || !this.price.equals(other.price))) {
        return false;
    }
    if (this.dateAdded != other.dateAdded && (this.dateAdded == null || !this.dateAdded.equals(other.dateAdded))) {
        return false;
    }
    if (this.category_fk != other.category_fk && (this.category_fk == null || !this.category_fk.equals(other.category_fk))) {
        return false;
    }
    if (this.saleDetails_fk != other.saleDetails_fk && (this.saleDetails_fk == null || !this.saleDetails_fk.equals(other.saleDetails_fk))) {
        return false;
    }
    return true;
}

    private void writeObject(ObjectOutputStream oos) throws IOException, ClassNotFoundException
    {
        // default serialization
        oos.defaultWriteObject();

        // write object attributes
        oos.writeInt(product_id);
        oos.writeObject(name);
        oos.writeObject(description);
        oos.write(imageFile);
        oos.writeFloat(price);
        oos.writeObject(dateAdded);
        oos.writeObject(category_fk);
        oos.writeObject(saleDetails_fk);

    }

これはスタックトレースです:

    javax.faces.el.EvaluationException: java.lang.StackOverflowError
    at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
    at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
    at javax.faces.component.UICommand.broadcast(UICommand.java:315)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
    at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.StackOverflowError
    at java.util.Vector$Itr.<init>(Vector.java:1120)
    at java.util.Vector.iterator(Vector.java:1114)
    at java.util.AbstractList.hashCode(AbstractList.java:540)
    at java.util.Vector.hashCode(Vector.java:988)
    at org.eclipse.persistence.indirection.IndirectList.hashCode(IndirectList.java:460)
    at com.lv.Entity.Category.hashCode(Category.java:96)
    at com.lv.Entity.Product.hashCode(Product.java:148)
    at java.util.AbstractList.hashCode(AbstractList.java:541)
4

6 に答える 6

14

あなたのクラスには、あなたが行っているクラスのCategoryリストProductsequalsメソッドがありますCategory

if (this.product_fk != other.product_fk && (this.product_fk == null || !this.product_fk.equals(other.product_fk))) {
    return false;
}

equalsクラスのメソッドを呼び出す、ProductクラスのequalsメソッドをProduct呼び出す

if (this.category_fk != other.category_fk && (this.category_fk == null || !this.category_fk.equals(other.category_fk))) {
    return false;
}

これはもう一度equalsメソッドを呼び出し、プロセス全体が繰り返されてスタックオーバーフローが発生します。Category

解決:

  1. 双方向の依存関係を削除します。
  2. equalsメソッドを修正します。

それが役に立てば幸い。

于 2012-11-05T23:25:52.680 に答える
1

問題の根本的な原因として循環依存が疑われます。ProductオブジェクトのいずれCategoryかまたは両方にマッピングされていると思いますSaleDetailsProductその場合、オブジェクトのシリアル化中に循環参照の問題が呼び出されますが、StackOverFlowエラーが発生します。

2つの選択肢があると思います。

  1. bi-dreictional回避できる場合は、マッピングを削除してください。
  2. 、およびクラスにメソッドを実装readObject()し、円でオブジェクトを読み書きすることは避けてください。writeObject()ProductCategorySaleDetails

編集:

 private void writeObject(ObjectOutputStream oos) throws IOException {
    // default serialization 
    oos.defaultWriteObject();
    // write the object attributes
    oos.writeInt(product_id);
    oos.writeObject(name);
    oos.writeObject(description);
    oos.write(imageFile);
    oos.writeFloat(price);
    oos.writeObject(dateAdded);
    oos.writeObject(category_fk);
    oos.writeObject(saleDetails_fk);
  }

   private void readObject(ObjectInputStream ois) 
                                    throws ClassNotFoundException, IOException {
      // default deserialization
      ois.defaultReadObject();
      //read the attributes
      product_id = ois.readInt();
      name = (String)ois.readObject();
      description = (String)ois.readObject();
      imageFile = ois.read();
      price = ois.readFloat();
      dateAdded = (Date)ois.readObject();
      category_fk = (Category)ois.readObject();
      saleDetails_fk = (SaleDetails)ois.readObject();
    } 

お役に立てれば。

于 2012-11-04T23:46:25.927 に答える
1

@Sajanが言ったように。equals()には循環依存関係があります。'Product'リストと'categoryId'を参照しないように、Categoryクラスのequals()メソッドを変更する必要があります。おそらく次のようになります-

    public class Category implements Serializable
{
   ...
 @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }

        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }
        if ((this.description == null) ? (other.description != null) : !this.description.equals(other.description)) {
            return false;
        }
        return true;
    }
}

Productクラスのequals()メソッドでは、「ProductId」と「Price」を削除する必要がある場合があります。

equals()メソッドとhashcode()メソッドは、デタッチ状態のオブジェクトを使用してjava.util.Setに追加するときに、オブジェクトの同等性を決定するため、重要です。推奨される実装は、equals()およびhashcode()実装で「自然キー識別子を形成するプロパティ」を使用することです。

カテゴリ-ProductAとProductBでCategoryAがあったとしましょう。同じProductAとProductBがCategoryBと呼ばれる別のカテゴリに関連付けられることはありません。したがって、equals()実装の一部であってはなりません。

Product-Product.equals()に「Category」を含めるかどうかは、「Category」がProductの自然キー識別子の一部であるかどうかによって異なります。また、カテゴリ内のリストを使用しているという事実は、オブジェクトの同等性についてあまり心配していないことを意味します。equality()が気になる場合は、Setに変更することをお勧めします。

次のシナリオがあった場合-

カテゴリー -

エレクトロニクス

製品1-

名前-カメラ| 価格-100ドル| カテゴリ-エレクトロニクス

製品2-

名前-ハンディカム| 価格-$200| カテゴリ-エレクトロニクス

「電子機器」カテゴリに上記の2つの製品のセットがある場合。次のサンプルコードがある場合-

        session.startTransaction();
    Category electronics = session.get(Category.class, 1234);
    Set<Product> products = electronics.getProducts();
    session.commit();

    Product camera = product.get(0);
    camera.setPrice("300");
    products.add(camera);

カメラの価格を変更してセットに追加するときは、新しい製品を追加するのではなく、既存の製品を変更するため、セットに2つの要素のみが含まれていることを確認し、3番目の新しい要素を追加しないようにします。

上記のシナリオでは、「Product」のequals()メソッドに「Category」と「name」が必要です。

于 2012-11-06T14:51:50.143 に答える
0

問題はCategoryクラスにあるようです-equalsはequalsを呼び出す何かを実行し、無限のループを作成します

于 2012-11-04T23:45:45.910 に答える
0

List.equalsVector.equals呼び出しから、エンティティのどこかにリストXを含むベクトルYを含むリストがあると思います。Xそのリストでequals呼び出しを実行すると、そのリストが繰り返され、ベクトルが繰り返され、リストが繰り返されます...など。

于 2012-11-04T23:50:28.900 に答える
0

コードには循環構造があります。equals、hashCode、toStringを含むクラス生成メソッドは、この循環動作を処理できません。これらのメソッドには、そのようなシナリオを処理する方法がありません。

これらの状況を引き起こす可能性のあるメソッドからフィールドを除外してください。

于 2021-06-01T07:58:29.517 に答える