@@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.JsonSerializer
99import com.fasterxml.jackson.databind.MappingIterator
1010import com.fasterxml.jackson.databind.ObjectMapper
1111import com.fasterxml.jackson.databind.ObjectReader
12+ import com.fasterxml.jackson.databind.RuntimeJsonMappingException
1213import com.fasterxml.jackson.databind.json.JsonMapper
1314import com.fasterxml.jackson.databind.module.SimpleModule
1415import com.fasterxml.jackson.databind.node.ArrayNode
@@ -50,21 +51,132 @@ fun ObjectMapper.registerKotlinModule(initializer: KotlinModule.Builder.() -> Un
5051
5152inline fun <reified T > jacksonTypeRef (): TypeReference <T > = object : TypeReference <T >() {}
5253
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+ */
5380inline 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+ }
5595
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+ */
58116inline 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+ */
60131inline 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+ */
61139inline 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+ */
63148inline 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+ */
64156inline 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+ */
66165inline 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+ }
68180inline fun <reified T > ObjectReader.treeToValue (n : TreeNode ): T ? = readValue(this .treeAsTokens(n), jacksonTypeRef<T >())
69181
70182inline fun <reified T , reified U > ObjectMapper.addMixIn (): ObjectMapper = this .addMixIn(T ::class .java, U ::class .java)
0 commit comments