Skip to content

Instantly share code, notes, and snippets.

@gabrieljones
Created December 16, 2020 15:55
Show Gist options
  • Save gabrieljones/cd0d5104cf6f6573c51b56707063213b to your computer and use it in GitHub Desktop.
Save gabrieljones/cd0d5104cf6f6573c51b56707063213b to your computer and use it in GitHub Desktop.
setAt, removeAt, withAt, withArrayAt for Jackson ObjectNodes
import com.fasterxml.jackson.core.JsonPointer
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.node.{ArrayNode, MissingNode, ObjectNode}
object JacksonExtension {
implicit class ObjectNodeExtension(val objectNode: ObjectNode) extends AnyVal {
def removeAt(jsonPtrExpr : String): JsonNode = removeAt(JsonPointer.compile(jsonPtrExpr))
def removeAt(ptr: JsonPointer): JsonNode = {
(objectNode.at(ptr), objectNode.at(ptr.head)) match {
case (missing: MissingNode, _) =>
missing
case (node, objectParent: ObjectNode) =>
objectParent.remove(ptr.last.getMatchingProperty)
node
case (node, arrayParent: ArrayNode) =>
arrayParent.remove(ptr.last.getMatchingIndex)
node
case (node, _) =>
node
}
}
def withAt(jsonPtrExpr : String): JsonNode = withAt(JsonPointer.compile(jsonPtrExpr))
def withAt(ptr: JsonPointer): JsonNode = {
(objectNode.at(ptr.head), ptr.last) match {
case (objectParent: ObjectNode, leaf) if leaf.mayMatchProperty() =>
objectParent.`with`(ptr.last.getMatchingProperty)
case (arrayParent: ArrayNode, leaf) if leaf.mayMatchElement() =>
throw new UnsupportedOperationException(s"Property `${ptr.head}` is an ArrayNode which is not currently supported, but could be, need to figure out padding")
case (missingParent: MissingNode, leaf) =>
withAt(ptr.head()) // recursively materialize parent
withAt(ptr) //try again
case (otherParent, leaf) =>
throw new UnsupportedOperationException(s"Property '${ptr.toString}' has value that is not of type ObjectNode (but ${otherParent.getClass.getName})")
}
}
def withArrayAt(jsonPtrExpr : String): JsonNode = withArrayAt(JsonPointer.compile(jsonPtrExpr))
def withArrayAt(ptr: JsonPointer): JsonNode = {
(objectNode.at(ptr.head), ptr.last) match {
case (objectParent: ObjectNode, leaf) if leaf.mayMatchProperty() =>
objectParent.withArray(ptr.last.getMatchingProperty)
case (arrayParent: ArrayNode, leaf) if leaf.mayMatchElement() =>
throw new UnsupportedOperationException(s"Property `${ptr.head}` is an ArrayNode which is not currently supported, but could be, need to figure out padding")
case (missingParent: MissingNode, leaf) =>
withArrayAt(ptr.head()) // recursively materialize parent
withArrayAt(ptr) //try again
case (otherParent, leaf) =>
throw new UnsupportedOperationException(s"Property '${ptr.toString}' has value that is not of type ObjectNode or ArrayNode (but ${otherParent.getClass.getName})")
}
}
def setAt(jsonPtrExpr : String, value: JsonNode): JsonNode = setAt(JsonPointer.compile(jsonPtrExpr), value)
def setAt(ptr: JsonPointer, value: JsonNode): JsonNode = {
(objectNode.at(ptr.head), ptr.last) match {
case (objectParent: ObjectNode, leaf) if leaf.mayMatchProperty() =>
objectParent.set(ptr.last.getMatchingProperty, value)
case (arrayParent: ArrayNode, leaf) if leaf.mayMatchElement() =>
arrayParent.set(leaf.getMatchingIndex, value)
case (missingParent: MissingNode, leaf) if leaf.mayMatchProperty() =>
withAt(ptr.head()) // recursively materialize parent
setAt(ptr, value) //try again
case (missingParent: MissingNode, leaf) if leaf.mayMatchElement() =>
withArrayAt(ptr.head()) // recursively materialize parent
setAt(ptr, value) //try again
case (otherParent, leaf) if leaf.mayMatchElement() =>
throw new UnsupportedOperationException(s"Property '${ptr.head.toString}' has value that is not of type ObjectNode or ArrayNode (but ${otherParent.getClass.getName})")
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment