@@ -2,6 +2,7 @@ package com.fasterxml.jackson.module.scala
2
2
3
3
import com .fasterxml .jackson .core .{JsonParser , TreeNode }
4
4
import com .fasterxml .jackson .databind ._
5
+ import com .fasterxml .jackson .databind .`type` .TypeFactory
5
6
import com .fasterxml .jackson .databind .json .JsonMapper
6
7
7
8
import java .io .{File , InputStream , Reader }
@@ -20,11 +21,8 @@ object ClassTagExtensions {
20
21
}
21
22
22
23
/**
23
- * Experimental ClassTag equivalent of ScalaObjectMapper. This does not do a good job with
24
- * reference types that wrap primitives, eg Option[Int], Seq[Boolean].
25
- *
26
- * This is because ClassTags only provide access to the Java class and information
27
- * about the wrapped types is lost due to type erasure.
24
+ * Experimental ClassTag equivalent of ScalaObjectMapper.
25
+ * This only works with non parameterized types or parameterized types up to 5 type parameters.
28
26
*/
29
27
trait ClassTagExtensions {
30
28
self : ObjectMapper =>
@@ -35,6 +33,15 @@ trait ClassTagExtensions {
35
33
**********************************************************
36
34
*/
37
35
36
+ /**
37
+ * Convenience method for constructing [[com.fasterxml.jackson.databind.JavaType ]] out of given
38
+ * type (typically <code>java.lang.Class</code>), but without explicit
39
+ * context.
40
+ */
41
+ def constructType [T : JavaTypeable ]: JavaType = {
42
+ implicitly[JavaTypeable [T ]].asJavaType(getTypeFactory)
43
+ }
44
+
38
45
/*
39
46
**********************************************************
40
47
* Public API (from ObjectCodec): deserialization
@@ -50,8 +57,8 @@ trait ClassTagExtensions {
50
57
* and specifically needs to be used if the root type is a
51
58
* parameterized (generic) container type.
52
59
*/
53
- def readValue [T : ClassTag ](jp : JsonParser ): T = {
54
- readValue(jp, classFor [T ])
60
+ def readValue [T : JavaTypeable ](jp : JsonParser ): T = {
61
+ readValue(jp, constructType [T ])
55
62
}
56
63
57
64
/**
@@ -66,8 +73,8 @@ trait ClassTagExtensions {
66
73
* <p>
67
74
* Note that [[com.fasterxml.jackson.databind.ObjectReader ]] has more complete set of variants.
68
75
*/
69
- def readValues [T : ClassTag ](jp : JsonParser ): MappingIterator [T ] = {
70
- readValues(jp, classFor [T ])
76
+ def readValues [T : JavaTypeable ](jp : JsonParser ): MappingIterator [T ] = {
77
+ readValues(jp, constructType [T ])
71
78
}
72
79
73
80
/*
@@ -95,64 +102,64 @@ trait ClassTagExtensions {
95
102
* convenience methods
96
103
**********************************************************
97
104
*/
98
- def readValue [T : ClassTag ](src : File ): T = {
99
- readValue(src, classFor [T ])
105
+ def readValue [T : JavaTypeable ](src : File ): T = {
106
+ readValue(src, constructType [T ])
100
107
}
101
108
102
- def readValue [T : ClassTag ](src : URL ): T = {
103
- readValue(src, classFor [T ])
109
+ def readValue [T : JavaTypeable ](src : URL ): T = {
110
+ readValue(src, constructType [T ])
104
111
}
105
112
106
- def readValue [T : ClassTag ](content : String ): T = {
107
- readValue(content, classFor [T ])
113
+ def readValue [T : JavaTypeable ](content : String ): T = {
114
+ readValue(content, constructType [T ])
108
115
}
109
116
110
- def readValue [T : ClassTag ](src : Reader ): T = {
111
- readValue(src, classFor [T ])
117
+ def readValue [T : JavaTypeable ](src : Reader ): T = {
118
+ readValue(src, constructType [T ])
112
119
}
113
120
114
- def readValue [T : ClassTag ](src : InputStream ): T = {
115
- readValue(src, classFor [T ])
121
+ def readValue [T : JavaTypeable ](src : InputStream ): T = {
122
+ readValue(src, constructType [T ])
116
123
}
117
124
118
- def readValue [T : ClassTag ](src : Array [Byte ]): T = {
119
- readValue(src, classFor [T ])
125
+ def readValue [T : JavaTypeable ](src : Array [Byte ]): T = {
126
+ readValue(src, constructType [T ])
120
127
}
121
128
122
- def readValue [T : ClassTag ](src : Array [Byte ], offset : Int , len : Int ): T = {
123
- readValue(src, offset, len, classFor [T ])
129
+ def readValue [T : JavaTypeable ](src : Array [Byte ], offset : Int , len : Int ): T = {
130
+ readValue(src, offset, len, constructType [T ])
124
131
}
125
132
126
- def updateValue [T : ClassTag ](valueToUpdate : T , src : File ): T = {
133
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : File ): T = {
127
134
objectReaderFor(valueToUpdate).readValue(src)
128
135
}
129
136
130
- def updateValue [T : ClassTag ](valueToUpdate : T , src : URL ): T = {
137
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : URL ): T = {
131
138
objectReaderFor(valueToUpdate).readValue(src)
132
139
}
133
140
134
- def updateValue [T : ClassTag ](valueToUpdate : T , content : String ): T = {
141
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , content : String ): T = {
135
142
objectReaderFor(valueToUpdate).readValue(content)
136
143
}
137
144
138
- def updateValue [T : ClassTag ](valueToUpdate : T , src : Reader ): T = {
145
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : Reader ): T = {
139
146
objectReaderFor(valueToUpdate).readValue(src)
140
147
}
141
148
142
- def updateValue [T : ClassTag ](valueToUpdate : T , src : InputStream ): T = {
149
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : InputStream ): T = {
143
150
objectReaderFor(valueToUpdate).readValue(src)
144
151
}
145
152
146
- def updateValue [T : ClassTag ](valueToUpdate : T , src : Array [Byte ]): T = {
153
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : Array [Byte ]): T = {
147
154
objectReaderFor(valueToUpdate).readValue(src)
148
155
}
149
156
150
- def updateValue [T : ClassTag ](valueToUpdate : T , src : Array [Byte ], offset : Int , len : Int ): T = {
157
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : Array [Byte ], offset : Int , len : Int ): T = {
151
158
objectReaderFor(valueToUpdate).readValue(src, offset, len)
152
159
}
153
160
154
- private def objectReaderFor [T : ClassTag ](valueToUpdate : T ): ObjectReader = {
155
- readerForUpdating(valueToUpdate).forType(classFor [T ])
161
+ private def objectReaderFor [T : JavaTypeable ](valueToUpdate : T ): ObjectReader = {
162
+ readerForUpdating(valueToUpdate).forType(constructType [T ])
156
163
}
157
164
158
165
/*
@@ -181,8 +188,8 @@ trait ClassTagExtensions {
181
188
*
182
189
* @since 2.5
183
190
*/
184
- def writerFor [T : ClassTag ]: ObjectWriter = {
185
- writerFor(classFor [T ])
191
+ def writerFor [T : JavaTypeable ]: ObjectWriter = {
192
+ writerFor(constructType [T ])
186
193
}
187
194
188
195
/*
@@ -196,8 +203,8 @@ trait ClassTagExtensions {
196
203
* Factory method for constructing [[com.fasterxml.jackson.databind.ObjectReader ]] that will
197
204
* read or update instances of specified type
198
205
*/
199
- def readerFor [T : ClassTag ]: ObjectReader = {
200
- readerFor(classFor [T ])
206
+ def readerFor [T : JavaTypeable ]: ObjectReader = {
207
+ readerFor(constructType [T ])
201
208
}
202
209
203
210
/**
@@ -226,11 +233,139 @@ trait ClassTagExtensions {
226
233
* if so, root cause will contain underlying checked exception data binding
227
234
* functionality threw
228
235
*/
229
- def convertValue [T : ClassTag ](fromValue : Any ): T = {
230
- convertValue(fromValue, classFor [T ])
236
+ def convertValue [T : JavaTypeable ](fromValue : Any ): T = {
237
+ convertValue(fromValue, constructType [T ])
231
238
}
232
239
233
240
private def classFor [T : ClassTag ]: Class [T ] = {
234
241
implicitly[ClassTag [T ]].runtimeClass.asInstanceOf [Class [T ]]
235
242
}
236
243
}
244
+
245
+ trait JavaTypeable [T ] {
246
+ def asJavaType (typeFactory : TypeFactory ): JavaType
247
+ }
248
+
249
+ object JavaTypeable {
250
+
251
+ implicit val anyJavaTypeable : JavaTypeable [Any ] = {
252
+ new JavaTypeable [Any ] {
253
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
254
+ val typeArgs : Array [JavaType ] = Array ()
255
+ typeFactory.constructParametricType(classOf [Object ], typeArgs : _* )
256
+ }
257
+ }
258
+ }
259
+
260
+ implicit def optionJavaTypeable [T : JavaTypeable ]: JavaTypeable [Option [T ]] = {
261
+ new JavaTypeable [Option [T ]] {
262
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
263
+ val typeArg0 = implicitly[JavaTypeable [T ]].asJavaType(typeFactory)
264
+ typeFactory.constructReferenceType(classOf [Option [_]], typeArg0)
265
+ }
266
+ }
267
+ }
268
+
269
+ implicit def arrayJavaTypeable [T : JavaTypeable ]: JavaTypeable [Array [T ]] = {
270
+ new JavaTypeable [Array [T ]] {
271
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
272
+ val typeArg0 = implicitly[JavaTypeable [T ]].asJavaType(typeFactory)
273
+ typeFactory.constructArrayType(typeArg0)
274
+ }
275
+ }
276
+ }
277
+
278
+ implicit def mapJavaTypeable [M [_,_] <: Map [_,_], K : JavaTypeable , V : JavaTypeable ](implicit ct : ClassTag [M [K ,V ]]): JavaTypeable [M [K , V ]] = {
279
+ new JavaTypeable [M [K , V ]] {
280
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
281
+ val typeArg0 = implicitly[JavaTypeable [K ]].asJavaType(typeFactory)
282
+ val typeArg1 = implicitly[JavaTypeable [V ]].asJavaType(typeFactory)
283
+ typeFactory.constructMapLikeType(ct.runtimeClass, typeArg0, typeArg1)
284
+ }
285
+ }
286
+ }
287
+
288
+ implicit def collectionJavaTypeable [I [_] <: Iterable [_], T : JavaTypeable ](implicit ct : ClassTag [I [T ]]): JavaTypeable [I [T ]] = {
289
+ new JavaTypeable [I [T ]] {
290
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
291
+ val typeArg0 = implicitly[JavaTypeable [T ]].asJavaType(typeFactory)
292
+ typeFactory.constructCollectionLikeType(ct.runtimeClass, typeArg0)
293
+ }
294
+ }
295
+ }
296
+
297
+ implicit def gen5JavaTypeable [T [_, _, _, _, _], A : JavaTypeable , B : JavaTypeable , C : JavaTypeable , D : JavaTypeable , E : JavaTypeable ](implicit ct : ClassTag [T [A , B , C , D , E ]]): JavaTypeable [T [A , B , C , D , E ]] = {
298
+ new JavaTypeable [T [A , B , C , D , E ]] {
299
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
300
+ val typeArgs : Array [JavaType ] = Array (
301
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory),
302
+ implicitly[JavaTypeable [B ]].asJavaType(typeFactory),
303
+ implicitly[JavaTypeable [C ]].asJavaType(typeFactory),
304
+ implicitly[JavaTypeable [D ]].asJavaType(typeFactory),
305
+ implicitly[JavaTypeable [E ]].asJavaType(typeFactory)
306
+ )
307
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
308
+ }
309
+ }
310
+ }
311
+
312
+ implicit def gen4JavaTypeable [T [_, _, _, _], A : JavaTypeable , B : JavaTypeable , C : JavaTypeable , D : JavaTypeable ](implicit ct : ClassTag [T [A , B , C , D ]]): JavaTypeable [T [A , B , C , D ]] = {
313
+ new JavaTypeable [T [A , B , C , D ]] {
314
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
315
+ val typeArgs : Array [JavaType ] = Array (
316
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory),
317
+ implicitly[JavaTypeable [B ]].asJavaType(typeFactory),
318
+ implicitly[JavaTypeable [C ]].asJavaType(typeFactory),
319
+ implicitly[JavaTypeable [D ]].asJavaType(typeFactory)
320
+ )
321
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
322
+ }
323
+ }
324
+ }
325
+
326
+ implicit def gen3JavaTypeable [T [_, _, _], A : JavaTypeable , B : JavaTypeable , C : JavaTypeable ](implicit ct : ClassTag [T [A , B , C ]]): JavaTypeable [T [A , B , C ]] = {
327
+ new JavaTypeable [T [A , B , C ]] {
328
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
329
+ val typeArgs : Array [JavaType ] = Array (
330
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory),
331
+ implicitly[JavaTypeable [B ]].asJavaType(typeFactory),
332
+ implicitly[JavaTypeable [C ]].asJavaType(typeFactory)
333
+ )
334
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
335
+ }
336
+ }
337
+ }
338
+
339
+ implicit def gen2JavaTypeable [T [_, _], A : JavaTypeable , B : JavaTypeable ](implicit ct : ClassTag [T [A , B ]]): JavaTypeable [T [A , B ]] = {
340
+ new JavaTypeable [T [A , B ]] {
341
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
342
+ val typeArgs : Array [JavaType ] = Array (
343
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory),
344
+ implicitly[JavaTypeable [B ]].asJavaType(typeFactory)
345
+ )
346
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
347
+ }
348
+ }
349
+ }
350
+
351
+ implicit def gen1JavaTypeable [T [_], A : JavaTypeable ](implicit ct : ClassTag [T [A ]]): JavaTypeable [T [A ]] = {
352
+ new JavaTypeable [T [A ]] {
353
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
354
+ val typeArgs : Array [JavaType ] = Array (
355
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory)
356
+ )
357
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
358
+ }
359
+ }
360
+ }
361
+
362
+ implicit def gen0JavaTypeable [T ](implicit ct : ClassTag [T ]): JavaTypeable [T ] = {
363
+ new JavaTypeable [T ] {
364
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
365
+ val typeArgs : Array [JavaType ] = Array ()
366
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
367
+ }
368
+ }
369
+ }
370
+
371
+ }
0 commit comments