[ 
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)

Reply via email to