0
votes

I need to manage 2 databases in my application. For it, i have developed a sample application using EclipseLink Composite Persistence Unit feature.

However during my tests i notice a strange behaviour:
- basics jpa operations (persist, merge, remove or JPQL code) work perfectly
- but when i use the criteria api, EclipseLink return me the following error:

java.lang.IllegalArgumentException: No [EntityType] was found for the key class [com.example.common.entity.ThirdParty] in the Metamodel - please verify that the [Entity] class was referenced in persistence.xml using a specific <class>com.example.common.entity.ThirdParty</class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.entityEmbeddableManagedTypeNotFound(MetamodelImpl.java:177)
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.entity(MetamodelImpl.java:198)
at org.eclipse.persistence.internal.jpa.querydef.CommonAbstractCriteriaImpl.internalFrom(CommonAbstractCriteriaImpl.java:113)
at org.eclipse.persistence.internal.jpa.querydef.AbstractQueryImpl.from(AbstractQueryImpl.java:246)
at com.example.data.dao.ClientTest.testSelectByCriteria(ClientTest.java:125)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

This is the code of my sample (basically 2 entities and one Junit test)

My composite persistence.xml:

<persistence-unit name="testPersistenceUnit" transaction-type="RESOURCE_LOCAL">

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">


<persistence-unit name="testPersistenceUnit" transaction-type="RESOURCE_LOCAL">

    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

    <jar-file>file://D:\projects\prj-archetypes\trunk\workspace\sample\sample-common\target\sample-common-0.0.1-SNAPSHOT.jar</jar-file>
    <properties>
        <property name="eclipselink.composite-unit" value="true" />
    </properties>
</persistence-unit>

My member persistence.xml, located on sample-common-0.0.1-SNAPSHOT.jar:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">

<persistence-unit name="memberPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>com.commons.entity.AbstractEntity</class>    
    <class>com.example.common.entity.ThirdParty</class>
    <class>com.example.common.entity.Address</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>

    <properties>
        <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
        <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/H2default" />
        <property name="javax.persistence.jdbc.user" value="sa" />
        <property name="javax.persistence.jdbc.password" value="" />

        <!-- <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.H2Platform"
            />
        -->
        <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
        <property name="eclipselink.ddl-generation.output-mode" value="database" />
        <property name="eclipselink.logging.level" value="FINEST" />
    </properties>

</persistence-unit>

My entities, also on sample-common-0.0.1-SNAPSHOT.jar:

ThirdParty:

package com.example.common.entity;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Generated;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;

import com.example.common.Gender;
import com.commons.entity.AbstractEntity;

/**
 * ThirdParty entity.
 */
@Entity
public class ThirdParty
    extends AbstractEntity
{

    /**
     * Constructor.
     */
    public ThirdParty()
    {
        super();
    }

    /**
     * Serial version UID.
     */
    private static final long serialVersionUID = 1L;

    /**
     * firstname.
     */
    @Column(name = "FIRST_NAME", nullable = false)
    @NotNull
    private String firstName;

    /**
     * last name.
     */
    @Column(name = "LAST_NAME", nullable = false)
    @NotNull
    @Size(max = 30)
    private String lastName;

    /**
     * Birth date.
     */
    @Column(name = "BIRTH_DATE", nullable = false)
    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    private Date birthdate;

    /**
     * last name.
     */
    @Column(name = "AGE", nullable = false, precision = 0)
    @NotNull
    private Integer age;

    /**
     * ThirdParty civility.
     */
    @Column(name = "CIVILITY", nullable = false)
    @NotNull
    @Enumerated(EnumType.STRING)
    private Gender civility;

     /**
     * addressList.
     */
    @OneToMany(mappedBy = "thirdParty", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
    private List<Address> addressList = new ArrayList<Address>();

    /**
     * Get firstName.
     * @return String
     */
    public String getFirstName()
    {
        return firstName;
    }

    /**
     * Set firstName.
     * @param firstName String
     */
    public void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }

    /**
     * Get lastName.
     * @return String
     */
    public String getLastName()
    {
        return lastName;
    }

    /**
     * Set lastName.
     * @param lastName String
     */
    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

    /**
     * Get birthdate.
     * @return Date
     */
    public Date getBirthdate()
    {
        Date tempDate = birthdate;
        if (tempDate != null)
        {
            tempDate = (Date) birthdate.clone();
        }
        return tempDate;
    }

    /**
     * Set birthdate.
     * @param birthdate Date
     */
    public void setBirthdate(Date birthdate)
    {

        if (birthdate == null)
        {
            this.birthdate = null;
        }
        else
        {
            this.birthdate = (Date) birthdate.clone();
        }
    }

    /**
     * Get age.
     * @return Integer
     */
    public Integer getAge()
    {
        return age;
    }

    /**
     * Set age.
     * @param age Integer
     */
    public void setAge(Integer age)
    {
        this.age = age;
    }

    /**
     * Get civility.
     * @return Gender
     */
    public Gender getCivility()
    {
        return civility;
    }

    /**
     * Set civility.
     * @param civility Gender
     */
    public void setCivility(Gender civility)
    {
        this.civility = civility;
    }

    /**
     * Get addressList.
     * @return Address
     */
    public List<Address> getAddressList()
    {
        return addressList;
    }

    /**
     * Set addressList.
     * @param addressList Address
     */
    public void setAddressList(List<Address> addressList)
    {
        this.addressList = addressList;
    }

    /**
     * Add addressList.
     * @param addressList Address
     */
    public void addAddressList(Address addressList)
    {
        this.addressList.add(addressList);
    }
}

Address entity:

package com.example.common.entity;

import javax.annotation.Generated;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import com.commons.entity.AbstractEntity;

/**
 * Address entity.
 */
@Entity
public class Address
    extends AbstractEntity
{

    /**
     * Serial version UID.
     */
    private static final long serialVersionUID = 1L;

    /**
     * street.
     */
    @Column(name = "STREET")
    private String street;

    /**
     * City.
     */
    @Column(name = "CITY")
    private String city;

    /**
     * Zipcode.
     */
    @Column(name = "ZIPCODE", precision = 0)
    private Integer zipcode;

    /**
     * Third Party.
     */
    @ManyToOne
    private ThirdParty thirdParty;

    /**
     * Get street.
     * @return String
     */
    public String getStreet()
    {
        return street;
    }

    /**
     * Set street.
     * @param street String
     */
    public void setStreet(String street)
    {
        this.street = street;
    }

    /**
     * Get city.
     * @return String
     */
    public String getCity()
    {
        return city;
    }

    /**
     * Set city.
     * @param city String
     */
    public void setCity(String city)
    {
        this.city = city;
    }

    /**
     * Get zipcode.
     * @return Integer
     */
    public Integer getZipcode()
    {
        return zipcode;
    }

    /**
     * Set zipcode.
     * @param zipcode Integer
     */
    public void setZipcode(Integer zipcode)
    {
        this.zipcode = zipcode;
    }

    /**
     * Get thirdParty.
     * @return ThirdParty
     */
    public ThirdParty getThirdParty()
    {
        return thirdParty;
    }

    /**
     * Set thirdParty.
     * @param ThirdParty
     */
    public void setThirdParty(ThirdParty thirdParty)
    {
        this.thirdParty = thirdParty;
    }
}

And finally the JUnit test class:

package com.example.data.dao;

import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.sopra.banking.example.common.Gender;
import com.sopra.banking.example.common.entity.Address;
import com.sopra.banking.example.common.entity.ThirdParty;

import junit.framework.Assert;

public class ClientTest
{

    private static EntityManagerFactory emf;

    private static EntityManager em;

    private static EntityTransaction tx;

    @BeforeClass
    public static void initEntityManager()
        throws Exception
    {
        emf = Persistence.createEntityManagerFactory("testPersistenceUnit");
        em = emf.createEntityManager();

    }

    @AfterClass
    public static void closeEntityManager()
        throws SQLException
    {
        em.close();
        emf.close();
    }

