class not found exceptions when parsing in sbt tasks #38

Closed
softprops opened this Issue Oct 31, 2011 · 5 comments

Comments

Projects
None yet
2 participants

I noticed that jerkson will throw a class not found exception when case class parsing occurs within an sbt task.

package baz    

import com.codahale.jerkson.Json._

case class Foo(bar: String)

(TaskKey[Unit]("jerkson", "parse with jerkson")) <<= (streams) map { (out) => 
   out.log.info(parse[Foo]("""{"bar":"boom"}"""))
 }

The relevant stack trace will look something like

    java.lang.ClassNotFoundException: baz.Foo
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:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at com.codahale.jerkson.util.CaseClassSigParser$.loadClass(CaseClassSigParser.scala:135)
at com.codahale.jerkson.util.CaseClassSigParser$.findRootClass(CaseClassSigParser.scala:49)
at com.codahale.jerkson.util.CaseClassSigParser$.parseScalaSig(CaseClassSigParser.scala:42)
at com.codahale.jerkson.util.CaseClassSigParser$.findSym(CaseClassSigParser.scala:56)
at com.codahale.jerkson.util.CaseClassSigParser$.parse(CaseClassSigParser.scala:83)
at com.codahale.jerkson.deser.CaseClassDeserializer.<init>(CaseClassDeserializer.scala:20)
at com.codahale.jerkson.deser.ScalaDeserializers.findBeanDeserializer(ScalaDeserializers.scala:94)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory._findCustomBeanDeserializer(BeanDeserializerFactory.java:391)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:433)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:398)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:307)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:287)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:136)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:157)
at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2461)
at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2376)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1166)
at com.codahale.jerkson.Parser$class.parse(Parser.scala:81)
at com.codahale.jerkson.Json$.parse(Json.scala:6)
at com.codahale.jerkson.Parser$class.parse(Parser.scala:14)
at com.codahale.jerkson.Json$.parse(Json.scala:6)
Owner

codahale commented Oct 31, 2011

Jerkson uses the current thread's ClassLoader, and SBT runs (well, ran—I haven't paid attention to 0.10+) with a highly-restricted class loader, which means you may not be able to parse the @ScalaSig annotation on your case classes.

Thanks. I'll repost this on the sbt mailing list to see if I can't conjure of some bites of info.

Owner

codahale commented Oct 31, 2011

So I'd say this boils down to:

  • Find a class loader with which you can load Foo and use it as the current thread's class loader.

or

  • Get SBT to loosen its class loader restrictions.

codahale closed this Oct 31, 2011

Okay thanks. The relevant post on the sbt list is at http://groups.google.com/group/simple-build-tool/browse_thread/thread/9878b1dc2631f20 if you wanted to listen in, in case some else asks here in the future

bada-bing, bada-boom.

When I explicitly set the current threads class loader to the one the case class was loaded in, the issue disappears. I'll let the the sbt list know for future reference

  private def inClassLoader[T](cls: Class[_])(f: => T): T = {
    val prev = Thread.currentThread.getContextClassLoader
    try {
      Thread.currentThread.setContextClassLoader(
         cls.getClassLoader
      )
      f
    } finally {
     Thread.currentThread.setContextClassLoader(prev)
    }
  }

  // works now
  (TaskKey[Unit]("jerkson", "parse with jerkson")) <<= (streams) map { (out) => 
     inClassLoader(classOf[Foo]) { out.log.info(parse[Foo]("""{"bar":"boom"}""")) }
  }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment