<!-- 
RSS generated by JIRA (4.4#649-r158309) at Thu Jun 20 02:03:26 CDT 2013

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary add field=key&field=summary to the URL of your request.
For example:
http://dev.clojure.org/jira/si/jira.issueviews:issue-xml/CLJ-1157/CLJ-1157.xml?field=key&field=summary
-->
<rss version="0.92" >
<channel>
    <title>Clojure JIRA</title>
    <link>http://dev.clojure.org/jira</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>4.4</version>
        <build-number>649</build-number>
        <build-date>25-07-2011</build-date>
    </build-info>

<item>
            <title>[CLJ-1157] Classes generated by gen-class aren&apos;t loadable from remote codebase for mis-implementation of static-initializer</title>
                <link>http://dev.clojure.org/jira/browse/CLJ-1157</link>
                <project id="10010" key="CLJ">Clojure</project>
                        <description>&lt;p&gt;When a client program uses a remote service which uses RMI, and the service returns a object which created with gen-class with clojure as the return value, the return value is not loadable at client side.&lt;/p&gt;

&lt;p&gt;At client side, a following exeption will be thrown.&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;Exception in thread &lt;span class=&quot;code-quote&quot;&gt;&quot;main&quot;&lt;/span&gt; java.lang.ExceptionInInitializerError
        at java.io.ObjectStreamClass.hasStaticInitializer(Native Method)
        at java.io.ObjectStreamClass.computeDefaultSUID(ObjectStreamClass.java:1723)
        at java.io.ObjectStreamClass.access$100(ObjectStreamClass.java:69)
        at java.io.ObjectStreamClass$1.run(ObjectStreamClass.java:247)
        at java.io.ObjectStreamClass$1.run(ObjectStreamClass.java:245)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.io.ObjectStreamClass.getSerialVersionUID(ObjectStreamClass.java:244)
        at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:600)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1601)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1514)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
        at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:324)
        at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:173)
        at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
        at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
        at $Proxy0.getResult(Unknown Source)
        at client.SampleClient$_main.doInvoke(SampleClient.clj:12)
        at clojure.lang.RestFn.invoke(RestFn.java:397)
        at clojure.lang.AFn.applyToHelper(AFn.java:159)
        at clojure.lang.RestFn.applyTo(RestFn.java:132)
        at client.SampleClient.main(Unknown Source)
 Caused by: java.io.FileNotFoundException: Could not locate remoteserver/SampleInterfaceImpl__init.class or remoteserver/SampleInterfaceImpl.clj on classpath: 
        at clojure.lang.RT.load(RT.java:434)
        at clojure.lang.RT.load(RT.java:402)
        at clojure.core$load$fn__5039.invoke(core.clj:5520)
        at clojure.core$load.doInvoke(core.clj:5519)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at clojure.lang.Var.invoke(Var.java:415)
        at remoteserver.SampleInterfaceImpl.&amp;lt;clinit&amp;gt;(Unknown Source)
        ... 23 more&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;h2&gt;&lt;a name=&quot;HOWTOREPRODUCTTHISISSUE&quot;&gt;&lt;/a&gt;HOW TO REPRODUCT THIS ISSUE&lt;/h2&gt;

&lt;p&gt;If you want to see this issue at your computer, clone my example project from my github.&lt;/p&gt;

&lt;p&gt;git clone git://github.com/tyano/clojure_genclass_fix.git&lt;/p&gt;

&lt;p&gt;and build them (You must have installed Leiningen 2):&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-none&quot;&gt;cd clojure_genclass_fix
sh build.sh&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;start rmiregistry:&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-none&quot;&gt;rmiregistry &amp;amp;&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;start remoteserver:&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-none&quot;&gt;cd remoteserver
sh start.sh&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will see a message &quot;Server ready. &quot; or &quot;Server ready. (rebind)&quot;.&lt;/p&gt;

&lt;p&gt;At last, start client program:&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-none&quot;&gt;cd ../client
sh start.sh&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Without my patch, you will see a same Exception described above. But with clojure with my patch, you will see a right response message: &quot;response = this is sample.&quot;&lt;/p&gt;


&lt;h2&gt;&lt;a name=&quot;THEREASON&quot;&gt;&lt;/a&gt;THE REASON        &lt;/h2&gt;

