Skip to content

Commit

Permalink
Allow for a custom ClassLoader to be used for case classes.
Browse files Browse the repository at this point in the history
Closes codahale#25.
  • Loading branch information
codahale committed Aug 18, 2011
1 parent 7eb954e commit 6a69533
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 18 deletions.
4 changes: 3 additions & 1 deletion src/main/scala/com/codahale/jerkson/Json.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import org.codehaus.jackson.{JsonGenerator, JsonParser => JacksonParser}
object Json extends Json

trait Json extends Parser with Generator {
protected val classLoader = Thread.currentThread().getContextClassLoader

protected val mapper = new ObjectMapper
mapper.registerModule(new ScalaModule)
mapper.registerModule(new ScalaModule(classLoader))

protected val factory = new MappingJsonFactory(mapper)
factory.enable(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT)
Expand Down
8 changes: 2 additions & 6 deletions src/main/scala/com/codahale/jerkson/ScalaModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@ import org.codehaus.jackson.Version
import org.codehaus.jackson.map.Module
import ser.ScalaSerializers

/**
*
* @author coda
*/
class ScalaModule extends Module {
class ScalaModule(classLoader: ClassLoader) extends Module {
def version = new Version(0, 2, 0, "")
def getModuleName = "jerkson"

def setupModule(context: SetupContext) {
context.addDeserializers(new ScalaDeserializers)
context.addDeserializers(new ScalaDeserializers(classLoader))
context.addSerializers(new ScalaSerializers)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import org.codehaus.jackson.map.annotate.JsonCachable
@JsonCachable
class CaseClassDeserializer(config: DeserializationConfig,
javaType: JavaType,
provider: DeserializerProvider) extends JsonDeserializer[Object] {
provider: DeserializerProvider,
classLoader: ClassLoader) extends JsonDeserializer[Object] {
require(javaType.getRawClass.getConstructors.length == 1, "Case classes must only have one constructor.")
private val constructor = javaType.getRawClass.getConstructors.head
private val params = CaseClassSigParser.parse(javaType.getRawClass, config.getTypeFactory).toArray
private val params = CaseClassSigParser.parse(javaType.getRawClass, config.getTypeFactory, classLoader).toArray

def deserialize(jp: JsonParser, ctxt: DeserializationContext): Object = {
if (jp.getCurrentToken == JsonToken.START_OBJECT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import scala.collection.{Traversable, MapLike, immutable, mutable}
import com.codahale.jerkson.AST.{JNull, JValue}
import scala.collection.generic.{MapFactory, GenericCompanion}

class ScalaDeserializers extends Deserializers.None {
class ScalaDeserializers(classLoader: ClassLoader) extends Deserializers.None {
override def findBeanDeserializer(javaType: JavaType, config: DeserializationConfig,
provider: DeserializerProvider, beanDesc: BeanDescription,
property: BeanProperty) = {
Expand Down Expand Up @@ -91,7 +91,7 @@ class ScalaDeserializers extends Deserializers.None {
} else if (klass == classOf[Either[_,_]]) {
new EitherDeserializer(config, javaType, provider)
} else if (classOf[Product].isAssignableFrom(klass)) {
new CaseClassDeserializer(config, javaType, provider)
new CaseClassDeserializer(config, javaType, provider, classLoader)
} else null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,27 @@ object CaseClassSigParser {
}
}

def parse[A](clazz: Class[A], factory: TypeFactory) = {
def parse[A](clazz: Class[A], factory: TypeFactory, classLoader: ClassLoader) = {
findSym(clazz).children
.filter(c => c.isCaseAccessor && !c.isPrivate)
.map(_.asInstanceOf[MethodSymbol])
.zipWithIndex
.flatMap {
case (ms, idx) => {
ms.infoType match {
case NullaryMethodType(t: TypeRefType) => Some(ms.name -> typeRef2JavaType(t, factory))
case NullaryMethodType(t: TypeRefType) => Some(ms.name -> typeRef2JavaType(t, factory, classLoader))
case _ => None
}
}
}
}

protected def typeRef2JavaType(ref: TypeRefType, factory: TypeFactory): JavaType = {
protected def typeRef2JavaType(ref: TypeRefType, factory: TypeFactory, classLoader: ClassLoader): JavaType = {
try {
val klass = loadClass(ref.symbol.path)
val klass = loadClass(ref.symbol.path, classLoader)
factory.constructParametricType(
klass, ref.typeArgs.map {
t => typeRef2JavaType(t.asInstanceOf[TypeRefType], factory)
t => typeRef2JavaType(t.asInstanceOf[TypeRefType], factory, classLoader)
}: _*
)
} catch {
Expand All @@ -110,7 +110,7 @@ object CaseClassSigParser {
}
}

protected def loadClass(path: String) = path match {
protected def loadClass(path: String, classLoader: ClassLoader) = path match {
case "scala.Predef.Map" => classOf[Map[_, _]]
case "scala.Predef.Set" => classOf[Set[_]]
case "scala.Predef.String" => classOf[String]
Expand All @@ -137,6 +137,6 @@ object CaseClassSigParser {
case "scala.Char" => classOf[java.lang.Character]
case "scala.Any" => classOf[Any]
case "scala.AnyRef" => classOf[AnyRef]
case name => Class.forName(name)
case name => classLoader.loadClass(name)
}
}

0 comments on commit 6a69533

Please sign in to comment.