Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » [SOLVED] Problem in custom classloader-environment: Object XYZ is not a known entity type
icon5.gif  [SOLVED] Problem in custom classloader-environment: Object XYZ is not a known entity type [message #515211] Thu, 18 February 2010 03:29 Go to next message
Alex C. is currently offline Alex C.
Messages: 4
Registered: February 2010
Location: Germany
Junior Member

Hi there,

I have question that has a little bit complex background:

I'm writing a serverframework that is expandable with plugins. Those plugins should be able to use JPA (eclipselink 2.0.0) to persist and load entities.

The serverframework makes use of URLClassLoader to load the plugins. Theres one URLClassLoader for each plugin. All those classloaders are registered at a higher level delegating classloader. Means: Everytime a plugin is looking for a class, the request goes to the delegating classlaoder which asks it's parent and also all registered "child URLClassLoader". That's until now working fine.

As I want to have a central database configuration, I created a singleton that can be used by the plugins to get an EntityManager. Each plugin provides META-INF/persistence.xml which looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" 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_1_0.xsd">
  <persistence-unit name="TestPU">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>my.domain.entities.MyEntity</class>
    <properties>
      <property name="eclipselink.ddl-generation.output-mode" value="database"/>    
      <property name="eclipselink.ddl-generation" value="create-tables"/>
    </properties>
  </persistence-unit>
</persistence>


As you can see, the DB specific properties are missing. As far as I read on the net, it's possible to provide a map that contains this information. So my get method for creating the EntityManager looks like this:

public static EntityManager getEntityManager(String unitName) {
        logger.trace("begin");
        Map propertyMap = DataSourceReader.getInstance().getPersistenceUnitProperties(unitName);

        propertyMap.put(PersistenceUnitProperties.CLASSLOADER, Deployer.getInstance().getDelegatingClassLoader());

        EntityManagerFactory myFactory = Persistence.createEntityManagerFactory(unitName, propertyMap);
        EntityManager myEntityManager = myFactory.createEntityManager(propertyMap);

        logger.trace("displaying meta model ...");
        Set<EntityType<?>> entities = myFactory.getMetamodel().getEntities();
        Iterator<EntityType<?>> iterator = entities.iterator();
        while (iterator.hasNext()) {
            logger.info("Meta Model entities: {}", iterator.next().getName());
        }
        logger.trace("displaying meta model ... *done*");

        logger.trace("end. result={}", myEntityManager);
        return myEntityManager;
    }


The propertyMap contains the missing DB specifiy properties. I also added the property for the classloader that references the delegating classloader that is able to lookup via all registerd URLCLassLoader of each plugin. As I can see from the logoutput, the thing with providing the map works, because EclipseLink is able to connect to the database successfully.

That works so far quite well. The plugins can be loaded, I can have access to all plugins-classes from everywhere etc etc etc. But if my plugin tries to persist an Entity, I get the following error:

Quote:

java.lang.IllegalArgumentException: Object: my.domain.entities.MyEntity[0|HalloWeltText] is not a known entity type.
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.reg isterNewObjectForPersist(UnitOfWorkImpl.java:4147)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persi st(EntityManagerImpl.java:368)



The entity class looks like this:

@Entity
public class MyEntity implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.TABLE)
    int id;

    private String text;

    /**
     * @return the text
     */
    public String getText() {
        return text;
    }

    /**
     * @param text the text to set
     */
    public void setText(String text) {
        this.text = text;
    }

    @Override
    public String toString() {
        return getClass().getCanonicalName()+"["+id+"|"+text+"]";
    }

}


And the code that is trying to persist the Entity:

MyEntity myEntity = new MyEntity();
myEntity.setText("HalloWeltText");
entityManager.getTransaction().begin();
entityManager.persist(myEntity);
entityManager.flush();
entityManager.getTransaction().commit();


It seems to me, that I have a problem with classloader or so. In a non-serverframework-plugin environment, I get all the entities via the MetaModel. But within the framework, I get none.

I tried to debug the problem. While creating the EntityManagerFactory, I saw in some member variable somehow named "managedClasses" that "MyEntity" is known. But in next step, creating the EntityManager, it seems that this information gets lost or that the EntityManager get's the information again, but in a different way that does not recognize the entity classes.

I hope someone can help me with this issue.
I can provide more code and details if required.

best regards,
Alex

[Updated on: Thu, 18 February 2010 04:43]

Report message to a moderator

Re: Problem in custom classloader-environment: Object XYZ is not a known entity type [message #515241 is a reply to message #515211] Thu, 18 February 2010 04:40 Go to previous message
Alex C. is currently offline Alex C.
Messages: 4
Registered: February 2010
Location: Germany
Junior Member

OMG .. I think i finally found the solution Very Happy

I debugged the code again and again (very wierd stuff Sad ) and found out, that a temporary classloader is used, which was based on the thread's context classloader.

As the context classloader of the thread that "getEntityManager()" method calling had no clue ybout my delegation classloader, the persistence xml was not found and thus, the entitys where not recognized and thus unknown.

I added the following line to the getEntityManager() method just before getting the EntityManagerFactory and creating the EntityManager:

Thread.currentThread().setContextClassLoader(Deployer.getInstance().getDelegatingClassLoader());


Now it works as expected. *YEEEEEES*

Thanks for reading Smile

best regards,
Alex

[Updated on: Thu, 18 February 2010 04:41]

Report message to a moderator

Previous Topic:Lazy relationship is intiated, when it shouldn't be
Next Topic:Cache hits for non object queries
Goto Forum:
  


Current Time: Thu Jul 24 16:09:41 EDT 2014

Powered by FUDForum. Page generated in 0.01736 seconds