Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
scala: [ 2.12.14, 2.13.6 ]
scala: [ 2.12.15, 2.13.6 ]

steps:
- name: Checkout the Repository
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ lazy val orgSettings = Seq(

lazy val buildSettings = Seq(
scalaVersion := "2.13.6",
crossScalaVersions := Seq("2.12.14", "2.13.6")
crossScalaVersions := Seq("2.12.15", "2.13.6")
)

lazy val root =
Expand Down
1 change: 1 addition & 0 deletions doc/changes/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Releases

* [0.3.1](changes_0.3.1.md)
* [0.3.0](changes_0.3.0.md)
* [0.2.0](changes_0.2.0.md)
* [0.1.0](changes_0.1.0.md)
20 changes: 20 additions & 0 deletions doc/changes/changes_0.3.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Import Export UDF Common Scala 0.3.1, released 2021-10-14

Code name: Fixed JSON Mapper

## Summary

This release fixes parsing bugs in JSON mapper functionality.

## Bug Fixes

* #24: Fixed JSON mapper issues

## Dependency Updates

### Runtime Dependency Updates

### Test Dependency Updates

### Plugin Updates

1 change: 1 addition & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ object Dependencies {
exclude ("org.scala-lang", "scala-reflect"),
"org.apache.avro" % "avro" % AvroVersion
exclude ("org.slf4j", "slf4j-api")
exclude ("org.apache.commons", "commons-compress")
excludeAll (
ExclusionRule(organization = "com.fasterxml.jackson.core"),
ExclusionRule(organization = "com.fasterxml.jackson.module")
Expand Down
61 changes: 54 additions & 7 deletions src/main/scala/com/exasol/common/json/JsonMapper.scala
Original file line number Diff line number Diff line change
@@ -1,20 +1,67 @@
package com.exasol.common.json

import com.fasterxml.jackson.core.`type`.TypeReference
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.MapperFeature
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.json.{JsonMapper => BaseJsonMapper}
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.ClassTagExtensions

/**
* JSON parsing helper object class.
*/
object JsonMapper {

private[this] val mapper = BaseJsonMapper
.builder()
.addModule(DefaultScalaModule)
.build()
private[this] class ScalaJsonMapper(jsonMapper: BaseJsonMapper)
extends BaseJsonMapper(jsonMapper)
with ClassTagExtensions

private[this] val mapper = {
val builder = BaseJsonMapper
.builder()
.findAndAddModules()
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
.enable(JsonParser.Feature.ALLOW_COMMENTS)
.defaultMergeable(true)
new ScalaJsonMapper(builder.build())
}

/**
* Parses given value type into a JSON string.
*
* For parsing into pretty indented JSON use {@link toPrettyJson}.
*
* @param value a provided value type
* @return JSON string
*/
def toJson[T](value: T): String =
mapper.writeValueAsString(value)

/**
* Parses given value into pretty JSON format.
*
* @param value a provided value type
* @return pretty JSON string
*/
def toPrettyJson[T](value: T): String =
mapper.writer(SerializationFeature.INDENT_OUTPUT).writeValueAsString(value)

/**
* Parses JSON string into a type.
*
* @param jsonString a JSON string
* @return parsed value
*/
def fromJson[T: Manifest](jsonString: String): T =
mapper.readValue[T](jsonString)

/**
* Parses JSON string into a type.
*
* @param jsonString a JSON string
* @return parsed value
*/
@deprecated("Use fromJson method instead.", "0.3.1")
def parseJson[T: Manifest](jsonString: String): T =
mapper.readValue[T](jsonString, new TypeReference[T]() {})
fromJson(jsonString)

}
29 changes: 27 additions & 2 deletions src/test/scala/com/exasol/common/json/JsonMapperTest.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
package com.exasol.common.json

import java.util.LinkedHashMap

import com.fasterxml.jackson.databind.JsonNode

import org.scalatest.funsuite.AnyFunSuite

class JsonMapperTest extends AnyFunSuite {

test("parse to and from json to internal data type") {
test("parses to/from JSON to internal Scala data type") {
val jsonStr = """{"name":"John","age":30,"skills":["a","b","c"]}"""
val map = JsonMapper.parseJson[Map[String, Any]](jsonStr)
val map = JsonMapper.fromJson[Map[String, Any]](jsonStr)
assert(map.get("skills") === Option(Seq("a", "b", "c")))
assert(JsonMapper.toJson(map) === jsonStr)
}

test("parses to/from JSON to JsonNode") {
val jsonStr =
"""|{
| "number" : 1,
| "record" : {
| "field1" : "value1",
| "field2" : 23
| }
|}""".stripMargin
val jsonNode = JsonMapper.fromJson[JsonNode](jsonStr)
assert(JsonMapper.toPrettyJson(jsonNode) === jsonStr)
}

test("parses to/from JSON to Java LinkedHashMap") {
val jsonStr = """{"name":"John","age":"ten"}"""
val expected = new LinkedHashMap[String, String](java.util.Map.of("name", "John", "age", "ten"))
val parsedMap = JsonMapper.fromJson[LinkedHashMap[String, String]](jsonStr)
assert(parsedMap === expected)
assert(JsonMapper.toJson(parsedMap) === jsonStr)
}

}