    @Before
    public void initTransaction()
    {
        tx = em.getTransaction();

    }

    @Test
    public void testInsert()
        throws ParseException
    {

        // Create an instance of ThirdParty
        ThirdParty thirdParty = new ThirdParty();

        // Create an instance of Address
        Address address = new Address();

        // set address
        address.setCity("Annecy");
        address.setStreet("street");
        address.setZipcode(74000);
        ArrayList<Address> addresses = new ArrayList<Address>();
        addresses.add(address);

        // set client
        thirdParty.setCivility(Gender.MISTER);
        thirdParty.setAge(17);
        thirdParty.setBirthdate(new SimpleDateFormat("yyyy-MM-dd").parse("2011-01-01"));
        thirdParty.setFirstName("firstName");
        thirdParty.setLastName("lastName");

        thirdParty.setAddressList(addresses);
        address.setThirdParty(thirdParty);

        // Persists the client in DB
        tx.begin();
        em.persist(thirdParty);

        tx.commit();

        Assert.assertNotNull("ID should not be null", thirdParty.getId());
    }

    @Test
    public void testSelectById()
        throws ParseException
    {

        ThirdParty thirdParty = em.find(ThirdParty.class, 1);
        Assert.assertEquals(true, true);

    }

    @Test
    public void testSelectAll()
        throws ParseException
    {

        Query query = em.createQuery("SELECT t FROM ThirdParty t");
        List<ThirdParty> thirdParties = query.getResultList();
        Assert.assertEquals(true, true);

    }

    @Test
    public void testSelectByCriteria()
    {
        CriteriaBuilder qb = em.getCriteriaBuilder();
        CriteriaQuery<ThirdParty> criteriaQuery = qb.createQuery(ThirdParty.class);
        Root<ThirdParty> thRoot = criteriaQuery.from(ThirdParty.class);
        criteriaQuery.select(thRoot);
        List<ThirdParty> thirdPartyList = em.createQuery(criteriaQuery).getResultList();
        Assert.assertEquals(true, true);
    }

}

testInsert, testSelectAll and testSelectById work well but testSelectByCriteria crashes with the error trace on the beginning of my post.

During debug i notice that typeMap is empty on class:
org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl on method entityEmbeddableManagedTypeNotFound

private void entityEmbeddableManagedTypeNotFound(Map typeMap, Object aType, Class clazz, String metamodelType, String metamodelTypeName) {
        // 338837: verify that the collection is not empty - this would mean entities did not make it into the search path
        if(typeMap.isEmpty()) {
            AbstractSessionLog.getLog().log(SessionLog.WARNING, SessionLog.METAMODEL, "metamodel_type_collection_empty_during_lookup", clazz, metamodelTypeName);           
        }
        // A null type will mean either the metamodel type does not exist because it was not found/processed, or the clazz is not part of the model
        if(null == clazz) {
                throw new IllegalArgumentException(ExceptionLocalization.buildMessage(
                        "metamodel_class_null_type_instance_for_null_key",  
                        new Object[] { metamodelTypeName, metamodelType}));
        } else {
            if(null == aType) {
                throw new IllegalArgumentException(ExceptionLocalization.buildMessage(
                        "metamodel_class_null_type_instance",  
                        new Object[] { clazz.getCanonicalName(), metamodelTypeName, metamodelType}));
            } else {

Has anyone ever encountered this problem, it seems managed entites are not visible because the map

Map<String, EntityTypeImpl<?>> entities

is empty.

I try to generate metamodel classes following this procedure jpa-metamodels-with-maven but call using Criteria still failing.

1

1 Answers

0
votes

You bind an entity manager to testPersistenceUnit Persistence.createEntityManagerFactory("testPersistenceUnit"), but you also need an dedicated (individual!) entity manger for memberPU.

At the moment, you eventually try to fetch a ThirdParty via the testPersistenceUnit which is not possible, because you exclude-unlisted-classes'ed it.

Introduce a second entity manager, grab your third party entity using the second entity manager. Do not try to fetch a third party using the first manager.