You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by caden whitaker <ca...@gmail.com> on 2010/11/03 20:29:38 UTC

ClassLoader vs GroovyClassLoader

Hey all, hope you aren't tired of me yet

This in a nutshell is the problem:
            ClassLoader parent = getClass().getClassLoader();
            GroovyClassLoader loader = new GroovyClassLoader(parent);
            loader.parseClass(new
File("C:\\tutorial\\src\\main\\java\\org\\example\\cayenne\\persistent\\Store.groovy"));

loader.loadClass("main.java.org.example.cayenne.persistent.Store");

System.out.println(Class.forName("main.java.org.example.cayenne.persistent.Store",
true, loader).toString());

            DataDomain dd =
Configuration.getSharedConfiguration().getDomain();
            ObjectContext context = dd.createDataContext();

Error:
java.lang.ClassNotFoundException: class
main.java.org.example.cayenne.persistent.Store
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    at
main.java.org.example.cayenne.ut.CayenneUnitTest.testBuild(CayenneUnitTest.java:128)

At this point the "Store" object (which is compiled at runtime through
Groovy) does not exist in any context that teh DataContext can find it, the
DataContext is looking for it in Class.forName, but that is looking in the
default ClassLoader. This "Store" object does not exist in that context, it
is in its own ClassLoader (GroovyClassLoader). So how do I tell the system
to load the object from this GroovyClassLoader?? I know this is the issue
because if I take that Store object, make it a Java class, compile it, and
run the same test it works fine.

Re: ClassLoader vs GroovyClassLoader

Posted by caden whitaker <ca...@gmail.com>.
YOU ROCK!

That was all I needed to do, here is the full dynamic and groovified code,
I'll eventually put this in a blog or something, but at least for not it'll
be part of the internet. This is going to look like a lot of code, but most
of it is auto-generated from Cayenne Modeler.


CayenneUnitTest.java
package main.java.org.example.cayenne.ut;

//import groovy.lang.GroovyObject;

//import com.pdi.reporting.ApplicationData;
//import com.pdi.reporting.ApplicationInitializer;
//import com.pdi.reporting.report.ReportData;

import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyShell;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;

import org.apache.cayenne.*;
import org.apache.cayenne.access.*;
import org.apache.cayenne.conf.Configuration;
import org.apache.cayenne.conf.DefaultConfiguration;
import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.map.MapLoader;
import org.apache.cayenne.modeler.ClassLoadingService;
import org.apache.cayenne.modeler.FileClassLoadingService;
import org.apache.cayenne.util.ResourceLocator;
import org.xml.sax.InputSource;

import junit.framework.TestCase;

public class CayenneUnitTest   extends TestCase {
    public CayenneUnitTest(String name)
    {
        super(name);
    }

    //
    // Test Main
    //
    public static void main(String[] args)
        throws Exception
    {
        junit.textui.TestRunner.run(CayenneUnitTest.class);
    }

    private void addMap(Configuration c, InputSource is) throws Exception {

        DataDomain dd = c.getDomain();

        MapLoader ml = new MapLoader();
        DataMap dataMap = ml.loadDataMap(is);

        // Add the shared map to the target data domain
        dd.addMap(dataMap);

        // Add the shared map to the data node
        Collection nodes = dd.getDataNodes();

        if (nodes.size() != 1)
        {
          System.out.println("Expected only one DataNode for DataDomain '" +
                             "" +
                             "' -- this DataDomain is not usable.");
          return;
        }

        Iterator dataNodeIterator = nodes.iterator();

        // We are only getting one, though ...
        while (dataNodeIterator.hasNext())
        {
          DataNode node = (DataNode) dataNodeIterator.next();

          node.addDataMap(dataMap);

        }

    }
    public void testGroovy() throws Exception
    {
        // call groovy expressions from Java code
        Binding binding = new Binding();
        binding.setVariable("foo", new Integer(2));
        GroovyShell shell = new GroovyShell(binding);

        Object value = shell.evaluate("println 'Hello World!'; x = 123;
return foo * 10");
        assertEquals(value.equals(new Integer(20)), true);
        assertEquals(binding.getVariable("x").equals(new Integer(123)),
true);

    }

    // JUnit
    public void testBuild()
        throws Exception
    {

        try {


            ClassLoader parent = GroovyClassLoader.getSystemClassLoader();
            GroovyClassLoader loader = new GroovyClassLoader(parent);
            loader.parseClass(new
File("F:\\tutorial\\src\\main\\java\\org\\example\\cayenne\\persistent\\Store.groovy"));
            loader.parseClass(new
File("F:\\tutorial\\src\\main\\java\\org\\example\\cayenne\\persistent\\Artist.groovy"));
            loader.parseClass(new
File("F:\\tutorial\\src\\main\\java\\org\\example\\cayenne\\persistent\\Painting.groovy"));

            Thread.currentThread().setContextClassLoader(loader);

            addMap(Configuration.getSharedConfiguration(), new
InputSource(new
FileInputStream("F:\\tutorial\\src\\HelloWorld3Map.map.xml")));
            addMap(Configuration.getSharedConfiguration(), new
InputSource(new
FileInputStream("F:\\tutorial\\src\\HelloWorld2Map.map.xml")));

            Class clazz = loader.parseClass(new
File("F:\\tutorial\\src\\main\\java\\org\\example\\cayenne\\persistent\\Test.groovy"));
            GroovyObject obj = (GroovyObject)clazz.newInstance();
            obj.invokeMethod("Execute", null);


        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("End Test");
    }

}


Store.groovy
package main.java.org.example.cayenne.persistent;

import java.util.List;

import org.apache.cayenne.CayenneDataObject;

import main.java.org.example.cayenne.persistent.Painting;

import org.apache.cayenne.CayenneDataObject;

/**
* Class _Painting was generated by Cayenne.
* It is probably a good idea to avoid changing this class manually,
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
public class Store extends CayenneDataObject {

   public static final String NAME_PROPERTY = "name";

   public static final String STORE_ID_PK_COLUMN = "StoreID";

   public void setName(String name) {
       writeProperty("name", name);
   }
   public String getName() {
       return (String)readProperty("name");
   }
}

Artist.groovy
package main.java.org.example.cayenne.persistent;

import java.util.List;

import org.apache.cayenne.CayenneDataObject;

import main.java.org.example.cayenne.persistent.Painting;

/**
 * Class _Artist was generated by Cayenne.
 * It is probably a good idea to avoid changing this class manually,
 * since it may be overwritten next time code is regenerated.
 * If you need to make any customizations, please use subclass.
 */
public class Artist extends CayenneDataObject {

    public static final String NAME_PROPERTY = "name";
    public static final String PAINTINGS1_PROPERTY = "paintings1";

    public static final String ARTIST_ID_PK_COLUMN = "ArtistID";

    public void setName(String name) {
        writeProperty("name", name);
    }
    public String getName() {
        return (String)readProperty("name");
    }

    public void addToPaintings(Painting obj) {
        addToManyTarget("paintings", obj, true);
    }
    public void removeFromPaintings(Painting obj) {
        removeToManyTarget("paintings", obj, true);
    }
    @SuppressWarnings("unchecked")
    public List<Painting> getPaintings() {
        return (List<Painting>)readProperty("paintings1");
    }


}

Painting.groovy
package main.java.org.example.cayenne.persistent;

import org.apache.cayenne.CayenneDataObject;

import main.java.org.example.cayenne.persistent.Artist;

/**
 * Class _Painting was generated by Cayenne.
 * It is probably a good idea to avoid changing this class manually,
 * since it may be overwritten next time code is regenerated.
 * If you need to make any customizations, please use subclass.
 */
public class Painting extends CayenneDataObject {

    public static final String NAME_PROPERTY = "name";
    public static final String ARTIST1_PROPERTY = "artist1";

    public static final String PAINTING_ID_PK_COLUMN = "PaintingID";

    public void setName(String name) {
        writeProperty("name", name);
    }
    public String getName() {
        return (String)readProperty("name");
    }

    public void setArtist(Artist artist) {
        setToOneTarget("artist", artist, true);
    }

    public Artist getArtist() {
        return (Artist)readProperty("artist");
    }


}

Test.groovy
package main.java.org.example.cayenne.persistent;

import groovy.lang.GroovyClassLoader;
import main.java.org.example.cayenne.persistent.Artist;
import main.java.org.example.cayenne.persistent.Painting;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.conf.Configuration;
import org.apache.cayenne.query.SelectQuery;

public class Test {

public Test() {
}
public Execute() {


    ObjectContext context =
Configuration.getSharedConfiguration().getDomain().createDataContext();

    context.newObject(Artist.class).setName("Artist 1");
    context.newObject(Artist.class).setName("Artist 2");
    context.newObject(Artist.class).setName("Artist 3");
    context.newObject(Artist.class).setName("Artist 4");
    context.newObject(Artist.class).setName("Artist 5");
    context.newObject(Artist.class).setName("Artist 6");

    Artist picasso = context.newObject(Artist.class);
    picasso.setName("Pablo Picasso");

    Painting girl = context.newObject(Painting.class);
    girl.setName("Girl Reading at a Table");
    girl.setArtist(picasso);

    Painting stein = context.newObject(Painting.class);
    stein.setName("Gertrude Stein");
    stein.setArtist(picasso);

    SelectQuery query = new SelectQuery(Artist.class);
    query.addOrdering(Artist.NAME_PROPERTY, true);

    context.commitChanges()

    List artists = context.performQuery(query);

    for(artist in artists) {
        System.out.println(artist.getName());
    }
}

}


HelloWorld2Map.map.xml
<?xml version="1.0" encoding="utf-8"?>
<data-map xmlns="http://cayenne.apache.org/schema/3.0/modelMap"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://cayenne.apache.org/schema/3.0/modelMap
http://cayenne.apache.org/schema/3.0/modelMap.xsd"
  project-version="3.0.0.1">
    <property name="defaultPackage2"
value="org.example.cayenne.persistent"/>
    <db-entity name="ARTIST">
        <db-attribute name="ArtistID" type="BIGINT" isPrimaryKey="true"
isMandatory="true"/>
        <db-attribute name="Name" type="VARCHAR" length="255"/>
    </db-entity>

    <db-entity name="PAINTING">
        <db-attribute name="ArtistID" type="BIGINT"/>
        <db-attribute name="Name" type="VARCHAR" length="255"/>
        <db-attribute name="PaintingID" type="BIGINT" isPrimaryKey="true"
isMandatory="true"/>
    </db-entity>

    <obj-entity name="Artist"
className="main.java.org.example.cayenne.persistent.Artist"
dbEntityName="ARTIST">
        <obj-attribute name="name" type="java.lang.String"
db-attribute-path="Name"/>
    </obj-entity>
    <obj-entity name="Painting"
className="main.java.org.example.cayenne.persistent.Painting"
dbEntityName="PAINTING">
        <obj-attribute name="name" type="java.lang.String"
db-attribute-path="Name"/>
    </obj-entity>
    <db-relationship name="paintings" source="ARTIST" target="PAINTING"
toMany="true">
        <db-attribute-pair source="ArtistID" target="ArtistID"/>
    </db-relationship>

    <db-relationship name="artist" source="PAINTING" target="ARTIST"
toMany="false">
        <db-attribute-pair source="ArtistID" target="ArtistID"/>
    </db-relationship>

    <obj-relationship name="paintings" source="Artist" target="Painting"
deleteRule="Deny" db-relationship-path="paintings"/>
    <obj-relationship name="artist" source="Painting" target="Artist"
deleteRule="Nullify" db-relationship-path="artist"/>
</data-map>

HelloWorld3Map.map.xml
<?xml version="1.0" encoding="utf-8"?>
<data-map xmlns="http://cayenne.apache.org/schema/3.0/modelMap"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://cayenne.apache.org/schema/3.0/modelMap
http://cayenne.apache.org/schema/3.0/modelMap.xsd"
  project-version="3.0.0.1">
    <property name="defaultPackage2"
value="org.example.cayenne.persistent"/>
    <db-entity name="STORE">
        <db-attribute name="StoreID" type="BIGINT" isPrimaryKey="true"
isMandatory="true"/>
        <db-attribute name="Name" type="VARCHAR" length="255"/>
    </db-entity>

    <obj-entity name="Store"
className="main.java.org.example.cayenne.persistent.Store"
dbEntityName="STORE">
        <obj-attribute name="name" type="java.lang.String"
db-attribute-path="Name"/>
    </obj-entity>

</data-map>

Re: ClassLoader vs GroovyClassLoader

Posted by Andrus Adamchik <an...@objectstyle.org>.
Also be aware that most (all?) places in Cayenne 3.0.x were we load classes dynamically would use a thread ClassLoader if available:

Thread.currentThread().getContextClassLoader()

so you can force your ClassLoader via Thread.currentThread().setContextClassLoader(cl);

Cayenne 3.1 uses a similar approach, and additionally allows to register a custom service via DI.

Andrus

On Nov 3, 2010, at 3:57 PM, caden whitaker wrote:

> Think I got it, at least doing this gave me a ton of new errors that make
> sense ;) please let me know if you think I'm on the wrong track:
> 
>           ClassLoader parent = getClass().getClassLoader();
>           GroovyClassLoader loader = new GroovyClassLoader(parent);
>           loader.parseClass(new
> File("C:\\tutorial\\src\\main\\java\\org\\example\\cayenne\\persistent\\Store.groovy"));
> 
>           ResourceLocator rl = new ResourceLocator();
>           rl.setClassLoader(loader);
> 
>           Configuration c = new DefaultConfiguration("cayenne.xml", rl);
>           c.addDomain(new DataDomain("default"));
> 
> On Wed, Nov 3, 2010 at 2:29 PM, caden whitaker <ca...@gmail.com>wrote:
> 
>> Hey all, hope you aren't tired of me yet
>> 
>> This in a nutshell is the problem:
>>           ClassLoader parent = getClass().getClassLoader();
>>           GroovyClassLoader loader = new GroovyClassLoader(parent);
>>           loader.parseClass(new
>> File("C:\\tutorial\\src\\main\\java\\org\\example\\cayenne\\persistent\\Store.groovy"));
>> 
>> loader.loadClass("main.java.org.example.cayenne.persistent.Store");
>> 
>> System.out.println(Class.forName("main.java.org.example.cayenne.persistent.Store",
>> true, loader).toString());
>> 
>>           DataDomain dd =
>> Configuration.getSharedConfiguration().getDomain();
>>           ObjectContext context = dd.createDataContext();
>> 
>> Error:
>> java.lang.ClassNotFoundException: class
>> main.java.org.example.cayenne.persistent.Store
>>   at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
>>   at java.security.AccessController.doPrivileged(Native Method)
>>   at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
>>   at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
>>   at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
>>   at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
>>   at
>> main.java.org.example.cayenne.ut.CayenneUnitTest.testBuild(CayenneUnitTest.java:128)
>> 
>> At this point the "Store" object (which is compiled at runtime through
>> Groovy) does not exist in any context that teh DataContext can find it, the
>> DataContext is looking for it in Class.forName, but that is looking in the
>> default ClassLoader. This "Store" object does not exist in that context, it
>> is in its own ClassLoader (GroovyClassLoader). So how do I tell the system
>> to load the object from this GroovyClassLoader?? I know this is the issue
>> because if I take that Store object, make it a Java class, compile it, and
>> run the same test it works fine.
>> 
>> 
>> 


Re: ClassLoader vs GroovyClassLoader

Posted by caden whitaker <ca...@gmail.com>.
Think I got it, at least doing this gave me a ton of new errors that make
sense ;) please let me know if you think I'm on the wrong track:

            ClassLoader parent = getClass().getClassLoader();
            GroovyClassLoader loader = new GroovyClassLoader(parent);
            loader.parseClass(new
File("C:\\tutorial\\src\\main\\java\\org\\example\\cayenne\\persistent\\Store.groovy"));

            ResourceLocator rl = new ResourceLocator();
            rl.setClassLoader(loader);

            Configuration c = new DefaultConfiguration("cayenne.xml", rl);
            c.addDomain(new DataDomain("default"));

