This repository has been archived by the owner. It is now read-only.

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
@softprops

softprops commented Oct 31, 2011

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)
@codahale

This comment has been minimized.

Show comment
Hide comment
@codahale

codahale Oct 31, 2011

Owner

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.

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.

@softprops

This comment has been minimized.

Show comment
Hide comment
@softprops

softprops Oct 31, 2011

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

softprops commented Oct 31, 2011

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

@codahale

This comment has been minimized.

Show comment
Hide comment
@codahale

codahale Oct 31, 2011

Owner

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.
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 codahale closed this Oct 31, 2011

@softprops

This comment has been minimized.

Show comment
Hide comment
@softprops

softprops 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

softprops commented 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

@softprops

This comment has been minimized.

Show comment
Hide comment
@softprops

softprops Oct 31, 2011

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"}""")) }
  }

softprops commented Oct 31, 2011

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 subscribe to this conversation on GitHub. Already have an account? Sign in.