1

I have the Micronaut Http Client with Kotlin which loads data from another micro service. The date formatting from this micro service is not valid sometimes.

Example: normal pattern is dd-MM-yyyy, but when there is no date micro service returns it as " - - ". So, I need to skip the serialisation when date is " - - ". I've already used @JsonDeserialize(using = "CustomDateDeserialize"), but I couldn't make it to not deserialise the date field when the pattern is not met.

MyClient

@Get(value = ..., produces = [MediaType.APPLICATION_JSON])
@Headers(...)
fun findParcels(...) : HttpResponse<MyDTO>

MyDTO

@KotlinBuilder
data class ParcelsDTO(
   @JsonProperty("property1")
   val property1: String
   
   @JsonProperty("property2")
   val property2: Long
   
   @JsonProperty("property3")
   @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
   val property3: LocalDate
   
   @JsonProperty("property4")
   val property4: BigDecimal
   
   @JsonProperty("property5")
   @JsonDeserialize(using = CustomLocalDateDeserializer::class)
   @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
   val property5: LocalDate
)

MyCustomDeserializer

class CustomLocalDateDeserializer protected constructor() : StdDeserializer<LocalDate?>(LocalDate::class.java) {
    @Throws(IOException::class)
    override fun deserialize(parser: JsonParser, context: DeserializationContext?): LocalDate {
        val node: JsonNode = parser.codec.readTree(parser)

        val itemName = node.get("property5").asText()

        if(!GenericValidator.isDate(itemName, "dd-MM-yyyy", true)){
            //here was to set to not serialize the node
        }

        return LocalDateDeserializer.INSTANCE.deserialize(parser, context)
    }
}

Source Json

{
   [
      {
         "property1": "string",
         "property2": 123,
         "property3": "01-01-2021",
         "property4": 1.20,
         "property5": " - - ",
      },
      {
         "property1": "string2",
         "property2": 123,
         "property3": "01-01-2021",
         "property4": 1.20,
         "property5": "01-01-2022",
      },   
   ]
}
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
ewertonsms
  • 11
  • 3
  • post your custom deserializer code – yejianfengblue Jun 03 '21 at 06:10
  • @yejianfengblue I'm add my custom deserializer and set in my DTO. – ewertonsms Jun 03 '21 at 11:56
  • Try remove @JsonFormat from `property5`. Is `null` returned in the `if (!GenericValidator...` code block? When you debug the malformated date, does it enter the if code block? – yejianfengblue Jun 03 '21 at 13:08
  • how I defined a JsonFormat for the date if the source Json to be deserialized does not meet the desired format Jackson returns an exception, what I wanted was that for cases where the pattern is not met that the node be removed from deserialization. In the case of the if block (!GenericValidator... it needs me to return a specific date (An instantiated LocalDate object) and this will reflect in my DTO with a date that doesn't exist, the intention to get a JsonIgnore behavior where the default is different , that is, if the date "dd-MM-yyyy" returns a LocalDate, otherwise JsonIgnore this field – ewertonsms Jun 03 '21 at 13:24

1 Answers1

0

Your custom deserialiser does more than it has to. You need to handle only date value. See how it should look like:

import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.BeanProperty
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer
import java.io.IOException
import java.time.LocalDate
import java.time.format.DateTimeFormatter

class CustomLocalDateDeserializer : LocalDateDeserializer(DateTimeFormatter.ofPattern("dd-MM-yyyy")) {

    @Throws(IOException::class)
    override fun deserialize(parser: JsonParser, context: DeserializationContext?): LocalDate {
        val value: String? = parser.text

        if (value == null || value == " - - ") {
            // skip deserialisation and return default date
            return LocalDate.of(2000, 1, 1)
        }
        return super.deserialize(parser, context)
    }

    override fun createContextual(ctxt: DeserializationContext?, property: BeanProperty?): JsonDeserializer<*> {
        return this
    }
}

You can register it as below:

@JsonProperty("property5")
@JsonDeserialize(using = CustomLocalDateDeserializer::class)
val property5: LocalDate
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146