On Wed, Nov 3, 2010 at 2:29 PM, caden whitaker <ca...@gmail.com>wrote:

> Hey all, hope you aren't tired of me yet
>
> This in a nutshell is the problem:
>             ClassLoader parent = getClass().getClassLoader();
>             GroovyClassLoader loader = new GroovyClassLoader(parent);
>             loader.parseClass(new
> File("C:\\tutorial\\src\\main\\java\\org\\example\\cayenne\\persistent\\Store.groovy"));
>
> loader.loadClass("main.java.org.example.cayenne.persistent.Store");
>
> System.out.println(Class.forName("main.java.org.example.cayenne.persistent.Store",
> true, loader).toString());
>
>             DataDomain dd =
> Configuration.getSharedConfiguration().getDomain();
>             ObjectContext context = dd.createDataContext();
>
> Error:
> java.lang.ClassNotFoundException: class
> main.java.org.example.cayenne.persistent.Store
>     at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
>     at java.security.AccessController.doPrivileged(Native Method)
>     at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
>     at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
>     at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
>     at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
>     at
> main.java.org.example.cayenne.ut.CayenneUnitTest.testBuild(CayenneUnitTest.java:128)
>
> At this point the "Store" object (which is compiled at runtime through
> Groovy) does not exist in any context that teh DataContext can find it, the
> DataContext is looking for it in Class.forName, but that is looking in the
> default ClassLoader. This "Store" object does not exist in that context, it
> is in its own ClassLoader (GroovyClassLoader). So how do I tell the system
> to load the object from this GroovyClassLoader?? I know this is the issue
> because if I take that Store object, make it a Java class, compile it, and
> run the same test it works fine.
>
>
>