我如何在Scala Jackson中遍历JSON对象,即使存在错误?

huangapple go评论78阅读模式
英文:

How can I iterate through JSON objects even there is error using Scala Jackson

问题

以下是您提供的代码的翻译:

// 当前,jackson在属性值为空时会拒绝整个JSON。

// 我想使用com.fasterxml.jackson.*来解析JSON代码。

// 如下所示的输入JSON中,某些元素的名称属性为空。

// 因此,通过Jackson迭代JSON对象将被忽略。

// 因此,将形成2个作为输出的元素。

// 我使用了下面的代码,但没有成功

def readJsonString[T](content: String)(implicit m: Manifest[T]): T = {
   val objectMapper = new ObjectMapper(new JsonFactory().enable(Feature.ALLOW_COMMENTS)) with ScalaObjectMapper
   objectMapper.registerModule(DefaultScalaModule)
   objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
   objectMapper.configure(DeserializationFeature.WRAP_EXCEPTIONS, false)
   objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
   objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
   objectMapper.readValue(content)
}

// 要作为输入使用的现有Json,其中某些属性具有空值

[
   {
      "name": "Invalid",
      "ruleType": "validation_1",
      "inputs": [ { "Name": "", "country": ["USA"] } ]
   },
   {
      "name": "",
      "ruleType": "validation_2",
      "inputs": [ { "Name": "Test", "place": ["USA"] } ]
   },
   {
      "name": "Valid",
      "ruleType": "validation_1",
      "inputs": []
   },
   {
      "name": "Valid",
      "ruleType": "validation_2",
      "inputs": [ { "Name": "Test", "place": ["USA"] } ]
   },
   {
      "name": "Valid",
      "ruleType": "validation_1",
      "inputs": [ { "Name": "Test", "place": ["France"] } ]
   }
]

// 从上述创建的新Json中,具有适当名称属性值的Json

[
   {
      "name": "Valid",
      "ruleType": "validation_1",
      "inputs": [ { "Name": "Test", "country": ["USA"] } ]
   },

   {
      "name": "Valid",
      "ruleType": "validation_1",
      "inputs": [ { "Name": "Test", "place": ["France"] } ]
   }
]

请注意,这是您提供的代码的直接翻译,无需其他解释或附加内容。如果您有更多代码部分需要翻译,请随时提供。

英文:

Currently, jackson is rejecting the whole JSON when there is blank property value.

I want to use com.fasterxml.jackson.* to parse JSON code.

As you see below input JSON, name attribute is blank some of the elements.

Hense iterate through JSON objects will ignore by Jackson.

hence there will be 2 elements formed as part of the output.

I am using below code but no luck

 def readJsonString[T](content: String)(implicit m: Manifest[T]): T = {
val objectMapper = new ObjectMapper(new JsonFactory().enable(Feature.ALLOW_COMMENTS)) with ScalaObjectMapper
objectMapper.registerModule(DefaultScalaModule)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
objectMapper.configure(DeserializationFeature.WRAP_EXCEPTIONS, false)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
objectMapper.readValue(content)
}

//Existing Json that I want to use as input where some attribute has blank value

[
{
"name": "Invalid",
"ruleType": "validation_1",
"inputs": [ { "Name": "", "country": ["USA"] } ]
},
{
"name": "",
"ruleType": "validation_2",
"inputs": [ { "Name": "Test", "place": ["USA"] } ]
},
{
"name": "Valid",
"ruleType": "validation_1",
"inputs": []
}
{
"name": "Valid",
"ruleType": "validation_2",
"inputs": [ { "Name": "Test", "place": ["USA"] } ]
},
{
"name": "Valid",
"ruleType": "validation_1",
"inputs": [ { "Name": "Test", "place": ["France"] } ]
}
]

//New Json that will created from above which has proper name attribute value

[
{
"name": "Valid",
"ruleType": "validation_1",
"inputs": [ { "Name": "Test", "country": ["USA"] } ]
}
{
"name": "Valid",
"ruleType": "validation_1",
"inputs": [ { "Name": "Test", "place": ["France"] } ]
}
]

答案1

得分: 0

这是一个使用Jackson库的解决方案:

用于映射JSON的案例类:

case class NamePlace(Name: String, country: Seq[String])
case class NameRuleTypeInputs(name: String, ruleType: String, inputs: Seq[NamePlace])

自定义序列化器以在序列化之前包含字段验证:

class NameRuleTypeInputsSerializer(defaultSerializer: JsonSerializer[Object]) extends JsonSerializer[NameRuleTypeInputs] {
  override def serialize(value: NameRuleTypeInputs, gen: JsonGenerator, serializers: SerializerProvider): Unit = {
    if (isValid(value)) {
      defaultSerializer.serialize(value, gen, serializers)
    }
  }

  private def isValid(value: NameRuleTypeInputs) = {
    !Option(value.name).getOrElse("").isEmpty &&
      Option(value.inputs).getOrElse(Seq.empty).nonEmpty &&
      !value.inputs.exists(i => Option(i.Name).getOrElse("").isEmpty)
  }
}

更新你的ObjectMapper以包含自定义序列化器:

val objectMapper = new ObjectMapper(new JsonFactory().enable(Feature.ALLOW_COMMENTS)) with ScalaObjectMapper
objectMapper.registerModule(DefaultScalaModule)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
objectMapper.configure(DeserializationFeature.WRAP_EXCEPTIONS, false)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
objectMapper.registerModule(new SimpleModule() {
  override def setupModule(context: Module.SetupContext): Unit = {
    super.setupModule(context)
    context.addBeanSerializerModifier(new BeanSerializerModifier() {
      override def modifySerializer(config: SerializationConfig, beanDesc: BeanDescription, serializer: JsonSerializer[_]): JsonSerializer[_] = {
        if (classOf[NameRuleTypeInputs].isAssignableFrom(beanDesc.getBeanClass)) {
          new NameRuleTypeInputsSerializer(serializer.asInstanceOf[JsonSerializer[Object]])
        } else {
          serializer
        }
      }
    })
  }
})

