0

I have two entities: Sale and SaleProduct.

I am trying to persist the Sale entity, but I don't know how to make a service to it, because always that I try to save a Sale ir requires a SaleProduct.

This is the Sale entity:

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Sale {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    @NotNull(message = "Sale product!")
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "SALE_ID")
    private List<SaleProduct> products;

    @NotNull(message = "Sale needs some value!")
    private int saleValue;

    private Date creationDate = new Date();

}

And here is the SaleProduct entity:

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class SaleProduct {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    private int quantity;

    @NotNull(message = "Insert the product, please")
    @ManyToOne(fetch = FetchType.EAGER)
    private Product product;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Sale sale;

}

I am trying to persist the Sale with this method:

    public void insertSale(Sale sale) throws Exception {
        Product product = manager.find(Product.class, 2L);
        SaleProduct saleProduct = new SaleProduct();
        saleProduct.setProduct(product);
        sale.setProducts(Arrays.asList(saleProduct));
        saleProduct.setSale(sale);
        manager.persist(sale);
    }

I am sending this JSON:

{
    "saleValue" : "200"
}

When I try to select the sale I created I get these errors:

Caused by: com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.tax.entity.Sale.products, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.tax.entity.Sale["products"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:210)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:177)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:190)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:674)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:156)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContentsUsing(CollectionSerializer.java:160)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:102)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:94)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:24)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:251)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:846)
at org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider.writeTo(ResteasyJackson2Provider.java:207)
at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.writeTo(AbstractWriterInterceptorContext.java:131)
at org.jboss.resteasy.core.interception.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:60)
at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:120)
at org.jboss.resteasy.security.doseta.DigitalSigningInterceptor.aroundWriteTo(DigitalSigningInterceptor.java:145)
at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:124)
at org.jboss.resteasy.plugins.interceptors.encoding.GZIPEncodingInterceptor.aroundWriteTo(GZIPEncodingInterceptor.java:100)
at org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:124)
at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:98)
at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:466)
... 33 more

Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.tax.entity.Sale.products, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:567)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:205)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:146)
at org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:261)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:88)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:24)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:575)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:666)
... 50 more

One more problem: when I saleProduct.setSale(sale); I get this exception: com.sun.jdi.InvocationException occurred invoking method

  • 1
    Can you show us the error message? – Paul Wasilewski Jun 23 '16 at 04:01
  • @Paul of course. Sorry for forget it. Tomorrow I will paste the error here and improve the question. – Gabriel Cunha Jun 23 '16 at 04:12
  • @PaulWasilewski I added the erros I'm getting. – Gabriel Cunha Jun 23 '16 at 17:16
  • You mean, why do you get "No validator could be found for constraint 'javax.validation.constraints.Size' validating type 'com.tax.entity.Product'. Check configuration for 'product'" ? You haven't got a "bean-validation API" validator for that annotation. Nothing to do with JPA. You cannot put `@Size` on a single-valued relation field! – Neil Stockton Jun 23 '16 at 17:19
  • @NeilStockton but it's just one of the Exceptions. Solve this problem is not so hard. – Gabriel Cunha Jun 23 '16 at 17:21
  • A transaction fails for an exception. An exception has a nested exception etc etc. If you had simply put the FULL STACK TRACE with all nested exceptions then people could understand what problem you have! The BeanValidation exception is the only concrete exception I see, which could cause the others ... i.e root cause – Neil Stockton Jun 23 '16 at 17:22
  • Oh, thanks @NeilStockton The full stack trace is too long. Is it a problem to put it here? – Gabriel Cunha Jun 23 '16 at 17:26
  • add it in the question (formatted), the important bit is the root cause ... the stuff at the end – Neil Stockton Jun 23 '16 at 17:34
  • @NeilStockton this is the exception that appears in the end of the console, the root cause, as you said. – Gabriel Cunha Jun 23 '16 at 18:07
  • so fix it as my answer says and see what happens – Neil Stockton Jun 23 '16 at 18:10
  • @NeilStockton you were right! I changed my `@Size` annotation to `@NotNull` and it worked. Now I'm getting another exception, but it's persisting. – Gabriel Cunha Jun 23 '16 at 18:15
  • well if that exception was not the purpose of your question then don't post it and put the real question! – Neil Stockton Jun 23 '16 at 18:25

3 Answers3

0

In order to accomplish bidirectional mapping , you got to have "mappedBy" property in OneToMany annotation

In the entity Sale use

@OneToMany(mappedBy="product", cascade=cascadeType.ALL, fetch=fetchType.LAZY)
MWiesner
  • 7,913
  • 11
  • 31
  • 66
Ridhi
  • 105
  • 7
0
  1. The @JoinColumn annotation must be on the onwing side the relationship, that is, it should be on the @ManyToOne annotation:

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "SALE_ID")
    private Sale sale;
    
  2. The mappedBy attribute must be placed on the inverse side, that is where @OneToMany annotation is used:

    @OneToMany(mappedBy="sale" cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<SaleProduct> products;
    
  3. Create an instance of Sale, say sale.

  4. Create an instance of SaleProduct, say saleProduct.

  5. Add saleProduct into the list products. (I don't know why you named the list products even though it is containing SaleProducts).

  6. Assign sale to saleProduct: saleProduct.setSale(sale). Now both entity instances are wired together.

  7. And at last persist: entityManager.persist(sale);

ujulu
  • 3,154
  • 2
  • 9
  • 14
  • Not successfull. I updated the question. Can you review it? – Gabriel Cunha Jun 23 '16 at 17:11
  • I saw your comment too late. Anyway, it seems your problem ist solved; the mapping should also be OK now, if I understood your comment above correctly. – ujulu Jun 24 '16 at 08:51
  • Yeah @ujulu I'm just getting some errors to fetch the data, but that is another history. Many thanks. – Gabriel Cunha Jun 24 '16 at 11:25
  • Glad it helped you. What error do you get while fetching? – ujulu Jun 24 '16 at 11:28
  • I will add the the exception and the new implementation later, I'm little busy now. – Gabriel Cunha Jun 24 '16 at 11:30
  • can you take a look here? – Gabriel Cunha Jun 24 '16 at 17:12
  • It seems your Hibernate session is closed. Your `products` relationship is lazily loaded by default. If you serialize the sales object before accessing this property before closing the transaction then you will get this exception. So try to access this property by, for example, calling `sale.getProducts().size()` before closing the transaction. Otherwise, if you are using Hibernate look at [the solution to this question](http://stackoverflow.com/questions/21574236/org-hibernate-lazyinitializationexception-could-not-initialize-proxy-no-sess). – ujulu Jun 24 '16 at 17:56
  • I'm using JTA, so I'm not handling the transaction. – Gabriel Cunha Jun 24 '16 at 17:58
0

As the exception says

No validator could be found for constraint 'javax.validation.constraints.Size' validating type 'com.tax.entity.Product'. Check configuration for 'product'

So remove @Size from the field "product" since it is not a collection field. You could put it on the other side of the relation "Sale.products"

Neil Stockton
  • 10,531
  • 3
  • 28
  • 27
  • What you said is correct. I won't vote for accept this answer because it's not the purpose of my question. But thank you very much, it will help me a lot! – Gabriel Cunha Jun 23 '16 at 18:23