
skinny.json4s.JSONStringOps.scala Maven / Gradle / Ivy
package skinny.json4s
import com.fasterxml.jackson.databind.{ DeserializationFeature, ObjectMapper, ObjectWriter }
import org.json4s._
import org.json4s.jackson.Json4sScalaModule
import scala.util.Try
/**
* Easy-to-use JSON String Operation.
*/
trait JSONStringOps {
/**
* Use the prefix for JSON Vulnerability Protection.
* see: "https://docs.angularjs.org/api/ng/service/$http"
*/
protected def useJSONVulnerabilityProtection: Boolean = false
/**
* the prefix for JSON Vulnerability Protection.
* see: "https://docs.angularjs.org/api/ng/service/$http"
*/
protected def prefixForJSONVulnerabilityProtection: String = ")]}',\n"
/**
* Default key policy.
*/
protected def useUnderscoreKeysForJSON: Boolean = true
/**
* JSON format support implicitly.
*/
protected implicit val jsonFormats: Formats = DefaultFormats ++ org.json4s.ext.JodaTimeSerializers.all
// -------------------------------
// Avoid extending org.json4s.jackson.JsonMethods due to #render method conflict
// -------------------------------
private[this] lazy val _defaultMapper = {
val m = new ObjectMapper()
m.registerModule(new Json4sScalaModule)
m
}
private[this] def mapper = _defaultMapper
def defaultObjectMapper: ObjectMapper = mapper
private[this] def parse(in: JsonInput, useBigDecimalForDouble: Boolean = false): JValue = {
mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, useBigDecimalForDouble)
in match {
case StringInput(s) => mapper.readValue(s, classOf[JValue])
case ReaderInput(rdr) => mapper.readValue(rdr, classOf[JValue])
case StreamInput(stream) => mapper.readValue(stream, classOf[JValue])
case FileInput(file) => mapper.readValue(file, classOf[JValue])
}
}
private[this] def tryParsing(in: JsonInput, useBigDecimalForDouble: Boolean = false): Try[JValue] = Try {
parse(in, useBigDecimalForDouble)
}
private[this] def pretty(d: JValue): String = {
val writer: ObjectWriter = mapper.writerWithDefaultPrettyPrinter()
writer.writeValueAsString(d)
}
def asJValue[T](obj: T)(implicit writer: Writer[T]): JValue = writer.write(obj)
def fromJValue[T](json: JValue)(implicit reader: Reader[T]): T = reader.read(json)
/**
* Returns JSON string value.
*
* @param value value
*/
def compact(value: JValue): String = {
val json = mapper.writeValueAsString(value)
if (useJSONVulnerabilityProtection) prefixForJSONVulnerabilityProtection + json
else json
}
/**
* Converts a value to JSON value.
*
* @param v value
* @return JValue
*/
def toJSON(v: Any): JValue = Extraction.decompose(v)
/**
* Converts a value to JSON string.
*
* @param v value
* @param underscoreKeys apply #underscoreKeys keys if true
* @return json string
*/
def toJSONString(v: Any, underscoreKeys: Boolean = useUnderscoreKeysForJSON): String = {
if (underscoreKeys) compact(parse(compact(toJSON(v))).underscoreKeys)
else compact(toJSON(v))
}
/**
* Converts a value to JSON string without key conversions.
*
* @param v value
* @return json string
*/
def toJSONStringAsIs(v: Any): String = toJSONString(v, false)
/**
* Converts a value to prettified JSON string.
*
* @param v value
* @param underscoreKeys apply #underscoreKeys keys if true
* @return json string
*/
def toPrettyJSONString(v: Any, underscoreKeys: Boolean = useUnderscoreKeysForJSON): String = {
if (underscoreKeys) pretty(parse(compact(toJSON(v))).underscoreKeys)
else pretty(toJSON(v))
}
/**
* Converts a value to prettified JSON string without key conversions.
*
* @param v value
* @return json string
*/
def toPrettyJSONStringAsIs(v: Any): String = toPrettyJSONString(v, false)
/**
* Extracts a value from JSON string.
* NOTE: When you convert to Map objects, be aware that underscoreKeys is false by default.
*
* @param json json string
* @param underscoreKeys apply #underscoreKeys keys if true
* @param asIs never apply key conversions if true
* @tparam A return type
* @return value
*/
def fromJSONString[A](json: String, underscoreKeys: Boolean = false, asIs: Boolean = false)(implicit mf: Manifest[A]): Try[A] = {
fromJSONStringToJValue(json, underscoreKeys, asIs).map[A](_.extract[A])
}
/**
* Extracts a value from JSON string. The keys will be used as-is.
*
* {{{
* case class Something(fooBar_baz: String)
* val something = new Something("foo")
* val json = toJSONString(something)
* val something2 = fromJSONStringAsIs[Something](json)
* something2.map(_.fooBar_baz) should equal(Some(something.fooBar_Baz))
* }}}
*
* @param json json string
* @param mf manifest
* @tparam A return type
* @return value
*/
def fromJSONStringAsIs[A](json: String)(implicit mf: Manifest[A]): Try[A] = fromJSONString(json, false, true)
/**
* Extracts a JSON value from JSON string.
* NOTE: When you convert to Map objects, be aware that underscoreKeys is false by default.
*
* @param json json string
* @param underscoreKeys underscore keys
* @return value
*/
def fromJSONStringToJValue(json: String, underscoreKeys: Boolean = false, asIs: Boolean = false): Try[JValue] = {
val pureJson = if (useJSONVulnerabilityProtection &&
json.startsWith(prefixForJSONVulnerabilityProtection)) {
json.replace(prefixForJSONVulnerabilityProtection, "")
} else {
json
}
tryParsing(StringInput(pureJson)).map { v =>
if (asIs) v
else if (underscoreKeys) v.underscoreKeys
else v.camelizeKeys
}
}
}
object JSONStringOps
extends JSONStringOps
© 2015 - 2025 Weber Informatics LLC | Privacy Policy