Skip to content

Commit

Permalink
AVRO-3947: Support any subclass or instance in custom LogicalType Con…
Browse files Browse the repository at this point in the history
…versions
  • Loading branch information
tmoschou committed Feb 26, 2024
1 parent 627e8d5 commit f3297d0
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.UUID;
import java.util.concurrent.ConcurrentMap;

import com.fasterxml.jackson.databind.JsonNode;
import org.apache.avro.AvroMissingFieldException;
import org.apache.avro.AvroRuntimeException;
import org.apache.avro.AvroTypeException;
Expand All @@ -57,8 +58,6 @@
import org.apache.avro.io.FastReaderBuilder;
import org.apache.avro.util.Utf8;
import org.apache.avro.util.internal.Accessor;

import com.fasterxml.jackson.databind.JsonNode;
import org.apache.avro.util.springframework.ConcurrentReferenceHashMap;

import static org.apache.avro.util.springframework.ConcurrentReferenceHashMap.ReferenceType.WEAK;
Expand Down Expand Up @@ -916,14 +915,13 @@ public int resolveUnion(Schema union, Object datum) {
// this allows logical type concrete classes to overlap with supported ones
// for example, a conversion could return a map
if (datum != null) {
Map<String, Conversion<?>> conversions = conversionsByClass.get(datum.getClass());
if (conversions != null) {
List<Schema> candidates = union.getTypes();
for (int i = 0; i < candidates.size(); i += 1) {
LogicalType candidateType = candidates.get(i).getLogicalType();
if (candidateType != null) {
Conversion<?> conversion = conversions.get(candidateType.getName());
if (conversion != null) {
List<Schema> candidates = union.getTypes();
for (int i = 0; i < candidates.size(); i += 1) {
LogicalType candidateType = candidates.get(i).getLogicalType();
if (candidateType != null) {
Conversion<?> conversion = conversions.get(candidateType.getName());
if (conversion != null) {
if (conversion.getConvertedType().isInstance(datum)) {
return i;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import java.util.Objects;

public final class CustomType {
public class CustomType {
private final String name;

public CustomType(CharSequence name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@

package org.apache.avro.generic;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.UUID;

import org.apache.avro.Conversion;
import org.apache.avro.Conversions;
import org.apache.avro.CustomType;
Expand All @@ -35,24 +50,10 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.UUID;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotSame;

public class TestGenericLogicalTypes {
Expand Down Expand Up @@ -488,4 +489,20 @@ public void testWriteAutomaticallyRegisteredUri() throws IOException {
assertEquals(expected, read(GenericData.get().createDatumReader(stringSchema), test),
"Should read CustomType as strings");
}

@Test
public void testLogicalTypeSubclassing() {
Schema stringSchema = Schema.create(Schema.Type.STRING);
GenericData.setStringType(stringSchema, GenericData.StringType.String);
LogicalType customType = LogicalTypes.getCustomRegisteredTypes().get("custom").fromSchema(stringSchema);
Schema customTypeSchema = customType.addToSchema(Schema.create(Schema.Type.STRING));
Schema unionSchema = Schema.createUnion(Schema.create(Schema.Type.NULL), customTypeSchema);

// anonymous subclass
CustomType ct1 = new CustomType("foo") {
};
assertNotEquals(ct1.getClass(), CustomType.class);
int index = GenericData.get().resolveUnion(unionSchema, ct1);
assertEquals(1, index, "Should resolve custom type subclass correct schema");
}
}

0 comments on commit f3297d0

Please sign in to comment.