Skip to content

Commit d06e656

Browse files
committed
feat: 🚀 Remove usage of Manifest in ScalaObjectMapper
Replaced with typeclasses
1 parent 5a2c069 commit d06e656

File tree

1 file changed

+129
-40
lines changed

1 file changed

+129
-40
lines changed

src/main/scala-2.+/com/fasterxml/jackson/module/scala/ScalaObjectMapper.scala

Lines changed: 129 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@ import com.fasterxml.jackson.core.{JsonParser, TreeNode}
77
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper
88
import com.fasterxml.jackson.databind.jsonschema.JsonSchema
99
import com.fasterxml.jackson.databind._
10+
import com.fasterxml.jackson.databind.`type`.TypeFactory
1011
import com.fasterxml.jackson.databind.json.JsonMapper
12+
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper
13+
14+
import scala.reflect.{ClassTag, classTag}
1115

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

18-
@deprecated("ScalaObjectMapper is deprecated because Manifests are not supported in Scala3", "2.12.1")
22+
//@deprecated("ScalaObjectMapper is deprecated because Manifests are not supported in Scala3", "2.12.1")
1923
trait ScalaObjectMapper {
2024
self: ObjectMapper =>
2125

@@ -64,6 +68,8 @@ trait ScalaObjectMapper {
6468
* type (typically <code>java.lang.Class</code>), but without explicit
6569
* context.
6670
*/
71+
def constructType[T](implicit m: JavaTypeable[T]): JavaType = {
72+
m.asJavaType(getTypeFactory)
6773
def constructType[T](implicit m: Manifest[T]): JavaType = {
6874
val clazz = m.runtimeClass
6975
if (isArray(clazz)) {
@@ -111,7 +117,7 @@ trait ScalaObjectMapper {
111117
* and specifically needs to be used if the root type is a
112118
* parameterized (generic) container type.
113119
*/
114-
def readValue[T: Manifest](jp: JsonParser): T = {
120+
def readValue[T: JavaTypeable](jp: JsonParser): T = {
115121
readValue(jp, constructType[T])
116122
}
117123

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

@@ -146,8 +152,8 @@ trait ScalaObjectMapper {
146152
* objectMapper.convertValue(n, valueClass);
147153
* </pre>
148154
*/
149-
def treeToValue[T: Manifest](n: TreeNode): T = {
150-
treeToValue(n, manifest[T].runtimeClass).asInstanceOf[T]
155+
def treeToValue[T: ClassTag](n: TreeNode): T = {
156+
treeToValue(n, classTag[T].runtimeClass).asInstanceOf[T]
151157
}
152158

153159
/*
@@ -194,63 +200,63 @@ trait ScalaObjectMapper {
194200
* convenience methods
195201
**********************************************************
196202
*/
197-
def readValue[T: Manifest](src: File): T = {
203+
def readValue[T: JavaTypeable](src: File): T = {
198204
readValue(src, constructType[T])
199205
}
200206

201-
def readValue[T: Manifest](src: URL): T = {
207+
def readValue[T: JavaTypeable](src: URL): T = {
202208
readValue(src, constructType[T])
203209
}
204210

205-
def readValue[T: Manifest](content: String): T = {
211+
def readValue[T: JavaTypeable](content: String): T = {
206212
readValue(content, constructType[T])
207213
}
208214

209-
def readValue[T: Manifest](src: Reader): T = {
215+
def readValue[T: JavaTypeable](src: Reader): T = {
210216
readValue(src, constructType[T])
211217
}
212218

213-
def readValue[T: Manifest](src: InputStream): T = {
219+
def readValue[T: JavaTypeable](src: InputStream): T = {
214220
readValue(src, constructType[T])
215221
}
216222

217-
def readValue[T: Manifest](src: Array[Byte]): T = {
223+
def readValue[T: JavaTypeable](src: Array[Byte]): T = {
218224
readValue(src, constructType[T])
219225
}
220226

221-
def readValue[T: Manifest](src: Array[Byte], offset: Int, len: Int): T = {
227+
def readValue[T: JavaTypeable](src: Array[Byte], offset: Int, len: Int): T = {
222228
readValue(src, offset, len, constructType[T])
223229
}
224230

225-
def updateValue[T: Manifest](valueToUpdate: T, src: File): T = {
231+
def updateValue[T: JavaTypeable](valueToUpdate: T, src: File): T = {
226232
objectReaderFor(valueToUpdate).readValue(src)
227233
}
228234

229-
def updateValue[T: Manifest](valueToUpdate: T, src: URL): T = {
235+
def updateValue[T: JavaTypeable](valueToUpdate: T, src: URL): T = {
230236
objectReaderFor(valueToUpdate).readValue(src)
231237
}
232238

233-
def updateValue[T: Manifest](valueToUpdate: T, content: String): T = {
239+
def updateValue[T: JavaTypeable](valueToUpdate: T, content: String): T = {
234240
objectReaderFor(valueToUpdate).readValue(content)
235241
}
236242

237-
def updateValue[T: Manifest](valueToUpdate: T, src: Reader): T = {
243+
def updateValue[T: JavaTypeable](valueToUpdate: T, src: Reader): T = {
238244
objectReaderFor(valueToUpdate).readValue(src)
239245
}
240246

241-
def updateValue[T: Manifest](valueToUpdate: T, src: InputStream): T = {
247+
def updateValue[T: JavaTypeable](valueToUpdate: T, src: InputStream): T = {
242248
objectReaderFor(valueToUpdate).readValue(src)
243249
}
244250

245-
def updateValue[T: Manifest](valueToUpdate: T, src: Array[Byte]): T = {
251+
def updateValue[T: JavaTypeable](valueToUpdate: T, src: Array[Byte]): T = {
246252
objectReaderFor(valueToUpdate).readValue(src)
247253
}
248254

249-
def updateValue[T: Manifest](valueToUpdate: T, src: Array[Byte], offset: Int, len: Int): T = {
255+
def updateValue[T: JavaTypeable](valueToUpdate: T, src: Array[Byte], offset: Int, len: Int): T = {
250256
objectReaderFor(valueToUpdate).readValue(src, offset, len)
251257
}
252258

253-
private def objectReaderFor[T: Manifest](valueToUpdate: T): ObjectReader = {
259+
private def objectReaderFor[T: JavaTypeable](valueToUpdate: T): ObjectReader = {
254260
readerForUpdating(valueToUpdate).forType(constructType[T])
255261
}
256262

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

272278
/**
@@ -288,7 +294,7 @@ trait ScalaObjectMapper {
288294
*
289295
* @since 2.5
290296
*/
291-
def writerFor[T: Manifest]: ObjectWriter = {
297+
def writerFor[T: JavaTypeable]: ObjectWriter = {
292298
writerFor(constructType[T])
293299
}
294300

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

319325
/**
320326
* Factory method for constructing [[com.fasterxml.jackson.databind.ObjectReader]] that will
321327
* deserialize objects using specified JSON View (filter).
322328
*/
323-
def readerWithView[T: Manifest]: ObjectReader = {
324-
readerWithView(manifest[T].runtimeClass)
329+
def readerWithView[T: ClassTag]: ObjectReader = {
330+
readerWithView(classTag[T].runtimeClass)
325331
}
326332

327333
/*
@@ -342,7 +348,7 @@ trait ScalaObjectMapper {
342348
* if so, root cause will contain underlying checked exception data binding
343349
* functionality threw
344350
*/
345-
def convertValue[T: Manifest](fromValue: Any): T = {
351+
def convertValue[T: JavaTypeable](fromValue: Any): T = {
346352
convertValue(fromValue, constructType[T])
347353
}
348354

@@ -375,26 +381,109 @@ trait ScalaObjectMapper {
375381
*
376382
* @since 2.1
377383
*/
378-
def acceptJsonFormatVisitor[T: Manifest](visitor: JsonFormatVisitorWrapper): Unit = {
379-
acceptJsonFormatVisitor(manifest[T].runtimeClass, visitor)
384+
def acceptJsonFormatVisitor[T: ClassTag](visitor: JsonFormatVisitorWrapper): Unit = {
385+
acceptJsonFormatVisitor(classTag[T].runtimeClass, visitor)
380386
}
381387

382-
private def isArray(c: Class[_]): Boolean = {
383-
c.isArray
388+
}
389+
390+
trait JavaTypeable[T] {
391+
def asJavaType(typeFactory: TypeFactory): JavaType
392+
}
393+
394+
object JavaTypeable {
395+
396+
implicit val anyJavaTypeable: JavaTypeable[Any] = {
397+
new JavaTypeable[Any] {
398+
override def asJavaType(typeFactory: TypeFactory): JavaType = {
399+
val typeArgs: Array[JavaType] = Array()
400+
typeFactory.constructParametricType(classOf[Object], typeArgs: _*)
401+
}
402+
}
384403
}
385404

386-
private val MAP = classOf[collection.Map[_,_]]
387-
private def isMapLike(c: Class[_]): Boolean = {
388-
MAP.isAssignableFrom(c)
405+
implicit def optionJavaTypeable[T : JavaTypeable]: JavaTypeable[Option[T]] = {
406+
new JavaTypeable[Option[T]] {
407+
override def asJavaType(typeFactory: TypeFactory): JavaType = {
408+
val typeArg0 = implicitly[JavaTypeable[T]].asJavaType(typeFactory)
409+
typeFactory.constructReferenceType(classOf[Option[_]], typeArg0)
410+
}
411+
}
389412
}
390413

391-
private val OPTION = classOf[Option[_]]
392-
private def isReference(c: Class[_]): Boolean = {
393-
OPTION.isAssignableFrom(c)
414+
implicit def arrayJavaTypeable[T : JavaTypeable]: JavaTypeable[Array[T]] = {
415+
new JavaTypeable[Array[T]] {
416+
override def asJavaType(typeFactory: TypeFactory): JavaType = {
417+
val typeArg0 = implicitly[JavaTypeable[T]].asJavaType(typeFactory)
418+
typeFactory.constructArrayType(typeArg0)
419+
}
420+
}
394421
}
395422

396-
private val ITERABLE = classOf[collection.Iterable[_]]
397-
private def isCollectionLike(c: Class[_]): Boolean = {
398-
ITERABLE.isAssignableFrom(c)
423+
implicit def mapJavaTypeable[M[_,_] <: Map[_,_], K : JavaTypeable, V: JavaTypeable](implicit ct: ClassTag[M[K,V]]): JavaTypeable[M[K, V]] = {
424+
new JavaTypeable[M[K, V]] {
425+
override def asJavaType(typeFactory: TypeFactory): JavaType = {
426+
val typeArg0 = implicitly[JavaTypeable[K]].asJavaType(typeFactory)
427+
val typeArg1 = implicitly[JavaTypeable[V]].asJavaType(typeFactory)
428+
typeFactory.constructMapLikeType(ct.runtimeClass, typeArg0, typeArg1)
429+
}
430+
}
431+
}
432+
433+
implicit def collectionJavaTypeable[I[_] <: Iterable[_], T : JavaTypeable](implicit ct: ClassTag[I[T]]): JavaTypeable[I[T]] = {
434+
new JavaTypeable[I[T]] {
435+
override def asJavaType(typeFactory: TypeFactory): JavaType = {
436+
val typeArg0 = implicitly[JavaTypeable[T]].asJavaType(typeFactory)
437+
typeFactory.constructCollectionLikeType(ct.runtimeClass, typeArg0)
438+
}
439+
}
399440
}
441+
442+
// TODO generate genX for X up to a large enough number, 10? 22?
443+
444+
implicit def gen3JavaTypeable[T[_, _, _], A: JavaTypeable, B: JavaTypeable, C: JavaTypeable](implicit ct: ClassTag[T[A, B, C]]): JavaTypeable[T[A, B, C]] = {
445+
new JavaTypeable[T[A, B, C]] {
446+
override def asJavaType(typeFactory: TypeFactory): JavaType = {
447+
val typeArgs: Array[JavaType] = Array(
448+
implicitly[JavaTypeable[A]].asJavaType(typeFactory),
449+
implicitly[JavaTypeable[B]].asJavaType(typeFactory),
450+
implicitly[JavaTypeable[C]].asJavaType(typeFactory)
451+
)
452+
typeFactory.constructParametricType(ct.runtimeClass, typeArgs: _*)
453+
}
454+
}
455+
}
456+
457+
implicit def gen2JavaTypeable[T[_, _], A: JavaTypeable, B: JavaTypeable](implicit ct: ClassTag[T[A, B]]): JavaTypeable[T[A, B]] = {
458+
new JavaTypeable[T[A, B]] {
459+
override def asJavaType(typeFactory: TypeFactory): JavaType = {
460+
val typeArgs: Array[JavaType] = Array(
461+
implicitly[JavaTypeable[A]].asJavaType(typeFactory),
462+
implicitly[JavaTypeable[B]].asJavaType(typeFactory)
463+
)
464+
typeFactory.constructParametricType(ct.runtimeClass, typeArgs: _*)
465+
}
466+
}
467+
}
468+
469+
implicit def gen1JavaTypeable[T[_], A: JavaTypeable](implicit ct: ClassTag[T[A]]): JavaTypeable[T[A]] = {
470+
new JavaTypeable[T[A]] {
471+
override def asJavaType(typeFactory: TypeFactory): JavaType = {
472+
val typeArgs: Array[JavaType] = Array(
473+
implicitly[JavaTypeable[A]].asJavaType(typeFactory)
474+
)
475+
typeFactory.constructParametricType(ct.runtimeClass, typeArgs: _*)
476+
}
477+
}
478+
}
479+
480+
implicit def gen0JavaTypeable[T](implicit ct: ClassTag[T]): JavaTypeable[T] = {
481+
new JavaTypeable[T] {
482+
override def asJavaType(typeFactory: TypeFactory): JavaType = {
483+
val typeArgs: Array[JavaType] = Array()
484+
typeFactory.constructParametricType(ct.runtimeClass, typeArgs: _*)
485+
}
486+
}
487+
}
488+
400489
}

0 commit comments

Comments
 (0)