diff --git a/README.md b/README.md index 9c313e698..6900972cf 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,30 @@ myMemberWithType = mapper.readValue(json) All inferred types for the extension functions carry in full generic information (reified generics). Therefore, using `readValue()` extension without the `Class` parameter will reify the type and automatically create a `TypeReference` for Jackson. +Also, there are some convenient operator overloading extension functions for JsonNode inheritors. +```kotlin +import com.fasterxml.jackson.databind.node.ArrayNode +import com.fasterxml.jackson.databind.node.ObjectNode +import com.fasterxml.jackson.databind.node.JsonNodeFactory +import com.fasterxml.jackson.module.kotlin.* + +// ... +val objectNode: ObjectNode = JsonNodeFactory.instance.objectNode() +objectNode.put("foo1", "bar").put("foo2", "baz").put("foo3", "bax") +objectNode -= "foo1" +objectNode -= listOf("foo2") +println(objectNode.toString()) // {"foo3":"bax"} + +// ... +val arrayNode: ArrayNode = JsonNodeFactory.instance.arrayNode() +arrayNode += "foo" +arrayNode += true +arrayNode += 1 +arrayNode += 1.0 +arrayNode += "bar".toByteArray() +println(arrayNode.toString()) // ["foo",true,1,1.0,"YmFy"] +``` + # Annotations You can intermix non-field values in the constructor and `JsonProperty` annotation in the constructor. diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/Extensions.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/Extensions.kt index 4caf3b3be..9d5ab1986 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/Extensions.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/Extensions.kt @@ -3,17 +3,16 @@ package com.fasterxml.jackson.module.kotlin import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.core.TreeNode import com.fasterxml.jackson.core.type.TypeReference -import com.fasterxml.jackson.databind.JsonMappingException -import com.fasterxml.jackson.databind.MappingIterator -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.ObjectReader -import com.fasterxml.jackson.databind.module.SimpleModule -import com.fasterxml.jackson.databind.JsonDeserializer -import com.fasterxml.jackson.databind.JsonSerializer +import com.fasterxml.jackson.databind.* import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.node.ArrayNode +import com.fasterxml.jackson.databind.node.ObjectNode import java.io.File import java.io.InputStream import java.io.Reader +import java.math.BigDecimal +import java.math.BigInteger import java.net.URL import java.util.* import kotlin.reflect.KClass @@ -54,6 +53,41 @@ inline fun ObjectReader.readValueTyped(jp: JsonParser): T = readValu inline fun ObjectReader.readValuesTyped(jp: JsonParser): Iterator = readValues(jp, jacksonTypeRef()) inline fun ObjectReader.treeToValue(n: TreeNode): T? = treeToValue(n, T::class.java) +operator fun ArrayNode.plus(element: Boolean) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: Short) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: Int) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: Long) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: Float) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: Double) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: BigDecimal) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: BigInteger) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: String) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: ByteArray) = Unit.apply { add(element) } +operator fun ArrayNode.plus(element: JsonNode) = Unit.apply { add(element) } +operator fun ArrayNode.plus(elements: ArrayNode) = Unit.apply { addAll(elements) } +operator fun ArrayNode.plusAssign(element: Boolean) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: Short) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: Int) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: Long) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: Float) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: Double) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: BigDecimal) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: BigInteger) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: String) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: ByteArray) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(element: JsonNode) = Unit.apply { add(element) } +operator fun ArrayNode.plusAssign(elements: ArrayNode) = Unit.apply { addAll(elements) } +operator fun ArrayNode.minus(index: Int) = Unit.apply { remove(index) } +operator fun ArrayNode.minusAssign(index: Int) = Unit.apply { remove(index) } + +operator fun ObjectNode.minus(field: String) = Unit.apply { remove(field) } +operator fun ObjectNode.minus(fields: Collection) = Unit.apply { remove(fields) } +operator fun ObjectNode.minusAssign(field: String) = Unit.apply { remove(field) } +operator fun ObjectNode.minusAssign(fields: Collection) = Unit.apply { remove(fields) } + +operator fun JsonNode.contains(field: String) = has(field) +operator fun JsonNode.contains(index: Int) = has(index) + internal fun JsonMappingException.wrapWithPath(refFrom: Any?, refFieldName: String) = JsonMappingException.wrapWithPath(this, refFrom, refFieldName) internal fun JsonMappingException.wrapWithPath(refFrom: Any?, index: Int) = JsonMappingException.wrapWithPath(this, refFrom, index) diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ExtensionMethodsTests.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ExtensionMethodsTests.kt index a5cb3c53c..963e86cb1 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ExtensionMethodsTests.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/ExtensionMethodsTests.kt @@ -2,7 +2,9 @@ package com.fasterxml.jackson.module.kotlin.test import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.databind.node.JsonNodeFactory import com.fasterxml.jackson.module.kotlin.* +import org.hamcrest.CoreMatchers.`is` import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat import org.junit.Test @@ -33,4 +35,30 @@ class TestExtensionMethods { val myList: List = mapper.readValue(jsonStr) assertThat(myList, equalTo(listOf(MyData("value1", 1), MyData("value2", 2)))) } + + @Test fun testOperatorFunExtensions() { + val factory = JsonNodeFactory.instance + + val objectNode = factory.objectNode() + objectNode.put("foo1", "bar") + objectNode.put("foo2", "baz") + objectNode.put("foo3", "bah") + objectNode -= "foo1" + objectNode -= listOf("foo2") + + assertThat("foo1" !in objectNode, `is`(true)) + assertThat("foo3" in objectNode, `is`(true)) + + val arrayNode = factory.arrayNode() + arrayNode += "foo" + arrayNode += true + arrayNode += 1 + arrayNode += 1.0 + arrayNode += "bar".toByteArray() + + assertThat(arrayNode.size(), `is`(5)) + + (4 downTo 0).forEach { arrayNode -= it } + assertThat(arrayNode.size(), `is`(0)) + } } \ No newline at end of file