Re: [Q] How to load Clojure as part of Wildfly module?
Hi! I ran into the same issue while helping a colleague in working on the [sonar-clojure Sonarqube|https://github.com/hjhamala/sonar-clojure/] plugin. A quick search on Clojure JIRA reveals couple of discussions, [this one|https://dev.clojure.org/jira/browse/CLJ-260?focusedCommentId=23453&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-23453] maybe the most relevant. In our case, we also wrote a piece of Java code to set up the threads context classloader so that RT can load itself. ClassLoader ccl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(this.getClass(). getClassLoader()); RT.init(); Var.pushThreadBindings(RT.map(RT.USE_CONTEXT_CLASSLOADER, RT.F)); } finally { Thread.currentThread().setContextClassLoader(ccl); } I think it might be neat to have a way to allow the RT to load itself from the classloader that loaded the RT class itself, instead of the thread's context classloader. A system property might be enough, but I started to think about a way to specify this even in a gen-classed. This would need less "glue", since a gen-classed class causes the RT class to load, in which case there is a need for callsite glue to setup the thread's context classloader. Maybe a new JIRA ticket might be a good place for the discussion :) - Kimmo torstai 7. helmikuuta 2019 23.02.24 UTC+2 henrik42 kirjoitti: > > Rastko - thanks for the reply. My > /modules/buttle/main/module.xml looks like this: > > > > > > > > > > > > > And the driver in standalone.xml: > > > > > > The loading of my classes incl. clojure.lang.RT works "in > principle". Only when Clojure uses the TCCL to load clojure/core.clj > things fail. To see what's > happening I changed > java/buttle/SetContextClassLoaderInStaticInitializer.java to: > > package buttle; > public class SetContextClassLoaderInStaticInitializer { > static { > ClassLoader tccl = > Thread.currentThread().getContextClassLoader(); > System.out.println("tccl = " + tccl); > System.out.println("tccl sees clojure/core.clj at " + > tccl.getResource("clojure/core.clj")); > ClassLoader myCl = > SetContextClassLoaderInStaticInitializer.class.getClassLoader(); > System.out.println("myCl = " + myCl); > System.out.println("myCl sees clojure/core.clj at " + > myCl.getResource("clojure/core.clj")); > > Thread.currentThread().setContextClassLoader(SetContextClassLoaderInStaticInitializer.class.getClassLoader()); > } > } > > I get: > > tccl = ModuleClassLoader for Module "org.jboss.as.controller" version > 4.0.0.Final from local module loader @6adca536 >(finder: local module finder @357246de (roots: > C:\henrik\wildfly-12.0.0.Final\modules,C:\henrik\wildfly-12.0.0.Final\modules\system\layers\base)) > tccl sees clojure/core.clj at null > myCl = ModuleClassLoader for Module "buttle" from local module loader > @6adca536 (finder: local module finder @357246de >(roots: > C:\henrik\wildfly-12.0.0.Final\modules,C:\henrik\wildfly-12.0.0.Final\modules\system\layers\base)) > myCl sees clojure/core.clj at > jar:file:/C:/henrik/wildfly-12.0.0.Final/modules/buttle/main/./buttle-standalone.jar!/clojure/core.clj > > I checked that my class and clojure.lang.RT are loaded with the same > classloader. So the TCCL which Wildfly puts into > place cannot load clojure/core.clj. But the (module) classloader which > loaded my class and clojure.lang.RT CAN load it. That's > why I came up with the idea of replacing the TCCL before > clojure.lang.RT runs. > > I believe that the way Wildfly uses the different classloaders is > absolutly on purpose. In [1] you find > arguments for why libraries should not use the TCCL for certain things. > And one could argue, that Clojure > is doing it the wrong way. > > I believe that the existence of clojure.core/*use-context-classloader* is > due to someone realizing that there are > cases when you cannot use the TCCL (like in mine). In my case though I > just can't set that var because of the chicken-egg-problem > as I pointed out. > > I think that adding additional dependencies or adding exports won't > change the Module-"org.jboss.as.controller"-classloader. But I'll check > tomorrow. > > One solution that comes to mind is to change clojure.lang/RT so that the > *use-context-classloader* var is not initialized to > true but to (Boolean/parseBoolean (System/getProperty > "clojure.use-context-classloader" "true")) > > Henrik > > [1] https://developer.jboss.org/wiki/ModuleCompatibleClassloadingGuide > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note th
Re: [Q] How to load Clojure as part of Wildfly module?
Rastko - thanks for the reply. My /modules/buttle/main/module.xml looks like this: And the driver in standalone.xml: The loading of my classes incl. clojure.lang.RT works "in principle". Only when Clojure uses the TCCL to load clojure/core.clj things fail. To see what's happening I changed java/buttle/SetContextClassLoaderInStaticInitializer.java to: package buttle; public class SetContextClassLoaderInStaticInitializer { static { ClassLoader tccl = Thread.currentThread().getContextClassLoader(); System.out.println("tccl = " + tccl); System.out.println("tccl sees clojure/core.clj at " + tccl.getResource("clojure/core.clj")); ClassLoader myCl = SetContextClassLoaderInStaticInitializer.class.getClassLoader(); System.out.println("myCl = " + myCl); System.out.println("myCl sees clojure/core.clj at " + myCl.getResource("clojure/core.clj")); Thread.currentThread().setContextClassLoader(SetContextClassLoaderInStaticInitializer.class.getClassLoader()); } } I get: tccl = ModuleClassLoader for Module "org.jboss.as.controller" version 4.0.0.Final from local module loader @6adca536 (finder: local module finder @357246de (roots: C:\henrik\wildfly-12.0.0.Final\modules,C:\henrik\wildfly-12.0.0.Final\modules\system\layers\base)) tccl sees clojure/core.clj at null myCl = ModuleClassLoader for Module "buttle" from local module loader @6adca536 (finder: local module finder @357246de (roots: C:\henrik\wildfly-12.0.0.Final\modules,C:\henrik\wildfly-12.0.0.Final\modules\system\layers\base)) myCl sees clojure/core.clj at jar:file:/C:/henrik/wildfly-12.0.0.Final/modules/buttle/main/./buttle-standalone.jar!/clojure/core.clj I checked that my class and clojure.lang.RT are loaded with the same classloader. So the TCCL which Wildfly puts into place cannot load clojure/core.clj. But the (module) classloader which loaded my class and clojure.lang.RT CAN load it. That's why I came up with the idea of replacing the TCCL before clojure.lang.RT runs. I believe that the way Wildfly uses the different classloaders is absolutly on purpose. In [1] you find arguments for why libraries should not use the TCCL for certain things. And one could argue, that Clojure is doing it the wrong way. I believe that the existence of clojure.core/*use-context-classloader* is due to someone realizing that there are cases when you cannot use the TCCL (like in mine). In my case though I just can't set that var because of the chicken-egg-problem as I pointed out. I think that adding additional dependencies or adding exports won't change the Module-"org.jboss.as.controller"-classloader. But I'll check tomorrow. One solution that comes to mind is to change clojure.lang/RT so that the *use-context-classloader* var is not initialized to true but to (Boolean/parseBoolean (System/getProperty "clojure.use-context-classloader" "true")) Henrik [1] https://developer.jboss.org/wiki/ModuleCompatibleClassloadingGuide -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [Q] How to load Clojure as part of Wildfly module?
Hm, it's been really long a go when I've last dealt with EE container but could you tell how does your module exports are set in module definition? Exports are I believe what defines what is exposed to the "outside" world. Furthermore, it might be that you should also add module imports in your app so it is able to see exposed classes/packages. I can't tell for sure this could or could not help but that is something what I could remember of. On Wednesday, February 6, 2019 at 10:40:39 PM UTC+1, henrik42 wrote: > > Hi, > > I'm working on a "proxying JDBC driver" in Clojure [1]. Everything is > working fine. But I had one problem with the way Clojure > (i.e. clojure.lang.RT) manages its classloader. > > When Wildfly loads my UBERJAR which contains Clojure and > loads/instanciates my gen-class `buttle.jdbc.Driver` then its static > initializer will load `clojure.lang.RT`. At this point the current > thread's context classloader (TCCL; which is put into place by > Wildfly) does NOT point to the one that is loading my code and the > TCCL in-fact does not "see" my classes. > > So when Clojure/RT then tries to find `clojure/core.clj` it fails > because Clojure uses the TCCL for loading [2]. I could try to set > `clojure.core/*use-context-classloader*` to false but this leads to a > chicken-egg-problem since for doing that, `clojure.lang/RT` would have > to be loaded in the first place. > > So my question is: is there a nice way out of this? > > The workaround I came up with was to compile a Java class [3] which is > the super class of my gen class [4]. And since static initializers are > called in order super-class->derived-class the static initializer of > the super-class is used to set the TCCL to the one that loads my code > base. After that Clojure finds clojure/core.clj without problems. > > Any ideas on how to do without this hack? > > Henrik > > [1] https://github.com/henrik42/buttle/ > [2] > https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L2174 > [3] > https://github.com/henrik42/buttle/blob/master/java/buttle/SetContextClassLoaderInStaticInitializer.java > [4] > https://github.com/henrik42/buttle/blob/master/src/buttle/driver.clj#L29 > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[Q] How to load Clojure as part of Wildfly module?
Hi, I'm working on a "proxying JDBC driver" in Clojure [1]. Everything is working fine. But I had one problem with the way Clojure (i.e. clojure.lang.RT) manages its classloader. When Wildfly loads my UBERJAR which contains Clojure and loads/instanciates my gen-class `buttle.jdbc.Driver` then its static initializer will load `clojure.lang.RT`. At this point the current thread's context classloader (TCCL; which is put into place by Wildfly) does NOT point to the one that is loading my code and the TCCL in-fact does not "see" my classes. So when Clojure/RT then tries to find `clojure/core.clj` it fails because Clojure uses the TCCL for loading [2]. I could try to set `clojure.core/*use-context-classloader*` to false but this leads to a chicken-egg-problem since for doing that, `clojure.lang/RT` would have to be loaded in the first place. So my question is: is there a nice way out of this? The workaround I came up with was to compile a Java class [3] which is the super class of my gen class [4]. And since static initializers are called in order super-class->derived-class the static initializer of the super-class is used to set the TCCL to the one that loads my code base. After that Clojure finds clojure/core.clj without problems. Any ideas on how to do without this hack? Henrik [1] https://github.com/henrik42/buttle/ [2] https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L2174 [3] https://github.com/henrik42/buttle/blob/master/java/buttle/SetContextClassLoaderInStaticInitializer.java [4] https://github.com/henrik42/buttle/blob/master/src/buttle/driver.clj#L29 -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.