[
https://issues.apache.org/jira/browse/AVRO-3989?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17939459#comment-17939459
]
Harshit Mittal edited comment on AVRO-3989 at 3/30/25 5:59 AM:
---------------------------------------------------------------
While this bug is annoying, I am able to figure out a work around for this. The
fix is to use {{new SpecificDatumReader<>(AvroPojo.class)}} instead of {{new
ReflectDatumReader<>(AvroPojo.class)}} or
{{SpecificData.get().createDatumReader(AvroPojo.class)}}.
Similarly for serialization, we need to use {{SpecificDatumWritier}} directly.
This creates a new instance of {{SpecificData}} from {{MODEL$}} static member
of the class that correctly handles logical type within a union field.
In fact, avro sourcecode seems to suggest this as the right fix per this
unit-test -
[TestSpecificData.java|https://github.com/apache/avro/blob/main/lang/java/compiler/src/test/java/org/apache/avro/specific/TestSpecificData.java]
was (Author: hmittal83):
While this bug is annoying, I am able to figure out a work around for this. The
fix is to use `new SpecificDatumReader<>(AvroPojo.class)` instead of `new
ReflectDatumReader<>(AvroPojo.class)` or
`SpecificData.get().createDatumReader(AvroPojo.class)`.
Similarly for serialization, we need to use `SpecificDatumWritier` directly.
This creates a new instance of `SpecificData` from `MODEL$` static member of
the class that correctly handles logical type within a union field.
> Schema conversion for logical types ignored when type is part of union
> ----------------------------------------------------------------------
>
> Key: AVRO-3989
> URL: https://issues.apache.org/jira/browse/AVRO-3989
> Project: Apache Avro
> Issue Type: Bug
> Components: java
> Affects Versions: 1.11.3
> Reporter: Jacob Stampe Mikkelsen
> Priority: Major
> Attachments: image-2024-06-02-21-32-25-461.png
>
>
> I have a schema with an optional timestamp which is to be rendered as millis
> and the generated Java class fails to get the conversions array and method
> added, which means that at runtime I get a ClassCastException when an
> "Instant" object is cast to a "Long" because there was no registered
> converter:
> The element with an optional timestamp in my schema:
> {{{}}
> {{ "name": "DecisionStartTime",}}
> {{ "type": [}}
> {{ "null",}}
> {{ {}}
> {{ "type": "long",}}
> {{ "logicalType": "timestamp-millis"}}
> {{ }}}
> {{ ],}}
> {{ "default": null}}
> {{}}}
> The problem seems to be here:
> [https://github.com/apache/avro/blame/5a60b5c43fe9c3bb40f4a1303913fdb3598bd4a5/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm#L198]
> Which only renders the conversion part if any of the fields has logicalType
> set and the actual method:
> [https://github.com/apache/avro/blob/5a60b5c43fe9c3bb40f4a1303913fdb3598bd4a5/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java#L976C3-L983C4]
> Does not take into account that a field which is a union does not have a
> logical type, however one of the union types might.
> *Proposed solution* - replace method
> {{ public boolean hasLogicalTypeField(Schema schema) {}}
> {{ for (Schema.Field field : schema.getFields()) {}}
> {{ if (field.schema().getLogicalType() != null) {}}
> {{ return true;}}
> {{ }}}
> {{ }}}
> {{ return false;}}
> {{ }}}
> With a method like this:
> {{ public boolean hasLogicalTypeField(Schema schema) {}}
> {{ for (Schema.Field field : schema.getFields()) {}}
> {{ if (field.schema().getLogicalType() != null) {}}
> {{ return true;}}
> {{ } else if (field.schema().type == Type.UNION) {}}
> {{ for (Schema type : field.schema().getTypes()) {}}
> {{ if (type.getLogicalType() != null) {}}
> {{ return true;}}
> {{ }}}
> {{ }}}
> {{ }}}
> {{ }}}
> {{ return false;}}
> {{ }}}
> The conversionInstance() method might also need tweaking in order to identify
> that the given type has a logical type as part of the union.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)