@@ -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 }
@@ -15,11 +16,8 @@ object ClassTagExtensions {
15
16
}
16
17
17
18
/**
18
- * Experimental ClassTag equivalent of ScalaObjectMapper. This does not do a good job with
19
- * reference types that wrap primitives, eg Option[Int], Seq[Boolean].
20
- *
21
- * This is because ClassTags only provide access to the Java class and information
22
- * about the wrapped types is lost due to type erasure.
19
+ * Experimental ClassTag equivalent of ScalaObjectMapper.
20
+ * This only works with non parameterized types or parameterized types up to 5 type parameters.
23
21
*/
24
22
trait ClassTagExtensions {
25
23
self : ObjectMapper =>
@@ -56,6 +54,15 @@ trait ClassTagExtensions {
56
54
**********************************************************
57
55
*/
58
56
57
+ /**
58
+ * Convenience method for constructing [[com.fasterxml.jackson.databind.JavaType ]] out of given
59
+ * type (typically <code>java.lang.Class</code>), but without explicit
60
+ * context.
61
+ */
62
+ def constructType [T : JavaTypeable ]: JavaType = {
63
+ implicitly[JavaTypeable [T ]].asJavaType(getTypeFactory)
64
+ }
65
+
59
66
/*
60
67
**********************************************************
61
68
* Public API (from ObjectCodec): deserialization
@@ -71,8 +78,8 @@ trait ClassTagExtensions {
71
78
* and specifically needs to be used if the root type is a
72
79
* parameterized (generic) container type.
73
80
*/
74
- def readValue [T : ClassTag ](jp : JsonParser ): T = {
75
- readValue(jp, classFor [T ])
81
+ def readValue [T : JavaTypeable ](jp : JsonParser ): T = {
82
+ readValue(jp, constructType [T ])
76
83
}
77
84
78
85
/**
@@ -87,8 +94,8 @@ trait ClassTagExtensions {
87
94
* <p>
88
95
* Note that [[com.fasterxml.jackson.databind.ObjectReader ]] has more complete set of variants.
89
96
*/
90
- def readValues [T : ClassTag ](jp : JsonParser ): MappingIterator [T ] = {
91
- readValues(jp, classFor [T ])
97
+ def readValues [T : JavaTypeable ](jp : JsonParser ): MappingIterator [T ] = {
98
+ readValues(jp, constructType [T ])
92
99
}
93
100
94
101
/*
@@ -116,64 +123,64 @@ trait ClassTagExtensions {
116
123
* convenience methods
117
124
**********************************************************
118
125
*/
119
- def readValue [T : ClassTag ](src : File ): T = {
120
- readValue(src, classFor [T ])
126
+ def readValue [T : JavaTypeable ](src : File ): T = {
127
+ readValue(src, constructType [T ])
121
128
}
122
129
123
- def readValue [T : ClassTag ](src : URL ): T = {
124
- readValue(src, classFor [T ])
130
+ def readValue [T : JavaTypeable ](src : URL ): T = {
131
+ readValue(src, constructType [T ])
125
132
}
126
133
127
- def readValue [T : ClassTag ](content : String ): T = {
128
- readValue(content, classFor [T ])
134
+ def readValue [T : JavaTypeable ](content : String ): T = {
135
+ readValue(content, constructType [T ])
129
136
}
130
137
131
- def readValue [T : ClassTag ](src : Reader ): T = {
132
- readValue(src, classFor [T ])
138
+ def readValue [T : JavaTypeable ](src : Reader ): T = {
139
+ readValue(src, constructType [T ])
133
140
}
134
141
135
- def readValue [T : ClassTag ](src : InputStream ): T = {
136
- readValue(src, classFor [T ])
142
+ def readValue [T : JavaTypeable ](src : InputStream ): T = {
143
+ readValue(src, constructType [T ])
137
144
}
138
145
139
- def readValue [T : ClassTag ](src : Array [Byte ]): T = {
140
- readValue(src, classFor [T ])
146
+ def readValue [T : JavaTypeable ](src : Array [Byte ]): T = {
147
+ readValue(src, constructType [T ])
141
148
}
142
149
143
- def readValue [T : ClassTag ](src : Array [Byte ], offset : Int , len : Int ): T = {
144
- readValue(src, offset, len, classFor [T ])
150
+ def readValue [T : JavaTypeable ](src : Array [Byte ], offset : Int , len : Int ): T = {
151
+ readValue(src, offset, len, constructType [T ])
145
152
}
146
153
147
- def updateValue [T : ClassTag ](valueToUpdate : T , src : File ): T = {
154
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : File ): T = {
148
155
objectReaderFor(valueToUpdate).readValue(src)
149
156
}
150
157
151
- def updateValue [T : ClassTag ](valueToUpdate : T , src : URL ): T = {
158
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : URL ): T = {
152
159
objectReaderFor(valueToUpdate).readValue(src)
153
160
}
154
161
155
- def updateValue [T : ClassTag ](valueToUpdate : T , content : String ): T = {
162
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , content : String ): T = {
156
163
objectReaderFor(valueToUpdate).readValue(content)
157
164
}
158
165
159
- def updateValue [T : ClassTag ](valueToUpdate : T , src : Reader ): T = {
166
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : Reader ): T = {
160
167
objectReaderFor(valueToUpdate).readValue(src)
161
168
}
162
169
163
- def updateValue [T : ClassTag ](valueToUpdate : T , src : InputStream ): T = {
170
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : InputStream ): T = {
164
171
objectReaderFor(valueToUpdate).readValue(src)
165
172
}
166
173
167
- def updateValue [T : ClassTag ](valueToUpdate : T , src : Array [Byte ]): T = {
174
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : Array [Byte ]): T = {
168
175
objectReaderFor(valueToUpdate).readValue(src)
169
176
}
170
177
171
- def updateValue [T : ClassTag ](valueToUpdate : T , src : Array [Byte ], offset : Int , len : Int ): T = {
178
+ def updateValue [T : JavaTypeable ](valueToUpdate : T , src : Array [Byte ], offset : Int , len : Int ): T = {
172
179
objectReaderFor(valueToUpdate).readValue(src, offset, len)
173
180
}
174
181
175
- private def objectReaderFor [T : ClassTag ](valueToUpdate : T ): ObjectReader = {
176
- readerForUpdating(valueToUpdate).forType(classFor [T ])
182
+ private def objectReaderFor [T : JavaTypeable ](valueToUpdate : T ): ObjectReader = {
183
+ readerForUpdating(valueToUpdate).forType(constructType [T ])
177
184
}
178
185
179
186
/*
@@ -202,8 +209,8 @@ trait ClassTagExtensions {
202
209
*
203
210
* @since 2.5
204
211
*/
205
- def writerFor [T : ClassTag ]: ObjectWriter = {
206
- writerFor(classFor [T ])
212
+ def writerFor [T : JavaTypeable ]: ObjectWriter = {
213
+ writerFor(constructType [T ])
207
214
}
208
215
209
216
/*
@@ -217,8 +224,8 @@ trait ClassTagExtensions {
217
224
* Factory method for constructing [[com.fasterxml.jackson.databind.ObjectReader ]] that will
218
225
* read or update instances of specified type
219
226
*/
220
- def readerFor [T : ClassTag ]: ObjectReader = {
221
- readerFor(classFor [T ])
227
+ def readerFor [T : JavaTypeable ]: ObjectReader = {
228
+ readerFor(constructType [T ])
222
229
}
223
230
224
231
/**
@@ -247,11 +254,139 @@ trait ClassTagExtensions {
247
254
* if so, root cause will contain underlying checked exception data binding
248
255
* functionality threw
249
256
*/
250
- def convertValue [T : ClassTag ](fromValue : Any ): T = {
251
- convertValue(fromValue, classFor [T ])
257
+ def convertValue [T : JavaTypeable ](fromValue : Any ): T = {
258
+ convertValue(fromValue, constructType [T ])
252
259
}
253
260
254
261
private def classFor [T : ClassTag ]: Class [T ] = {
255
262
implicitly[ClassTag [T ]].runtimeClass.asInstanceOf [Class [T ]]
256
263
}
257
264
}
265
+
266
+ trait JavaTypeable [T ] {
267
+ def asJavaType (typeFactory : TypeFactory ): JavaType
268
+ }
269
+
270
+ object JavaTypeable {
271
+
272
+ implicit val anyJavaTypeable : JavaTypeable [Any ] = {
273
+ new JavaTypeable [Any ] {
274
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
275
+ val typeArgs : Array [JavaType ] = Array ()
276
+ typeFactory.constructParametricType(classOf [Object ], typeArgs : _* )
277
+ }
278
+ }
279
+ }
280
+
281
+ implicit def optionJavaTypeable [T : JavaTypeable ]: JavaTypeable [Option [T ]] = {
282
+ new JavaTypeable [Option [T ]] {
283
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
284
+ val typeArg0 = implicitly[JavaTypeable [T ]].asJavaType(typeFactory)
285
+ typeFactory.constructReferenceType(classOf [Option [_]], typeArg0)
286
+ }
287
+ }
288
+ }
289
+
290
+ implicit def arrayJavaTypeable [T : JavaTypeable ]: JavaTypeable [Array [T ]] = {
291
+ new JavaTypeable [Array [T ]] {
292
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
293
+ val typeArg0 = implicitly[JavaTypeable [T ]].asJavaType(typeFactory)
294
+ typeFactory.constructArrayType(typeArg0)
295
+ }
296
+ }
297
+ }
298
+
299
+ implicit def mapJavaTypeable [M [_,_] <: Map [_,_], K : JavaTypeable , V : JavaTypeable ](implicit ct : ClassTag [M [K ,V ]]): JavaTypeable [M [K , V ]] = {
300
+ new JavaTypeable [M [K , V ]] {
301
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
302
+ val typeArg0 = implicitly[JavaTypeable [K ]].asJavaType(typeFactory)
303
+ val typeArg1 = implicitly[JavaTypeable [V ]].asJavaType(typeFactory)
304
+ typeFactory.constructMapLikeType(ct.runtimeClass, typeArg0, typeArg1)
305
+ }
306
+ }
307
+ }
308
+
309
+ implicit def collectionJavaTypeable [I [_] <: Iterable [_], T : JavaTypeable ](implicit ct : ClassTag [I [T ]]): JavaTypeable [I [T ]] = {
310
+ new JavaTypeable [I [T ]] {
311
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
312
+ val typeArg0 = implicitly[JavaTypeable [T ]].asJavaType(typeFactory)
313
+ typeFactory.constructCollectionLikeType(ct.runtimeClass, typeArg0)
314
+ }
315
+ }
316
+ }
317
+
318
+ 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 ]] = {
319
+ new JavaTypeable [T [A , B , C , D , E ]] {
320
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
321
+ val typeArgs : Array [JavaType ] = Array (
322
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory),
323
+ implicitly[JavaTypeable [B ]].asJavaType(typeFactory),
324
+ implicitly[JavaTypeable [C ]].asJavaType(typeFactory),
325
+ implicitly[JavaTypeable [D ]].asJavaType(typeFactory),
326
+ implicitly[JavaTypeable [E ]].asJavaType(typeFactory)
327
+ )
328
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
329
+ }
330
+ }
331
+ }
332
+
333
+ 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 ]] = {
334
+ new JavaTypeable [T [A , B , C , D ]] {
335
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
336
+ val typeArgs : Array [JavaType ] = Array (
337
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory),
338
+ implicitly[JavaTypeable [B ]].asJavaType(typeFactory),
339
+ implicitly[JavaTypeable [C ]].asJavaType(typeFactory),
340
+ implicitly[JavaTypeable [D ]].asJavaType(typeFactory)
341
+ )
342
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
343
+ }
344
+ }
345
+ }
346
+
347
+ implicit def gen3JavaTypeable [T [_, _, _], A : JavaTypeable , B : JavaTypeable , C : JavaTypeable ](implicit ct : ClassTag [T [A , B , C ]]): JavaTypeable [T [A , B , C ]] = {
348
+ new JavaTypeable [T [A , B , C ]] {
349
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
350
+ val typeArgs : Array [JavaType ] = Array (
351
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory),
352
+ implicitly[JavaTypeable [B ]].asJavaType(typeFactory),
353
+ implicitly[JavaTypeable [C ]].asJavaType(typeFactory)
354
+ )
355
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
356
+ }
357
+ }
358
+ }
359
+
360
+ implicit def gen2JavaTypeable [T [_, _], A : JavaTypeable , B : JavaTypeable ](implicit ct : ClassTag [T [A , B ]]): JavaTypeable [T [A , B ]] = {
361
+ new JavaTypeable [T [A , B ]] {
362
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
363
+ val typeArgs : Array [JavaType ] = Array (
364
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory),
365
+ implicitly[JavaTypeable [B ]].asJavaType(typeFactory)
366
+ )
367
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
368
+ }
369
+ }
370
+ }
371
+
372
+ implicit def gen1JavaTypeable [T [_], A : JavaTypeable ](implicit ct : ClassTag [T [A ]]): JavaTypeable [T [A ]] = {
373
+ new JavaTypeable [T [A ]] {
374
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
375
+ val typeArgs : Array [JavaType ] = Array (
376
+ implicitly[JavaTypeable [A ]].asJavaType(typeFactory)
377
+ )
378
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
379
+ }
380
+ }
381
+ }
382
+
383
+ implicit def gen0JavaTypeable [T ](implicit ct : ClassTag [T ]): JavaTypeable [T ] = {
384
+ new JavaTypeable [T ] {
385
+ override def asJavaType (typeFactory : TypeFactory ): JavaType = {
386
+ val typeArgs : Array [JavaType ] = Array ()
387
+ typeFactory.constructParametricType(ct.runtimeClass, typeArgs : _* )
388
+ }
389
+ }
390
+ }
391
+
392
+ }
0 commit comments