&lt;p&gt;The reason of this problem is in bytecodes generated by gen-class. A gen-classed class (in this case, SampleInterfaceImpl.class) uses a static-initializer for loading SampleInterfaceImpl__init.class (which load other classes which implements functions in the class). The static-initializer is like bellow: (the following code is decompiled with JD - &lt;a href=&quot;http://java.decompiler.free.fr/?q=jdgui&quot;&gt;http://java.decompiler.free.fr/?q=jdgui&lt;/a&gt; )&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;&lt;span class=&quot;code-keyword&quot;&gt;static&lt;/span&gt;
  {
    RT.&lt;span class=&quot;code-keyword&quot;&gt;var&lt;/span&gt;(&lt;span class=&quot;code-quote&quot;&gt;&quot;clojure.core&quot;&lt;/span&gt;, &lt;span class=&quot;code-quote&quot;&gt;&quot;load&quot;&lt;/span&gt;).invoke(&lt;span class=&quot;code-quote&quot;&gt;&quot;/remoteserver/SampleInterfaceImpl&quot;&lt;/span&gt;);
  }&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Very simple code. it seems non-problematic. But RT.load changes the classloader for loading __init.class in the processing! RT.load in default uses a context-classloader for loading classes. But all classes depending on a gen-classed class must be loaded a same classloader with a main gen-classed class. In this case, RT.load must use a remote URLClassLoader which load a main class.&lt;/p&gt;

&lt;p&gt;So, gen-class must be create bytecodes that is same with the following java code.&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;&lt;span class=&quot;code-keyword&quot;&gt;static&lt;/span&gt;
  {
    Var.pushThreadBindings(RT.map(&lt;span class=&quot;code-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;code-object&quot;&gt;Object&lt;/span&gt;[] { &lt;span class=&quot;code-object&quot;&gt;Compiler&lt;/span&gt;.LOADER, SampleInterfaceImpl.class.getClassLoader() }));
    &lt;span class=&quot;code-keyword&quot;&gt;try&lt;/span&gt; {
        RT.&lt;span class=&quot;code-keyword&quot;&gt;var&lt;/span&gt;(&lt;span class=&quot;code-quote&quot;&gt;&quot;clojure.core&quot;&lt;/span&gt;, &lt;span class=&quot;code-quote&quot;&gt;&quot;load&quot;&lt;/span&gt;).invoke(&lt;span class=&quot;code-quote&quot;&gt;&quot;/remoteserver/SampleInterfaceImpl&quot;&lt;/span&gt;);
    }
    &lt;span class=&quot;code-keyword&quot;&gt;finally&lt;/span&gt; 
    {
        Var.popThreadBindings();
    }
  }&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this code, RT.load will uses a same classloader which load SampleInterfaceImpl.class.&lt;br/&gt;
My patch for gen-class will create bytecodes equal to the above example.&lt;/p&gt;

&lt;p&gt;You can use an attached patch &apos;20130204_fix_classloader.diff&apos;, or pull &apos;fix_classloader&apos; branch from my github repositry ( git@github.com:tyano/clojure.git ).&lt;/p&gt;</description>
                <environment>Tested on Mac OS X 10.8 and Oracle JVM 1.7.0 update 13.</environment>
            <key id="15988">CLJ-1157</key>
            <summary>Classes generated by gen-class aren&apos;t loadable from remote codebase for mis-implementation of static-initializer</summary>
                <type id="1" iconUrl="http://dev.clojure.org/jira/images/icons/bug.gif">Defect</type>
                                <priority id="3" iconUrl="http://dev.clojure.org/jira/images/icons/priority_major.gif">Major</priority>
                    <status id="1" iconUrl="http://dev.clojure.org/jira/images/icons/status_open.gif">Open</status>
                    <resolution id="-1">Unresolved</resolution>
                                <assignee username="-1">Unassigned</assignee>
                                <reporter username="tyano">Tsutomu Yano</reporter>
                        <labels>
                    </labels>
                <created>Mon, 4 Feb 2013 01:06:21 -0600</created>
                <updated>Fri, 12 Apr 2013 09:19:05 -0500</updated>
                                    <version>Release 1.4</version>
                <version>Release 1.5</version>
                                                        <due></due>
                    <votes>0</votes>
                        <watches>1</watches>
                        <comments>
                    <comment id="30675" author="stu" created="Fri, 1 Mar 2013 10:20:27 -0600"  >&lt;p&gt;This sounds reasonable, but anything touching classloaders must be considered very carefully.&lt;/p&gt;</comment>
                    <comment id="30679" author="stu" created="Fri, 1 Mar 2013 12:12:09 -0600"  >&lt;p&gt;It seems overly complex to have the patch do so much code generation.  Why not implement a method that does this job, and have the generated code call that?&lt;/p&gt;
</comment>
                </comments>
                    <attachments>
                    <attachment id="11832" name="20130204_fix_classloader.diff" size="4563" author="tyano" created="Mon, 4 Feb 2013 01:06:21 -0600" />
                </attachments>
            <subtasks>
        </subtasks>
                <customfields>
                                <customfield id="customfield_10002" key="com.atlassian.jira.plugin.system.customfieldtypes:select">
                <customfieldname>Approval</customfieldname>
                <customfieldvalues>
                        <customfieldvalue key="10003">Vetted</customfieldvalue>

                </customfieldvalues>
            </customfield>
                                                                                    <customfield id="customfield_10010" key="com.pyxis.greenhopper.jira:gh-global-rank">
                <customfieldname>Global Rank</customfieldname>
                <customfieldvalues>
                    
                </customfieldvalues>
            </customfield>
                                            <customfield id="customfield_10000" key="com.atlassian.jira.plugin.system.customfieldtypes:select">
                <customfieldname>Patch</customfieldname>
                <customfieldvalues>
                        <customfieldvalue key="10001">Code</customfieldvalue>

                </customfieldvalues>
            </customfield>
                                                                                        </customfields>
    </item>
</channel>
</rss>