Skip to content

Commit 5718eac

Browse files
committed
allow no timezone in offset datetime
1 parent 0ab42f4 commit 5718eac

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

lithic-java-core/src/main/kotlin/com/lithic/api/core/ObjectMappers.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import java.io.InputStream
2424
import java.time.DateTimeException
2525
import java.time.LocalDate
2626
import java.time.LocalDateTime
27+
import java.time.OffsetDateTime
2728
import java.time.ZonedDateTime
2829
import java.time.format.DateTimeFormatter
2930
import java.time.temporal.ChronoField
@@ -37,6 +38,7 @@ fun jsonMapper(): JsonMapper =
3738
SimpleModule()
3839
.addSerializer(InputStreamSerializer)
3940
.addDeserializer(LocalDateTime::class.java, LenientLocalDateTimeDeserializer())
41+
.addDeserializer(OffsetDateTime::class.java, LenientOffsetDateTimeDeserializer())
4042
)
4143
.withCoercionConfig(LogicalType.Boolean) {
4244
it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail)
@@ -123,6 +125,33 @@ private object InputStreamSerializer : BaseSerializer<InputStream>(InputStream::
123125
}
124126
}
125127

128+
/**
129+
* A deserializer that can deserialize [OffsetDateTime], assuming UTC when a timezone isn't given.
130+
*/
131+
private class LenientOffsetDateTimeDeserializer : StdDeserializer<OffsetDateTime>(OffsetDateTime::class.java) {
132+
override fun logicalType(): LogicalType = LogicalType.DateTime
133+
134+
override fun deserialize(p: JsonParser, context: DeserializationContext?): OffsetDateTime {
135+
val exceptions = mutableListOf<Exception>()
136+
137+
try {
138+
return OffsetDateTime.parse(p.text)
139+
} catch (e: DateTimeException) {
140+
exceptions.add(e)
141+
}
142+
143+
try {
144+
return OffsetDateTime.parse(p.text + 'Z')
145+
} catch (e: DateTimeException) {
146+
exceptions.add(e)
147+
}
148+
149+
throw JsonParseException(p, "Cannot parse `OffsetDateTime` from value: ${p.text}").apply {
150+
exceptions.forEach { addSuppressed(it) }
151+
}
152+
}
153+
}
154+
126155
/**
127156
* A deserializer that can deserialize [LocalDateTime] from datetimes, dates, and zoned datetimes.
128157
*/

lithic-java-core/src/test/kotlin/com/lithic/api/core/ObjectMappersTest.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
44
import com.fasterxml.jackson.databind.exc.MismatchedInputException
55
import com.fasterxml.jackson.module.kotlin.readValue
66
import java.time.LocalDateTime
7+
import java.time.OffsetDateTime
78
import kotlin.reflect.KClass
89
import org.assertj.core.api.Assertions.assertThat
910
import org.assertj.core.api.Assertions.catchThrowable
@@ -99,4 +100,19 @@ internal class ObjectMappersTest {
99100

100101
assertDoesNotThrow { jsonMapper().readValue<LocalDateTime>(json) }
101102
}
103+
104+
enum class LenientOffsetDateTimeTestCase(val string: String) {
105+
DATE_TIME("1998-04-21T04:00:00"),
106+
ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"),
107+
ZONED_DATE_TIME_2("1998-04-21T04:00:00Z"),
108+
}
109+
110+
@ParameterizedTest
111+
@EnumSource
112+
fun readOffsetDateTime_lenient(testCase: LenientOffsetDateTimeTestCase) {
113+
val jsonMapper = jsonMapper()
114+
val json = jsonMapper.writeValueAsString(testCase.string)
115+
116+
assertDoesNotThrow { jsonMapper().readValue<OffsetDateTime>(json) }
117+
}
102118
}

0 commit comments

Comments
 (0)