Je veux lire un objet json dans une classe scala qui conserve une partie de l'objet json sous forme de chaîne sans essayer de l'analyser.

Voici à quoi ressemble le json:

[
  {
    "contractType": "NullContract",
    "contractDefinition": {
      "column": "age",
      "conditions": [
        {
          "conditionType": "equalsCondition",
          "conditionDefinition": {
            "column": "species",
            "value": "person"
          }
        }
      ]
    }
  }
]

J'utilise la bibliothèque jackson. Voici mon mappeur :

val mapper = new ObjectMapper()
    .registerModule(DefaultScalaModule)
    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    .setSerializationInclusion(Include.NON_ABSENT)

Voici ma classe:

case class ContractJson(contractType: String, contractDefinition: String)

, c'est à quoi je veux que mon objet résultant ressemble.

Voici le code qui l'analyse :

val contractJson: Array[ContractJson] = mapper.readValue(contractsJsonString, classOf[Array[ContractJson]])

Message d'erreur que je reçois : Can not deserialize instance of java.lang.String out of START_OBJECT token lorsqu'il commence à analyser le contractDefinition

1
user 25 oct. 2019 à 22:33

1 réponse

Meilleure réponse

Si vous êtes autorisé à utiliser d'autres bibliothèques et que le type de champ contractDefinition n'est pas limité à String, essayez fonctionnalité de jsoniter-scala d'extraction des valeurs JSON brutes en tableaux d'octets.

Vous devrez ajouter des dépendances :

libraryDependencies ++= Seq(
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core"   % "1.1.0" % Compile,
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "1.1.0" % Provided // required only in compile-time
)

Ensuite, définissez les types avec des codecs et analysez l'entrée :

import java.nio.charset.StandardCharsets.UTF_8

import com.github.plokhotnyuk.jsoniter_scala.macros._
import com.github.plokhotnyuk.jsoniter_scala.core._

import scala.util.hashing.MurmurHash3

object RawVal {
  def apply(s: String) = new RawVal(s.getBytes)

  implicit val codec: JsonValueCodec[RawVal] = new JsonValueCodec[RawVal] {
    override def decodeValue(in: JsonReader, default: RawVal): RawVal = new RawVal(in.readRawValAsBytes())

    override def encodeValue(x: RawVal, out: JsonWriter): Unit = out.writeRawVal(x.bs)

    override val nullValue: RawVal = new RawVal(new Array[Byte](0))
  }
}

case class RawVal private(bs: Array[Byte]) {
  def this(s: String) = this(s.getBytes(UTF_8))

  override lazy val hashCode: Int = MurmurHash3.arrayHash(bs)

  override def equals(obj: Any): Boolean = obj match {
    case that: RawVal => java.util.Arrays.equals(bs, that.bs)
    case _ => false
  }

  override def toString: String = new String(bs, UTF_8)
}

case class ContractJson(contractType: String, contractDefinition: RawVal)

implicit val codec: JsonValueCodec[List[ContractJson]] = JsonCodecMaker.make(CodecMakerConfig)

val jsonBytes =
  """[
    |  {
    |    "contractType": "NullContract",
    |    "contractDefinition": {
    |      "column": "age",
    |      "conditions": [
    |        {
    |          "conditionType": "equalsCondition",
    |          "conditionDefinition": {
    |            "column": "species",
    |            "value": "person"
    |          }
    |        }
    |      ]
    |    }
    |  }
    |]
    |""".stripMargin.getBytes("UTF-8")

val contractJsons = readFromArray(jsonBytes)

println(contractJsons)

Le résultat imprimé sera :

List(ContractJson(NullContract, {
  "column": "age",
  "conditions": [
    {
      "conditionType": "equalsCondition",
      "conditionDefinition": {
        "column": "species",
        "value": "person"
      }
    }
  ]
}))
0
Andriy Plokhotnyuk 25 oct. 2019 à 20:39