Skip to content

Commit 1816c38

Browse files
committed
Parsing Avro bytes or fixed types with logical type decimal into java.util.BigDecimal.
1 parent 4dd9828 commit 1816c38

File tree

5 files changed

+289
-27
lines changed

5 files changed

+289
-27
lines changed

avro/src/main/java/com/fasterxml/jackson/dataformat/avro/annotation/Decimal.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import java.lang.annotation.Target;
77

88
/**
9-
* Instructs the {@link com.fasterxml.jackson.dataformat.avro.schema.AvroSchemaGenerator AvroSchemaGenerator}
9+
* When generate logical types is enabled, annotation instructs the
10+
* {@link com.fasterxml.jackson.dataformat.avro.schema.AvroSchemaGenerator AvroSchemaGenerator}
1011
* to declare the annotated property's logical type as "decimal" ({@link org.apache.avro.LogicalTypes.Decimal}).
1112
* By default, the Avro type is "bytes" ({@link org.apache.avro.Schema.Type#BYTES}), unless the field is also
1213
* annotated with {@link com.fasterxml.jackson.dataformat.avro.AvroFixedSize}, in which case the Avro type
@@ -29,6 +30,6 @@
2930
/**
3031
* Scale must be zero or a positive integer less than or equal to the precision.
3132
*/
32-
int scale() default 0;
33+
int scale();
3334

3435
}

avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImpl.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,34 @@ public long getRemainingElements()
581581
public abstract int decodeIndex() throws IOException;
582582
public abstract int decodeEnum() throws IOException;
583583

584+
/*
585+
/**********************************************************
586+
/* Methods for AvroReadContext implementations: decimals
587+
/**********************************************************
588+
*/
589+
590+
public JsonToken decodeBytesDecimal(int scale) throws IOException {
591+
decodeBytes();
592+
_numberBigDecimal = new BigDecimal(new BigInteger(_binaryValue), scale);
593+
_numTypesValid = NR_BIGDECIMAL;
594+
return JsonToken.VALUE_NUMBER_FLOAT;
595+
}
596+
597+
public void skipBytesDecimal() throws IOException {
598+
skipBytes();
599+
}
600+
601+
public JsonToken decodeFixedDecimal(int scale, int size) throws IOException {
602+
decodeFixed(size);
603+
_numberBigDecimal = new BigDecimal(new BigInteger(_binaryValue), scale);
604+
_numTypesValid = NR_BIGDECIMAL;
605+
return JsonToken.VALUE_NUMBER_FLOAT;
606+
}
607+
608+
public void skipFixedDecimal(int size) throws IOException {
609+
skipFixed(size);
610+
}
611+
584612
/*
585613
/**********************************************************
586614
/* Methods for AvroReadContext impls, other

avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroReaderFactory.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.IOException;
44
import java.util.*;
55

6+
import org.apache.avro.LogicalTypes;
67
import org.apache.avro.Schema;
78

89
import com.fasterxml.jackson.dataformat.avro.deser.ScalarDecoder.*;
@@ -56,12 +57,18 @@ public ScalarDecoder createScalarValueDecoder(Schema type)
5657
case BOOLEAN:
5758
return READER_BOOLEAN;
5859
case BYTES:
60+
if (type.getLogicalType() instanceof LogicalTypes.Decimal) {
61+
return new BytesDecimalReader(((LogicalTypes.Decimal) type.getLogicalType()).getScale());
62+
}
5963
return READER_BYTES;
6064
case DOUBLE:
6165
return READER_DOUBLE;
6266
case ENUM:
6367
return new EnumDecoder(AvroSchemaHelper.getFullName(type), type.getEnumSymbols());
6468
case FIXED:
69+
if (type.getLogicalType() instanceof LogicalTypes.Decimal) {
70+
return new FixedDecimalReader(((LogicalTypes.Decimal) type.getLogicalType()).getScale(), type.getFixedSize());
71+
}
6572
return new FixedDecoder(type.getFixedSize(), AvroSchemaHelper.getFullName(type));
6673
case FLOAT:
6774
return READER_FLOAT;

avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/ScalarDecoder.java

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.fasterxml.jackson.dataformat.avro.deser;
22

33
import java.io.IOException;
4+
import java.math.BigDecimal;
45
import java.util.List;
56

67
import com.fasterxml.jackson.core.JsonToken;
@@ -546,4 +547,100 @@ public void skipValue(AvroParserImpl parser) throws IOException {
546547
}
547548
}
548549
}
550+
551+
protected final static class FixedDecimalReader extends ScalarDecoder {
552+
private final int _scale;
553+
private final int _size;
554+
555+
public FixedDecimalReader(int scale, int size) {
556+
_scale = scale;
557+
_size = size;
558+
}
559+
560+
@Override
561+
public JsonToken decodeValue(AvroParserImpl parser) throws IOException {
562+
return parser.decodeFixedDecimal(_scale, _size);
563+
}
564+
565+
@Override
566+
protected void skipValue(AvroParserImpl parser) throws IOException {
567+
parser.skipFixedDecimal(_size);
568+
}
569+
570+
@Override
571+
public String getTypeId() {
572+
return AvroSchemaHelper.getTypeId(BigDecimal.class);
573+
}
574+
575+
@Override
576+
public AvroFieldReader asFieldReader(String name, boolean skipper) {
577+
return new FR(name, skipper, getTypeId(), _scale, _size);
578+
}
579+
580+
private final static class FR extends AvroFieldReader {
581+
private final int _scale;
582+
private final int _size;
583+
public FR(String name, boolean skipper, String typeId, int scale, int size) {
584+
super(name, skipper, typeId);
585+
_scale = scale;
586+
_size = size;
587+
}
588+
589+
@Override
590+
public JsonToken readValue(AvroReadContext parent, AvroParserImpl parser) throws IOException {
591+
return parser.decodeFixedDecimal(_scale, _size);
592+
}
593+
594+
@Override
595+
public void skipValue(AvroParserImpl parser) throws IOException {
596+
parser.skipFixedDecimal(_size);
597+
}
598+
}
599+
}
600+
601+
protected final static class BytesDecimalReader extends ScalarDecoder {
602+
private final int _scale;
603+
604+
public BytesDecimalReader(int scale) {
605+
_scale = scale;
606+
}
607+
608+
@Override
609+
public JsonToken decodeValue(AvroParserImpl parser) throws IOException {
610+
return parser.decodeBytesDecimal(_scale);
611+
}
612+
613+
@Override
614+
protected void skipValue(AvroParserImpl parser) throws IOException {
615+
parser.skipBytesDecimal();
616+
}
617+
618+
@Override
619+
public String getTypeId() {
620+
return AvroSchemaHelper.getTypeId(BigDecimal.class);
621+
}
622+
623+
@Override
624+
public AvroFieldReader asFieldReader(String name, boolean skipper) {
625+
return new FR(name, skipper, getTypeId(), _scale);
626+
}
627+
628+
private final static class FR extends AvroFieldReader {
629+
private final int _scale;
630+
public FR(String name, boolean skipper, String typeId, int scale) {
631+
super(name, skipper, typeId);
632+
_scale = scale;
633+
}
634+
635+
@Override
636+
public JsonToken readValue(AvroReadContext parent, AvroParserImpl parser) throws IOException {
637+
return parser.decodeBytesDecimal(_scale);
638+
}
639+
640+
@Override
641+
public void skipValue(AvroParserImpl parser) throws IOException {
642+
parser.skipFloat();
643+
}
644+
}
645+
}
549646
}

0 commit comments

Comments
 (0)