I'm using XML mapping. I tried to make a many to many association between Invoice and Product (an invoice can contain many products and a product can belong to many invoices). My approach was to make an association called "InvoiceLine" that will contain a single product, its quantity and total and this InvoiceLine would belong to a single Invoice. -An Invoice has many invoiceLines -An InvoiceLine has many Products and has an attribute which is the Invoice Id that corresponds to the invoice While searching for a way to make this mapping, I came to know that you can't make a many to many association with an extra column and that I need to make 2 one-to-many associations to replace that many-to-many association. This is what I tried but I keep getting the error:
19359 [http-nio-8088-exec-3] ERROR org.hibernate.property.BasicPropertyAccessor - IllegalArgumentException in class: model.InvoiceLine, getter method of property: Product
org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of model.InvoiceLine.Product
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:195)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:87)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValues(AbstractComponentTuplizer.java:93)
at org.hibernate.tuple.component.PojoComponentTuplizer.getPropertyValues(PojoComponentTuplizer.java:109)
at org.hibernate.type.serComponentType.getPropertyValues(ComponentType.java:376)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:207)
at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:126)
at org.hibernate.engine.EntityKey.<init>(EntityKey.java:70)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:184)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:562)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:550)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:546)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:342)
at com.sun.proxy.$Proxy5.save(Unknown Source)
at dao.GenericDaoHibernateImpl.add(GenericDaoHibernateImpl.java:49)
at dao.InvoiceLineDaoImpl.ajouter(InvoiceLineDaoImpl.java:12)
at services.InvoiceLineServiceImpl.ajouter(InvoiceLineServiceImpl.java:25)
at controller.InvoiceLineServlet.doPost(InvoiceLineServlet.java:123)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1100)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:687)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:169)
... 50 more
Here are my mapping classes, the association entity and the servlet. InvoiceLine.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="model.InvoiceLine" table="INVOICE_LINE">
<composite-id name="id" class="model.InvoiceLine">
<key-many-to-one name="Product" entity-name="model.Product"
column="CODE_PRODUCT" />
<key-many-to-one name="Invoice" entity-name="model.Invoice"
column="ID_INVOICE"/>
</composite-id>
<property name="qte" column="quantity" />
<property name="total" column="TOTAL" />
</class>
</hibernate-mapping>
Product.hbm.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="model.Product" table="PRODUCT">
<meta attribute="class-description">
</meta>
<id name="codeProduct" column="CODE_PRODUCT">
<generator class="native"/>
</id>
<property name="name" column="NAME" />
<property name="description" column="DESCRIPTION" />
<property name="price" column="PRICE" />
<property name="quantityStock" column="QUANTITY_STOCK" />
<many-to-one name="category" class="model.category" fetch="select" update="true">
<column name="CODE_CATEGORY" not-null="true" />
</many-to-one>
<set name="invoiceline" table="INVOICE_LINE" inverse="true"
fetch="select" cascade="all">
<key>
<column name="CODE_PRODUCT" not-null="true" />
</key>
<one-to-many class="model.InvoiceLine" />
</set>
</class>
</hibernate-mapping>
Invoice.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="model.Invoice" table="INVOICE">
<meta attribute="class-description">
</meta>
<id name="id" column="ID_INVOICE">
<generator class="native"/>
</id>
<property name="date" column="DATE" />
<property name="total" column="TOTAL" />
<many-to-one name="client" class="model.Client" fetch="select" update="true">
<column name="ID_CLIENT" not-null="true" />
</many-to-one>
<set name="InvoiceLine" table="INVOICE_LINE" inverse="true"
fetch="select" cascade="all">
<key>
<column name="ID_INVOICE" not-null="true" />
</key>
<one-to-many class="model.InvoiceLine" />
</set>
</class>
</hibernate-mapping>
And this is the SERVLET
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if ((request.getParameter("addInvoiceLine")) != null) {
RequestDispatcher dispatcher = request.getRequestDispatcher("/View/AddInvoiceLine.jsp");
dispatcher.forward(request, response);
//get the InvoiceId from a select list
String[] invoice = request.getParameterValues("invoice");
int codeInvoice = Integer.parseInt(invoice[0]);
//get the ProductId from a select list
String[] product= request.getParameterValues("product");
int codeProd = Integer.parseInt(product[0]);
//get the quantity from a textField and convert it to integer
String stringQuantity = request.getParameter("quantity");
int quantity= Integer.parseInt(stringQuantity);
InvoiceServiceImpl InvoiceService = new InvoiceServiceImpl();
Invoice invoice= invoiceService.return(codeInvoice);
ProductServiceImpl productService = new ProductServiceImpl();
Product product = productService.return(codeProd);
InvoiceLineServiceImpl invoiceLineServiceImpl = new InvoiceLineServiceImpl();
InvoiceLine invoiceLine= new InvoiceLine(quantity);
invoiceLine.setProduct(product);
invoiceLine.setInvoice(invoice);
invoiceLineServiceImpl.add(invoiceLine);
The line that throws the error is:
invoiceLineServiceImpl.add(invoiceLine);
the method add is inherited from this GenericDao:
package dao;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
@SuppressWarnings("unchecked")
public abstract class GenericDaoHibernateImpl<E, PK extends Serializable> implements GenericDao<E, PK> {
/**
* By defining this class as abstract, we prevent Spring from creating
* instance of this class If not defined as abstract,
* getClass().getGenericSuperClass() would return Object. There would be
* exception because Object class does not hava constructor with parameters.
*/
protected Class<? extends E> daoType;
public static SessionFactory sessionFactory;
@SuppressWarnings("rawtypes")
public GenericDaoHibernateImpl() {
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
daoType = (Class) pt.getActualTypeArguments()[0];
}
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable t) {
t.printStackTrace();
}
}
public static SessionFactory getSession() {
return sessionFactory;
}
protected Session currentSession() {
return getSession().getCurrentSession();
}
@Override
public void add(E entity) {
currentSession().beginTransaction();
currentSession().save(entity);
currentSession().getTransaction().commit();
}
@Override
public void update(E entity) {
currentSession().beginTransaction();
currentSession().update(entity);
currentSession().getTransaction().commit();
}
@Override
public void remove(E entity) {
currentSession().beginTransaction();
// E oldEntity = (E) currentSession().l;
currentSession().delete(entity);
currentSession().getTransaction().commit();
}
@Override
public E find(PK key) {
currentSession().beginTransaction();
return (E) currentSession().get(daoType, key);
}
@Override
public List<E> getAll() {
currentSession().beginTransaction();
return currentSession().createCriteria(daoType).list();
}
}
Please note that the method add works perfectly for other entities like Product, so that got me thinking that the issue is with the xml mapping of InvoiceLineand not the java code
This is my InvoiceLine entity
package model;
import java.io.Serializable;
public class InvoiceLine implements Serializable{
private long id;
private double total;
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public long getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
private Product product;
private Invoice invoice;
private int quantity;
public InvoiceLine() {
super();
}
public InvoiceLine(int quantity) {
super();
this.quantity= quantity;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public Invoice getInvoice() {
return invoice;
}
public void setInvoice(Invoice invoice) {
this.invoice= invoice;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity= quantity;
}
}
Product entity
package model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Product implements Serializable{
private int codeProduct;
private String name;
private String description;
private Double price;
private int quantityStock;
private Category category;
private Set<InvoiceLine> invoiceLine= new HashSet<InvoiceLine>();
public Set<InvoiceLine> getInvoiceLine() {
return invoiceLine;
}
public void setInvoiceLine(Set<InvoiceLine> invoiceLine) {
this.invoiceLine= invoiceLine;
}
public Product() {
}
public Product(String name, String description, Double price, int quantityStock) {
this.name = name;
this.description = description;
this.price = price;
this.quantityStock = quantityStock;
}
// getters and setters
public int getCodeProduct() {
return codeProduct;
}
public void setCodeProduct(int codeProduct) {
this.codeProduct = codeProduct;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price= price;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public int getQuantityStock() {
return quantityStock;
}
public void setQuantityStock(int quantityStock) {
this.quantityStock = quantityStock;
}
}
try using
<many-to-one name="category" class="model.Category" fetch="select" update="true">
in product.hbm.xml andin InvoiceLine.hbm.xml