Click here to Skip to main content
15,890,946 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
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.

What I have tried:

This is what I tried but I keep getting the error:
Java
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
<?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
<?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
<?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**
Java
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:

Java
invoiceLineServiceImpl.add(invoiceLine);

**the method add is inherited from this GenericDao:**
Java
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**

Java
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**
Java
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;
    	}
    
    }
Posted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900