@@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.JsonSerializer
9
9
import com.fasterxml.jackson.databind.MappingIterator
10
10
import com.fasterxml.jackson.databind.ObjectMapper
11
11
import com.fasterxml.jackson.databind.ObjectReader
12
+ import com.fasterxml.jackson.databind.RuntimeJsonMappingException
12
13
import com.fasterxml.jackson.databind.json.JsonMapper
13
14
import com.fasterxml.jackson.databind.module.SimpleModule
14
15
import com.fasterxml.jackson.databind.node.ArrayNode
@@ -50,21 +51,132 @@ fun ObjectMapper.registerKotlinModule(initializer: KotlinModule.Builder.() -> Un
50
51
51
52
inline fun <reified T > jacksonTypeRef (): TypeReference <T > = object : TypeReference <T >() {}
52
53
54
+ /* *
55
+ * It is public due to Kotlin restrictions, but should not be used externally.
56
+ */
57
+ inline fun <reified T > Any?.checkTypeMismatch (): T {
58
+ // Basically, this check assumes that T is non-null and the value is null.
59
+ // Since this can be caused by both input or ObjectMapper implementation errors,
60
+ // a more abstract RuntimeJsonMappingException is thrown.
61
+ if (this !is T ) {
62
+ val nullability = if (null is T ) " ?" else " (non-null)"
63
+
64
+ // Since the databind implementation of MappingIterator throws RuntimeJsonMappingException,
65
+ // JsonMappingException was not used to unify the behavior.
66
+ throw RuntimeJsonMappingException (
67
+ " Deserialized value did not match the specified type; " +
68
+ " specified ${T ::class .qualifiedName}${nullability} but was ${this ?.let { it::class .qualifiedName }} "
69
+ )
70
+ }
71
+ return this
72
+ }
73
+
74
+ /* *
75
+ * Shorthand for [ObjectMapper.readValue].
76
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
77
+ * Other cases where the read value is of a different type than [T]
78
+ * due to an incorrect customization to [ObjectMapper].
79
+ */
53
80
inline fun <reified T > ObjectMapper.readValue (jp : JsonParser ): T = readValue(jp, jacksonTypeRef<T >())
54
- inline fun <reified T > ObjectMapper.readValues (jp : JsonParser ): MappingIterator <T > = readValues(jp, jacksonTypeRef<T >())
81
+ .checkTypeMismatch()
82
+ /* *
83
+ * Shorthand for [ObjectMapper.readValues].
84
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
85
+ * Other cases where the read value is of a different type than [T]
86
+ * due to an incorrect customization to [ObjectMapper].
87
+ */
88
+ inline fun <reified T > ObjectMapper.readValues (jp : JsonParser ): MappingIterator <T > {
89
+ val values = readValues(jp, jacksonTypeRef<T >())
90
+
91
+ return object : MappingIterator <T >(values) {
92
+ override fun nextValue (): T = super .nextValue().checkTypeMismatch()
93
+ }
94
+ }
55
95
56
- inline fun <reified T > ObjectMapper.readValue (src : File ): T = readValue(src, jacksonTypeRef<T >())
57
- inline fun <reified T > ObjectMapper.readValue (src : URL ): T = readValue(src, jacksonTypeRef<T >())
96
+ /* *
97
+ * Shorthand for [ObjectMapper.readValue].
98
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
99
+ * Other cases where the read value is of a different type than [T]
100
+ * due to an incorrect customization to [ObjectMapper].
101
+ */
102
+ inline fun <reified T > ObjectMapper.readValue (src : File ): T = readValue(src, jacksonTypeRef<T >()).checkTypeMismatch()
103
+ /* *
104
+ * Shorthand for [ObjectMapper.readValue].
105
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
106
+ * Other cases where the read value is of a different type than [T]
107
+ * due to an incorrect customization to [ObjectMapper].
108
+ */
109
+ inline fun <reified T > ObjectMapper.readValue (src : URL ): T = readValue(src, jacksonTypeRef<T >()).checkTypeMismatch()
110
+ /* *
111
+ * Shorthand for [ObjectMapper.readValue].
112
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
113
+ * Other cases where the read value is of a different type than [T]
114
+ * due to an incorrect customization to [ObjectMapper].
115
+ */
58
116
inline fun <reified T > ObjectMapper.readValue (content : String ): T = readValue(content, jacksonTypeRef<T >())
59
- inline fun <reified T > ObjectMapper.readValue (src : Reader ): T = readValue(src, jacksonTypeRef<T >())
117
+ .checkTypeMismatch()
118
+ /* *
119
+ * Shorthand for [ObjectMapper.readValue].
120
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
121
+ * Other cases where the read value is of a different type than [T]
122
+ * due to an incorrect customization to [ObjectMapper].
123
+ */
124
+ inline fun <reified T > ObjectMapper.readValue (src : Reader ): T = readValue(src, jacksonTypeRef<T >()).checkTypeMismatch()
125
+ /* *
126
+ * Shorthand for [ObjectMapper.readValue].
127
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
128
+ * Other cases where the read value is of a different type than [T]
129
+ * due to an incorrect customization to [ObjectMapper].
130
+ */
60
131
inline fun <reified T > ObjectMapper.readValue (src : InputStream ): T = readValue(src, jacksonTypeRef<T >())
132
+ .checkTypeMismatch()
133
+ /* *
134
+ * Shorthand for [ObjectMapper.readValue].
135
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
136
+ * Other cases where the read value is of a different type than [T]
137
+ * due to an incorrect customization to [ObjectMapper].
138
+ */
61
139
inline fun <reified T > ObjectMapper.readValue (src : ByteArray ): T = readValue(src, jacksonTypeRef<T >())
62
-
140
+ .checkTypeMismatch()
141
+
142
+ /* *
143
+ * Shorthand for [ObjectMapper.readValue].
144
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
145
+ * Other cases where the read value is of a different type than [T]
146
+ * due to an incorrect customization to [ObjectMapper].
147
+ */
63
148
inline fun <reified T > ObjectMapper.treeToValue (n : TreeNode ): T = readValue(this .treeAsTokens(n), jacksonTypeRef<T >())
149
+ .checkTypeMismatch()
150
+ /* *
151
+ * Shorthand for [ObjectMapper.convertValue].
152
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
153
+ * Other cases where the read value is of a different type than [T]
154
+ * due to an incorrect customization to [ObjectMapper].
155
+ */
64
156
inline fun <reified T > ObjectMapper.convertValue (from : Any? ): T = convertValue(from, jacksonTypeRef<T >())
65
-
157
+ .checkTypeMismatch()
158
+
159
+ /* *
160
+ * Shorthand for [ObjectMapper.readValue].
161
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
162
+ * Other cases where the read value is of a different type than [T]
163
+ * due to an incorrect customization to [ObjectMapper].
164
+ */
66
165
inline fun <reified T > ObjectReader.readValueTyped (jp : JsonParser ): T = readValue(jp, jacksonTypeRef<T >())
67
- inline fun <reified T > ObjectReader.readValuesTyped (jp : JsonParser ): Iterator <T > = readValues(jp, jacksonTypeRef<T >())
166
+ .checkTypeMismatch()
167
+ /* *
168
+ * Shorthand for [ObjectMapper.readValues].
169
+ * @throws RuntimeJsonMappingException Especially if [T] is non-null and the value read is null.
170
+ * Other cases where the read value is of a different type than [T]
171
+ * due to an incorrect customization to [ObjectMapper].
172
+ */
173
+ inline fun <reified T > ObjectReader.readValuesTyped (jp : JsonParser ): Iterator <T > {
174
+ val values = readValues(jp, jacksonTypeRef<T >())
175
+
176
+ return object : Iterator <T > by values {
177
+ override fun next (): T = values.next().checkTypeMismatch<T >()
178
+ }
179
+ }
68
180
inline fun <reified T > ObjectReader.treeToValue (n : TreeNode ): T ? = readValue(this .treeAsTokens(n), jacksonTypeRef<T >())
69
181
70
182
inline fun <reified T , reified U > ObjectMapper.addMixIn (): ObjectMapper = this .addMixIn(T ::class .java, U ::class .java)
0 commit comments