[
https://issues.apache.org/jira/browse/AVRO-2904?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Dan Lipofsky updated AVRO-2904:
-------------------------------
Attachment: (was: AVRO-2471.zip)
> timestamp-millis doesn't truncate when in a union with null
> -----------------------------------------------------------
>
> Key: AVRO-2904
> URL: https://issues.apache.org/jira/browse/AVRO-2904
> Project: Apache Avro
> Issue Type: Bug
> Components: java, logical types
> Affects Versions: 1.10.0
> Reporter: Dan Lipofsky
> Priority: Major
>
> In Avro 1.10.0 the setter for logical-type timestamp-millis will truncate the
> timestamp to millis in the simplest condition but not when it is in a union
> with null.
> It looks like something similar was addressed in AVRO-2360 but that was
> supposedly fixed in 1.9.0 and this is still broken in 1.10.0.
> Here is my IDL
> {noformat}
> record TimestampTest1 {
> union { null, timestamp_ms } ts;
> }
> record TimestampTest2 {
> timestamp_ms ts;
> }
> {noformat}
> Here is my test, in which {{TimestampTest2}} passes but {{TimestampTest1}}
> fails.
> {noformat}
> public class SerDeTest {
> @Test
> public void TimestampTest1() throws IOException {
> final TimestampTest1 ts =
> TimestampTest1.newBuilder().setTs(Instant.now()).build();
> byte[] bytes = serialize(ts);
> TimestampTest1 other = deserialize(ts.getSchema(), bytes);
> Assert.assertEquals(ts, other);
> }
> @Test
> public void TimestampTest2() throws IOException {
> final TimestampTest2 ts =
> TimestampTest2.newBuilder().setTs(Instant.now()).build();
> byte[] bytes = serialize(ts);
> TimestampTest2 other = deserialize(ts.getSchema(), bytes);
> Assert.assertEquals(ts, other);
> }
> private <T extends SpecificRecord> T deserialize(Schema schema, byte[]
> bytes)
> throws IOException {
> Decoder decoder = DecoderFactory.get().binaryDecoder(bytes, null);
> SpecificDatumReader<T> reader = new SpecificDatumReader<>(schema);
> return reader.read(null, decoder);
> }
> private byte[] serialize(SpecificRecord record) throws IOException {
> try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
> SpecificDatumWriter<SpecificRecord> writer = new
> SpecificDatumWriter<>(
> record.getSchema());
> Encoder encoder = EncoderFactory.get().binaryEncoder(out, null);
> writer.write(record, encoder);
> encoder.flush();
> return out.toByteArray();
> }
> }
> }
> {noformat}
> {{TimestampTest1}} fails with
> {noformat}
> java.lang.AssertionError:
> Expected :{"ts": 2020-07-23T21:35:12.348379Z}
> Actual :{"ts": 2020-07-23T21:35:12.348Z}
> {noformat}
> If I change my tests to use {{Instant.now().truncatedTo(ChronoUnit.MILLIS)}}
> they'll both pass, but it seems like that should not be necessary,
> particularly given the code below.
> Looking at the generated Java DTO, I see a few differences, but the most
> important would seem to be that the working DTO has
> {noformat}
> public void setTs(java.time.Instant value) {
> this.ts = value.truncatedTo(java.time.temporal.ChronoUnit.MILLIS);
> }
> {noformat}
> while the broken one has
> {noformat}
> public void setTs(java.time.Instant value) {
> this.ts = value;
> }
> {noformat}
> The working one also has this code, which is missing from the broken one:
> {noformat}
> private static final org.apache.avro.Conversion<?>[] conversions =
> new org.apache.avro.Conversion<?>[] {
> new org.apache.avro.data.TimeConversions.TimestampMillisConversion(),
> null
> };
> @Override
> public org.apache.avro.Conversion<?> getConversion(int field) {
> return conversions[field];
> }
> {noformat}
--
This message was sent by Atlassian Jira
(v8.3.4#803005)