java.lang.StackOverflowError lors de la persistance d'un objet jpa
Je suis la construction d'une application en utilisant JPA, JSF, EJB, Derby. À ce stade, la demande est encore faible. J'ai un formulaire dans l'application pour ajouter de nouveaux produits. Lors de l'ajout de données dans la bd il se passe bien jusqu'à ce que je redémarrez l'application ou le serveur. Quand j'ai redémarrer le serveur ou de l'application, je reçois java.lang.StackOverflowError
, j'ai encore pouvez interroger la base de données pour les données représentées par le produit db, mais le produit de création n'est pas possible. Je n'ai que 5 entrées dans la base de données, dès maintenant, mais je suis préoccupé par ce qui se passe si tôt.
C'est l'Ejb (Getter, setter et les constructeurs supprimé pour des raisons de simplicité):
@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));
}
c'est le ProductController (Getter, setter et les constructeurs supprimé pour des raisons de simplicité):
@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();
}
Catégorie de l'Entité (Getters, setters, hash() et les constructeurs supprimé pour des raisons de simplicité):
@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;
}
Produit de l'Entité (Getters, setters, hash() et les constructeurs supprimé pour des raisons de simplicité):
@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);
}
C'est la stacktrace:
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)
Merci. Je viens de mettre à jour le post avec la Catégorie de la classe. Merci à l'avance.
semble que vous avez obtenu votre réponse..
Pourriez-vous poster votre equals() de la mise en œuvre du Produit et de la Catégorie des classes? Est-il possible que la méthode equals() dans le Produit est l'appel de la méthode equals() dans la Catégorie, et vice-versa.
J'ai mis à jour le code ci-dessus avec la equals() méthodes permettant à la fois Produit et de la Catégorie. Merci
OriginalL'auteur lv10 | 2012-11-04
Vous devez vous connecter pour publier un commentaire.
Votre
Category
classe dispose d'une liste deProducts
et dans leequals
méthode de laCategory
classe que vous faitesqui appelle le
equals
méthode sur laProduct
classe, leequals
méthode sur laProduct
classe qui nequi appelle le
equals
méthode sur laCategory
une fois de plus et tout le processus se répète, causant un débordement de Pile.Solution:
Espère que cela aide.
!this.product_fk.equals(other.product_fk)
et!this.category_fk.equals(other.category_fk)
lastackOverflowError goes away
. Cependant, je suis préoccupé par l'implication logique non-exécution de cette condition. Recommanderiez-vous le correctif que j'ai utilisé? pourriez-vous me faire connaître votre raisonnement sur cette question? merci à l'avance.J'ai une question. En essayant de terminer une opération de mise à jour d'un produit, j'obtiens le même
StackOverflow
erreur. Cependant, cette fois, c'est en se référant à lahash
, quelque chose comme ceci: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)
je voulais vous demander si le problème est le même problème que nous discutions avant. Merci à l'avance.de son mieux pour nous montrer un peu de code, de sorte que nous pouvons vous aider.
Sajan, j'ai mis à jour la pile. Merci encore.
Il est. Vous ne devez pas utiliser vos relations dans equals et hashcode calculs. Vous ne devriez pas utiliser quoi que ce soit qui pourrait changer dans un hashcode.
OriginalL'auteur Sajan Chandran
Je suis soupçonner dépendance circulaire comme la cause racine du problème. Je pense que vous avez mappé
Product
soit dansCategory
ouSaleDetails
ou deux objets. Si oui, il va appeler problème de référence circulaire lors de la sérialisation de l'Product
objet, alors que l'entraînera dansStackOverFlow
erreur.Je pense que vous avez deux options:
bi-dreictional
cartographie si elle peut être évitée.readObject()
etwriteObject()
méthodes dans votreProduct
,Category
etSaleDetails
classes et d'éviter de lecture/écriture d'objets dans les cercles.EDIT:
Espère que cette aide.
Il n'y a pas de problème. Mettre en œuvre vous personnalisé readObject/writeObject. Si vous avez besoin de plus de détails à ce sujet, s'il vous plaît laissez-moi savoir.
Ajout d'un exemple de code pour
Product
classe. Ajouter des méthodes similaires dansCustomer
etSaleDetails
classes. S'il vous plaît ne pas lire/écrireProduct
attribut deCustomer
etSaleDetails
classes.Juste pour s'assurer que nous travaillons sur le droit de la cause du problème, pouvez vous s'il vous plaît faites de votre relation unidirectionnelle(temporairement commentaire d'une direction de la cartographie) et puis essayer? Si cela fonctionne, nous savons de son la dépendance circulaire pour vous et puis je vais travailler avec vous pour résoudre le problème. Je suis juste essayer d'éviter de mettre de l'effort dans le sens de pas de valeur à la fin.
Si cela s'avère, j'ai été correct dans l'identification de la cause du problème.
If you really don't need bi-directional mapping, its best
(supprimer une direction de la cartographie), sinon nous allons reprendre que la sérialisation tâche. S'il vous plaît partagez votre readObject/writeObject code que vous avez mis en œuvre.OriginalL'auteur Yogendra Singh
@Sajan mentionné. Vous avez une dépendance cyclique dans votre equals().
Vous avez besoin de changer la méthode equals() dans votre Catégorie de la classe de ne pas se référer à "Produit" liste et "categoryId' . Il devrait probablement être comme suit -
Dans la méthode equals() dans la catégorie de Produits que vous pouvez avoir à supprimer "ProductId" et "Prix".
La equals() et hashcode() les méthodes sont importantes, car elles déterminent l'objet d'égalité lorsque vous utilisez des objets dans détaché de l'état et les ajouter à java.util.Ensemble.
La mise en œuvre recommandée est d'utiliser les propriétés qui forment un naturel identificateur de clé dans votre equals() et hashcode() implémentations.
Catégorie -
Disons que vous avez CategoryA avec ProductA et Produitb. Il n'est pas possible que le même ProductA et Produitb sera lié à une autre catégorie appelée CategoryB. Donc, ils ne devraient pas être partie de la equals() de la mise en œuvre.
Produit
Si "Catégorie" dans le Produit.equals() dépend de la "Catégorie" est une partie naturelle de l'identificateur de clé de Produit. Et le fait que vous êtes à l'aide d'une Liste à l'intérieur de la Catégorie signifie que vous n'êtes pas trop inquiet au sujet de l'objet de l'égalité. Si vous êtes concernés par l'égalité(), je vous recommande de le changer pour un Ensemble.
Si vous aviez le scénario suivant -
Si 'Électronique de catégorie a Ensemble de deux produits comme indiqué ci-dessus.
Si vous avez eu l'exemple de code suivant -
Lorsque vous changez le prix de l'appareil photo et l'ajouter dans le Jeu, vous voulez vous assurer que l'ensemble encore ne contient que deux éléments et ne pas ajouter un nouvel élément, car vous êtes en train de modifier un produit existant, pas d'ajout d'un nouveau Produit.
Pour le scénario ci-dessus, vous devez avoir de "Catégorie" et " nom "dans la méthode equals() de "Produit".
OriginalL'auteur Sashi
Il semble que le problème est dans la Catégorie de la classe - l'est égal à fait quelque chose qui à son tour appelle d'égal à égal, la création d'une boucle sans fin
OriginalL'auteur thedayofcondor
De la
List.equals
etVector.equals
appels, je pense qu'il y a une listeX
contenant un vecteurY
contenant la listeX
quelque part dans votre entité. L'exécution d'une égale appel sur cette liste permettra de parcourir cette liste, qui va parcourir le vecteur, qui vont parcourir la liste... et ainsi de suite.OriginalL'auteur Jorn