Skip to content

Commit 4b6a7ea

Browse files
authored
Merge pull request #1481 from stainless-sdks/timezoneless-offset-datetimes
allow no timezone in offset datetime
2 parents 0ab42f4 + e484c3c commit 4b6a7ea

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

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

Lines changed: 30 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)
@@ -165,3 +167,31 @@ private class LenientLocalDateTimeDeserializer :
165167
}
166168
}
167169
}
170+
171+
/**
172+
* A deserializer that can deserialize [OffsetDateTime], assuming UTC when a timezone isn't given.
173+
*/
174+
private class LenientOffsetDateTimeDeserializer :
175+
StdDeserializer<OffsetDateTime>(OffsetDateTime::class.java) {
176+
override fun logicalType(): LogicalType = LogicalType.DateTime
177+
178+
override fun deserialize(p: JsonParser, context: DeserializationContext?): OffsetDateTime {
179+
val exceptions = mutableListOf<Exception>()
180+
181+
try {
182+
return OffsetDateTime.parse(p.text)
183+
} catch (e: DateTimeException) {
184+
exceptions.add(e)
185+
}
186+
187+
try {
188+
return OffsetDateTime.parse(p.text + 'Z')
189+
} catch (e: DateTimeException) {
190+
exceptions.add(e)
191+
}
192+
193+
throw JsonParseException(p, "Cannot parse `OffsetDateTime` from value: ${p.text}").apply {
194+
exceptions.forEach { addSuppressed(it) }
195+
}
196+
}
197+
}

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)