读取/写入JSON的方法:

def readJsonString[T](content: String)(implicit m: Manifest[T]): T = {
  objectMapper.readValue(content)
}

def writeJsonString(nameRuleTypeInputsList: Seq[NameRuleTypeInputs]): String = {
  // 使用漂亮的打印器以提高可读性
  objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(nameRuleTypeInputsList)
}

一个小测试:

val testJson =
  """
      [
              {
                  "name": "Invalid",
                  "ruleType": "validation_1",
                  "inputs": [ { "Name": "", "country": ["USA"] } ]

              },
              {
                  "name": "",
                  "ruleType": "validation_2",
                  "inputs": [ { "Name": "Test", "country": ["USA"] } ]

              },
              {
                  "name": "Valid",
                  "ruleType": "validation_1",
                  "inputs": []

              },
              {
                  "name": "Valid",
                  "ruleType": "validation_2",
                  "inputs": [ { "Name": "Test", "country": ["USA"] } ]

              },
              {
                  "name": "Valid",
                  "ruleType": "validation_1",
                  "inputs": [ { "Name": "Test", "country": ["France"] } ]

              }
      ]
  """.stripMargin

val namedRuleTypeInputs: Seq[NameRuleTypeInputs] = readJsonString[Seq[NameRuleTypeInputs]](testJson)

println(writeJsonString(namedRuleTypeInputs))

输出:

[ {
  "name" : "Valid",
  "ruleType" : "validation_2",
  "inputs" : [ {
    "Name" : "Test",
    "country" : [ "USA" ]
  } ]
}, {
  "name" : "Valid",
  "ruleType" : "validation_1",
  "inputs" : [ {
    "Name" : "Test",
    "country" : [ "France" ]
  } ]
} ]

有用的参考链接:https://www.baeldung.com/jackson-serialize-field-custom-criteria

英文:

Here is one solution that would work using jackson:

Case classes to map your json to:

  case class NamePlace(Name: String, country: Seq[String])
case class NameRuleTypeInputs(name: String, ruleType: String, inputs: Seq[NamePlace])

Custom serializer to include field validations before serializing:

  class NameRuleTypeInputsSerializer(defaultSerializer: JsonSerializer[Object]) extends JsonSerializer[NameRuleTypeInputs] {
override def serialize(value: NameRuleTypeInputs, gen: JsonGenerator, serializers: SerializerProvider): Unit = {
if (isValid(value)) {
defaultSerializer.serialize(value, gen, serializers)
}
}
private def isValid(value: NameRuleTypeInputs) = {
!Option(value.name).getOrElse("").isEmpty &&
Option(value.inputs).getOrElse(Seq.empty).nonEmpty &&
!value.inputs.exists(i => Option(i.Name).getOrElse("").isEmpty)
}
}

Updated your objectMapper to include the custom serializer:

  val objectMapper = new ObjectMapper(new JsonFactory().enable(Feature.ALLOW_COMMENTS)) with ScalaObjectMapper
objectMapper.registerModule(DefaultScalaModule)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
objectMapper.configure(DeserializationFeature.WRAP_EXCEPTIONS, false)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
objectMapper.registerModule(new SimpleModule(){
override def setupModule(context: Module.SetupContext): Unit = {
super.setupModule(context)
context.addBeanSerializerModifier(new BeanSerializerModifier() {
override def modifySerializer(config: SerializationConfig, beanDesc: BeanDescription, serializer: JsonSerializer[_]): JsonSerializer[_] = {
if(classOf[NameRuleTypeInputs] isAssignableFrom beanDesc.getBeanClass) {
new NameRuleTypeInputsSerializer(serializer.asInstanceOf[JsonSerializer[Object]])
} else {
serializer
}
}
})
}
})

Methods to read/write json:

  def readJsonString[T](content: String)(implicit m: Manifest[T]): T = {
objectMapper.readValue(content)
}
def writeJsonString(nameRuleTypeInputsList: Seq[NameRuleTypeInputs]): String = {
// Using pretty printer for readability
objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(nameRuleTypeInputsList)
}

A small test:

val testJson =
"""
[
{
"name": "Invalid",
"ruleType": "validation_1",
"inputs": [ { "Name": "", "country": ["USA"] } ]
},
{
"name": "",
"ruleType": "validation_2",
"inputs": [ { "Name": "Test", "country": ["USA"] } ]
},
{
"name": "Valid",
"ruleType": "validation_1",
"inputs": []
},
{
"name": "Valid",
"ruleType": "validation_2",
"inputs": [ { "Name": "Test", "country": ["USA"] } ]
},
{
"name": "Valid",
"ruleType": "validation_1",
"inputs": [ { "Name": "Test", "country": ["France"] } ]
}
]
""".stripMargin
  val namedRuleTypeInputs: Seq[NameRuleTypeInputs] = readJsonString[Seq[NameRuleTypeInputs]](testJson)
println(writeJsonString(namedRuleTypeInputs))

Output:

[ {
"name" : "Valid",
"ruleType" : "validation_2",
"inputs" : [ {
"Name" : "Test",
"country" : [ "USA" ]
} ]
}, {
"name" : "Valid",
"ruleType" : "validation_1",
"inputs" : [ {
"Name" : "Test",
"country" : [ "France" ]
} ]
} ]

Useful Reference: https://www.baeldung.com/jackson-serialize-field-custom-criteria

huangapple
  • 本文由 发表于 2020年8月6日 17:55:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/63281079.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定