Skip to content

Commit

Permalink
feat: 🚀 Remove usage of Manifest in ScalaObjectMapper
Browse files Browse the repository at this point in the history
Replaced with typeclasses
  • Loading branch information
gaeljw committed May 19, 2021
1 parent 5a2c069 commit d06e656
Showing 1 changed file with 129 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@ import com.fasterxml.jackson.core.{JsonParser, TreeNode}
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper
import com.fasterxml.jackson.databind.jsonschema.JsonSchema
import com.fasterxml.jackson.databind._
import com.fasterxml.jackson.databind.`type`.TypeFactory
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper

import scala.reflect.{ClassTag, classTag}

object ScalaObjectMapper {
def ::(o: JsonMapper) = new Mixin(o)
final class Mixin private[ScalaObjectMapper](mapper: JsonMapper)
extends JsonMapper(mapper.rebuild().build()) with ScalaObjectMapper
}

@deprecated("ScalaObjectMapper is deprecated because Manifests are not supported in Scala3", "2.12.1")
//@deprecated("ScalaObjectMapper is deprecated because Manifests are not supported in Scala3", "2.12.1")
trait ScalaObjectMapper {
self: ObjectMapper =>

Expand Down Expand Up @@ -64,6 +68,8 @@ trait ScalaObjectMapper {
* type (typically <code>java.lang.Class</code>), but without explicit
* context.
*/
def constructType[T](implicit m: JavaTypeable[T]): JavaType = {
m.asJavaType(getTypeFactory)
def constructType[T](implicit m: Manifest[T]): JavaType = {
val clazz = m.runtimeClass
if (isArray(clazz)) {
Expand Down Expand Up @@ -111,7 +117,7 @@ trait ScalaObjectMapper {
* and specifically needs to be used if the root type is a
* parameterized (generic) container type.
*/
def readValue[T: Manifest](jp: JsonParser): T = {
def readValue[T: JavaTypeable](jp: JsonParser): T = {
readValue(jp, constructType[T])
}

Expand All @@ -127,7 +133,7 @@ trait ScalaObjectMapper {
* <p>
* Note that [[com.fasterxml.jackson.databind.ObjectReader]] has more complete set of variants.
*/
def readValues[T: Manifest](jp: JsonParser): MappingIterator[T] = {
def readValues[T: JavaTypeable](jp: JsonParser): MappingIterator[T] = {
readValues(jp, constructType[T])
}

Expand All @@ -146,8 +152,8 @@ trait ScalaObjectMapper {
* objectMapper.convertValue(n, valueClass);
* </pre>
*/
def treeToValue[T: Manifest](n: TreeNode): T = {
treeToValue(n, manifest[T].runtimeClass).asInstanceOf[T]
def treeToValue[T: ClassTag](n: TreeNode): T = {
treeToValue(n, classTag[T].runtimeClass).asInstanceOf[T]
}

/*
Expand Down Expand Up @@ -194,63 +200,63 @@ trait ScalaObjectMapper {
* convenience methods
**********************************************************
*/
def readValue[T: Manifest](src: File): T = {
def readValue[T: JavaTypeable](src: File): T = {
readValue(src, constructType[T])
}

def readValue[T: Manifest](src: URL): T = {
def readValue[T: JavaTypeable](src: URL): T = {
readValue(src, constructType[T])
}

def readValue[T: Manifest](content: String): T = {
def readValue[T: JavaTypeable](content: String): T = {
readValue(content, constructType[T])
}

def readValue[T: Manifest](src: Reader): T = {
def readValue[T: JavaTypeable](src: Reader): T = {
readValue(src, constructType[T])
}

def readValue[T: Manifest](src: InputStream): T = {
def readValue[T: JavaTypeable](src: InputStream): T = {
readValue(src, constructType[T])
}

def readValue[T: Manifest](src: Array[Byte]): T = {
def readValue[T: JavaTypeable](src: Array[Byte]): T = {
readValue(src, constructType[T])
}

def readValue[T: Manifest](src: Array[Byte], offset: Int, len: Int): T = {
def readValue[T: JavaTypeable](src: Array[Byte], offset: Int, len: Int): T = {
readValue(src, offset, len, constructType[T])
}

def updateValue[T: Manifest](valueToUpdate: T, src: File): T = {
def updateValue[T: JavaTypeable](valueToUpdate: T, src: File): T = {
objectReaderFor(valueToUpdate).readValue(src)
}

def updateValue[T: Manifest](valueToUpdate: T, src: URL): T = {
def updateValue[T: JavaTypeable](valueToUpdate: T, src: URL): T = {
objectReaderFor(valueToUpdate).readValue(src)
}

def updateValue[T: Manifest](valueToUpdate: T, content: String): T = {
def updateValue[T: JavaTypeable](valueToUpdate: T, content: String): T = {
objectReaderFor(valueToUpdate).readValue(content)
}

def updateValue[T: Manifest](valueToUpdate: T, src: Reader): T = {
def updateValue[T: JavaTypeable](valueToUpdate: T, src: Reader): T = {
objectReaderFor(valueToUpdate).readValue(src)
}

def updateValue[T: Manifest](valueToUpdate: T, src: InputStream): T = {
def updateValue[T: JavaTypeable](valueToUpdate: T, src: InputStream): T = {
objectReaderFor(valueToUpdate).readValue(src)
}

def updateValue[T: Manifest](valueToUpdate: T, src: Array[Byte]): T = {
def updateValue[T: JavaTypeable](valueToUpdate: T, src: Array[Byte]): T = {
objectReaderFor(valueToUpdate).readValue(src)
}

def updateValue[T: Manifest](valueToUpdate: T, src: Array[Byte], offset: Int, len: Int): T = {
def updateValue[T: JavaTypeable](valueToUpdate: T, src: Array[Byte], offset: Int, len: Int): T = {
objectReaderFor(valueToUpdate).readValue(src, offset, len)
}

private def objectReaderFor[T: Manifest](valueToUpdate: T): ObjectReader = {
private def objectReaderFor[T: JavaTypeable](valueToUpdate: T): ObjectReader = {
readerForUpdating(valueToUpdate).forType(constructType[T])
}

Expand All @@ -265,8 +271,8 @@ trait ScalaObjectMapper {
* Factory method for constructing [[com.fasterxml.jackson.databind.ObjectWriter]] that will
* serialize objects using specified JSON View (filter).
*/
def writerWithView[T: Manifest]: ObjectWriter = {
writerWithView(manifest[T].runtimeClass)
def writerWithView[T: ClassTag]: ObjectWriter = {
writerWithView(classTag[T].runtimeClass)
}

/**
Expand All @@ -288,7 +294,7 @@ trait ScalaObjectMapper {
*
* @since 2.5
*/
def writerFor[T: Manifest]: ObjectWriter = {
def writerFor[T: JavaTypeable]: ObjectWriter = {
writerFor(constructType[T])
}

Expand All @@ -312,16 +318,16 @@ trait ScalaObjectMapper {
* Factory method for constructing [[com.fasterxml.jackson.databind.ObjectReader]] that will
* read or update instances of specified type
*/
def readerFor[T: Manifest]: ObjectReader = {
def readerFor[T: JavaTypeable]: ObjectReader = {
readerFor(constructType[T])
}

/**
* Factory method for constructing [[com.fasterxml.jackson.databind.ObjectReader]] that will
* deserialize objects using specified JSON View (filter).
*/
def readerWithView[T: Manifest]: ObjectReader = {
readerWithView(manifest[T].runtimeClass)
def readerWithView[T: ClassTag]: ObjectReader = {
readerWithView(classTag[T].runtimeClass)
}

/*
Expand All @@ -342,7 +348,7 @@ trait ScalaObjectMapper {
* if so, root cause will contain underlying checked exception data binding
* functionality threw
*/
def convertValue[T: Manifest](fromValue: Any): T = {
def convertValue[T: JavaTypeable](fromValue: Any): T = {
convertValue(fromValue, constructType[T])
}

Expand Down Expand Up @@ -375,26 +381,109 @@ trait ScalaObjectMapper {
*
* @since 2.1
*/
def acceptJsonFormatVisitor[T: Manifest](visitor: JsonFormatVisitorWrapper): Unit = {
acceptJsonFormatVisitor(manifest[T].runtimeClass, visitor)
def acceptJsonFormatVisitor[T: ClassTag](visitor: JsonFormatVisitorWrapper): Unit = {
acceptJsonFormatVisitor(classTag[T].runtimeClass, visitor)
}

private def isArray(c: Class[_]): Boolean = {
c.isArray
}

trait JavaTypeable[T] {
def asJavaType(typeFactory: TypeFactory): JavaType
}

object JavaTypeable {

implicit val anyJavaTypeable: JavaTypeable[Any] = {
new JavaTypeable[Any] {
override def asJavaType(typeFactory: TypeFactory): JavaType = {
val typeArgs: Array[JavaType] = Array()
typeFactory.constructParametricType(classOf[Object], typeArgs: _*)
}
}
}

private val MAP = classOf[collection.Map[_,_]]
private def isMapLike(c: Class[_]): Boolean = {
MAP.isAssignableFrom(c)
implicit def optionJavaTypeable[T : JavaTypeable]: JavaTypeable[Option[T]] = {
new JavaTypeable[Option[T]] {
override def asJavaType(typeFactory: TypeFactory): JavaType = {
val typeArg0 = implicitly[JavaTypeable[T]].asJavaType(typeFactory)
typeFactory.constructReferenceType(classOf[Option[_]], typeArg0)
}
}
}

private val OPTION = classOf[Option[_]]
private def isReference(c: Class[_]): Boolean = {
OPTION.isAssignableFrom(c)
implicit def arrayJavaTypeable[T : JavaTypeable]: JavaTypeable[Array[T]] = {
new JavaTypeable[Array[T]] {
override def asJavaType(typeFactory: TypeFactory): JavaType = {
val typeArg0 = implicitly[JavaTypeable[T]].asJavaType(typeFactory)
typeFactory.constructArrayType(typeArg0)
}
}
}

private val ITERABLE = classOf[collection.Iterable[_]]
private def isCollectionLike(c: Class[_]): Boolean = {
ITERABLE.isAssignableFrom(c)
implicit def mapJavaTypeable[M[_,_] <: Map[_,_], K : JavaTypeable, V: JavaTypeable](implicit ct: ClassTag[M[K,V]]): JavaTypeable[M[K, V]] = {
new JavaTypeable[M[K, V]] {
override def asJavaType(typeFactory: TypeFactory): JavaType = {
val typeArg0 = implicitly[JavaTypeable[K]].asJavaType(typeFactory)
val typeArg1 = implicitly[JavaTypeable[V]].asJavaType(typeFactory)
typeFactory.constructMapLikeType(ct.runtimeClass, typeArg0, typeArg1)
}
}
}

implicit def collectionJavaTypeable[I[_] <: Iterable[_], T : JavaTypeable](implicit ct: ClassTag[I[T]]): JavaTypeable[I[T]] = {
new JavaTypeable[I[T]] {
override def asJavaType(typeFactory: TypeFactory): JavaType = {
val typeArg0 = implicitly[JavaTypeable[T]].asJavaType(typeFactory)
typeFactory.constructCollectionLikeType(ct.runtimeClass, typeArg0)
}
}
}

// TODO generate genX for X up to a large enough number, 10? 22?

implicit def gen3JavaTypeable[T[_, _, _], A: JavaTypeable, B: JavaTypeable, C: JavaTypeable](implicit ct: ClassTag[T[A, B, C]]): JavaTypeable[T[A, B, C]] = {
new JavaTypeable[T[A, B, C]] {
override def asJavaType(typeFactory: TypeFactory): JavaType = {
val typeArgs: Array[JavaType] = Array(
implicitly[JavaTypeable[A]].asJavaType(typeFactory),
implicitly[JavaTypeable[B]].asJavaType(typeFactory),
implicitly[JavaTypeable[C]].asJavaType(typeFactory)
)
typeFactory.constructParametricType(ct.runtimeClass, typeArgs: _*)
}
}
}

implicit def gen2JavaTypeable[T[_, _], A: JavaTypeable, B: JavaTypeable](implicit ct: ClassTag[T[A, B]]): JavaTypeable[T[A, B]] = {
new JavaTypeable[T[A, B]] {
override def asJavaType(typeFactory: TypeFactory): JavaType = {
val typeArgs: Array[JavaType] = Array(
implicitly[JavaTypeable[A]].asJavaType(typeFactory),
implicitly[JavaTypeable[B]].asJavaType(typeFactory)
)
typeFactory.constructParametricType(ct.runtimeClass, typeArgs: _*)
}
}
}

implicit def gen1JavaTypeable[T[_], A: JavaTypeable](implicit ct: ClassTag[T[A]]): JavaTypeable[T[A]] = {
new JavaTypeable[T[A]] {
override def asJavaType(typeFactory: TypeFactory): JavaType = {
val typeArgs: Array[JavaType] = Array(
implicitly[JavaTypeable[A]].asJavaType(typeFactory)
)
typeFactory.constructParametricType(ct.runtimeClass, typeArgs: _*)
}
}
}

implicit def gen0JavaTypeable[T](implicit ct: ClassTag[T]): JavaTypeable[T] = {
new JavaTypeable[T] {
override def asJavaType(typeFactory: TypeFactory): JavaType = {
val typeArgs: Array[JavaType] = Array()
typeFactory.constructParametricType(ct.runtimeClass, typeArgs: _*)
}
}
}

}

0 comments on commit d06e656

Please sign in to comment.