This is an automated email from the ASF dual-hosted git repository.

rskraba pushed a commit to branch branch-1.11
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/branch-1.11 by this push:
     new 54f5d08b7 AVRO-3473: ServiceLoader for Conversion (#1624)
54f5d08b7 is described below

commit 54f5d08b7df43866d499526ceefeba153de20a6f
Author: Oscar Westra van Holthe - Kind <[email protected]>
AuthorDate: Thu Jun 15 18:31:54 2023 +0200

    AVRO-3473: ServiceLoader for Conversion (#1624)
    
    * AVRO-3473: ServiceLoader for Conversion
    
    Automatically register Conversion classes using the Java 6 service
    loader upon startup. This works for any Conversion that does not need
    constructor parameters.
    
    * AVRO-3473: ServiceLoader for Conversion
    
    Improved variable name.
    
    * AVRO-3473: Spotless
    
    * Apply suggestions from code review
    
    Co-authored-by: Ryan Skraba <[email protected]>
    
    * AVRO-3473: Removed newline to trigger build
    
    * AVRO-3473: Add missing import
    
    No idea when that got dropped...
    
    * AVRO-3473: Removed unused import
    
    * AVRO-3473: Fix rebase errors
    
    * Fix static imports
    
    ---------
    
    Co-authored-by: Ryan Skraba <[email protected]>
---
 .../src/main/java/org/apache/avro/Conversion.java  | 43 ++++++++++------
 .../src/main/java/org/apache/avro/Conversions.java | 29 ++++++-----
 .../java/org/apache/avro/generic/GenericData.java  | 29 +++++++----
 ...ummyLogicalTypeFactory.java => CustomType.java} | 28 ++++++++--
 ...alTypeFactory.java => CustomTypeConverter.java} | 28 ++++++++--
 ...tory.java => CustomTypeLogicalTypeFactory.java} |  6 +--
 .../test/java/org/apache/avro/TestLogicalType.java |  4 +-
 .../avro/generic/TestGenericLogicalTypes.java      | 59 ++++++++++++++++++++--
 ...gicalTypeFactory => org.apache.avro.Conversion} |  2 +-
 ...org.apache.avro.LogicalTypes$LogicalTypeFactory |  2 +-
 10 files changed, 172 insertions(+), 58 deletions(-)

diff --git a/lang/java/avro/src/main/java/org/apache/avro/Conversion.java 
b/lang/java/avro/src/main/java/org/apache/avro/Conversion.java
index 4ae75f4a5..934672e7d 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/Conversion.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/Conversion.java
@@ -21,6 +21,9 @@ package org.apache.avro;
 import java.nio.ByteBuffer;
 import java.util.Collection;
 import java.util.Map;
+import java.util.ServiceLoader;
+
+import org.apache.avro.generic.GenericData;
 import org.apache.avro.generic.GenericEnumSymbol;
 import org.apache.avro.generic.GenericFixed;
 import org.apache.avro.generic.IndexedRecord;
@@ -28,23 +31,33 @@ import org.apache.avro.generic.IndexedRecord;
 /**
  * Conversion between generic and logical type instances.
  * <p>
- * Instances of this class are added to GenericData to convert a logical type 
to
- * a particular representation.
+ * Instances of this class can be added to GenericData to convert a logical 
type
+ * to a particular representation. This can be done manually, using
+ * {@link GenericData#addLogicalTypeConversion(Conversion)}, or automatically.
+ * This last option uses the Java {@link ServiceLoader}, and requires the
+ * implementation to be a public class with a public no-arg constructor, be
+ * named in a file called {@code 
/META-INF/services/org.apache.avro.Conversion},
+ * and both must available in the classpath.</li>
  * <p>
- * Implementations must provide: * {@link #getConvertedType()}: get the Java
- * class used for the logical type * {@link #getLogicalTypeName()}: get the
- * logical type this implements
+ * Implementations must provide:
+ * <ul>
+ * <li>{@link #getConvertedType()}: get the Java class used for the logical
+ * type</li>
+ * <li>{@link #getLogicalTypeName()}: get the logical type this implements</li>
+ * </ul>
  * <p>
- * Subclasses must also override all of the conversion methods for Avro's base
- * types that are valid for the logical type, or else risk causing
+ * Subclasses must also override the conversion methods for Avro's base types
+ * that are valid for the logical type, or else risk causing
  * {@code UnsupportedOperationException} at runtime.
  * <p>
  * Optionally, use {@link #getRecommendedSchema()} to provide a Schema that 
will
- * be used when a Schema is generated for the class returned by
- * {@code getConvertedType}.
+ * be used when generating a Schema for the class. This is useful when using
+ * {@code ReflectData} or {@code ProtobufData}, for example.
  *
- * @param <T> a Java type that generic data is converted to
+ * @param <T> a Java type that can represent the named logical type
+ * @see ServiceLoader
  */
+@SuppressWarnings("unused")
 public abstract class Conversion<T> {
 
   /**
@@ -65,9 +78,9 @@ public abstract class Conversion<T> {
    * Certain logical types may require adjusting the code within the "setter"
    * methods to make sure the data that is set is properly formatted. This 
method
    * allows the Conversion to generate custom setter code if required.
-   * 
-   * @param varName
-   * @param valParamName
+   *
+   * @param varName      the name of the variable holding the converted value
+   * @param valParamName the name of the parameter with the new converted value
    * @return a String for the body of the setter method
    */
   public String adjustAndSetValue(String varName, String valParamName) {
@@ -102,7 +115,7 @@ public abstract class Conversion<T> {
     throw new UnsupportedOperationException("fromCharSequence is not supported 
for " + type.getName());
   }
 
-  public T fromEnumSymbol(GenericEnumSymbol value, Schema schema, LogicalType 
type) {
+  public T fromEnumSymbol(GenericEnumSymbol<?> value, Schema schema, 
LogicalType type) {
     throw new UnsupportedOperationException("fromEnumSymbol is not supported 
for " + type.getName());
   }
 
@@ -150,7 +163,7 @@ public abstract class Conversion<T> {
     throw new UnsupportedOperationException("toCharSequence is not supported 
for " + type.getName());
   }
 
-  public GenericEnumSymbol toEnumSymbol(T value, Schema schema, LogicalType 
type) {
+  public GenericEnumSymbol<?> toEnumSymbol(T value, Schema schema, LogicalType 
type) {
     throw new UnsupportedOperationException("toEnumSymbol is not supported for 
" + type.getName());
   }
 
diff --git a/lang/java/avro/src/main/java/org/apache/avro/Conversions.java 
b/lang/java/avro/src/main/java/org/apache/avro/Conversions.java
index 1c28c9adb..7d01fc62a 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/Conversions.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/Conversions.java
@@ -106,11 +106,12 @@ public class Conversions {
       byte fillByte = (byte) (value.signum() < 0 ? 0xFF : 0x00);
       byte[] unscaled = value.unscaledValue().toByteArray();
       byte[] bytes = new byte[schema.getFixedSize()];
-      int offset = bytes.length - unscaled.length;
+      int unscaledLength = unscaled.length;
+      int offset = bytes.length - unscaledLength;
 
-      // Fill the front of the array and copy remaining with unscaled values
+      // Fill the front with the filler and copy the unscaled value into the 
remainder
       Arrays.fill(bytes, 0, offset, fillByte);
-      System.arraycopy(unscaled, 0, bytes, offset, bytes.length - offset);
+      System.arraycopy(unscaled, 0, bytes, offset, unscaledLength);
 
       return new GenericData.Fixed(schema, bytes);
     }
@@ -147,7 +148,7 @@ public class Conversions {
   }
 
   /**
-   * Convert a underlying representation of a logical type (such as a 
ByteBuffer)
+   * Convert an underlying representation of a logical type (such as a 
ByteBuffer)
    * to a higher level object (such as a BigDecimal).
    *
    * @param datum      The object to be converted.
@@ -157,9 +158,9 @@ public class Conversions {
    * @param conversion The tool used to finish the conversion. Cannot be null 
if
    *                   datum is not null.
    * @return The result object, which is a high level object of the logical 
type.
-   *         If a null datum is passed in, a null value will be returned.
-   * @throws IllegalArgumentException if a null schema, type or conversion is
-   *                                  passed in while datum is not null.
+   *         The null datum always converts to a null value.
+   * @throws IllegalArgumentException if datum is not null, but schema, type or
+   *                                  conversion is.
    */
   public static Object convertToLogicalType(Object datum, Schema schema, 
LogicalType type, Conversion<?> conversion) {
     if (datum == null) {
@@ -176,9 +177,9 @@ public class Conversions {
       case RECORD:
         return conversion.fromRecord((IndexedRecord) datum, schema, type);
       case ENUM:
-        return conversion.fromEnumSymbol((GenericEnumSymbol) datum, schema, 
type);
+        return conversion.fromEnumSymbol((GenericEnumSymbol<?>) datum, schema, 
type);
       case ARRAY:
-        return conversion.fromArray((Collection) datum, schema, type);
+        return conversion.fromArray((Collection<?>) datum, schema, type);
       case MAP:
         return conversion.fromMap((Map<?, ?>) datum, schema, type);
       case FIXED:
@@ -201,13 +202,13 @@ public class Conversions {
       return datum;
     } catch (ClassCastException e) {
       throw new AvroRuntimeException(
-          "Cannot convert " + datum + ":" + datum.getClass().getSimpleName() + 
": expected generic type", e);
+          "Cannot convert " + datum + ':' + datum.getClass().getSimpleName() + 
": expected generic type", e);
     }
   }
 
   /**
    * Convert a high level representation of a logical type (such as a 
BigDecimal)
-   * to the its underlying representation object (such as a ByteBuffer)
+   * to its underlying representation object (such as a ByteBuffer)
    *
    * @param datum      The object to be converted.
    * @param schema     The schema of datum. Cannot be null if datum is not 
null.
@@ -218,8 +219,8 @@ public class Conversions {
    * @return The result object, which is an underlying representation object of
    *         the logical type. If the input param datum is null, a null value 
will
    *         be returned.
-   * @throws IllegalArgumentException if a null schema, type or conversion is
-   *                                  passed in while datum is not null.
+   * @throws IllegalArgumentException if datum is not null, but schema, type or
+   *                                  conversion is.
    */
   public static <T> Object convertToRawType(Object datum, Schema schema, 
LogicalType type, Conversion<T> conversion) {
     if (datum == null) {
@@ -262,7 +263,7 @@ public class Conversions {
       return datum;
     } catch (ClassCastException e) {
       throw new AvroRuntimeException(
-          "Cannot convert " + datum + ":" + datum.getClass().getSimpleName() + 
": expected logical type", e);
+          "Cannot convert " + datum + ':' + datum.getClass().getSimpleName() + 
": expected logical type", e);
     }
   }
 
diff --git 
a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java 
b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
index 597a21949..e82dde040 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
@@ -33,6 +33,7 @@ import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.ServiceLoader;
 import java.util.UUID;
 import java.util.WeakHashMap;
 
@@ -115,6 +116,7 @@ public class GenericData {
   /** For subclasses. GenericData does not use a ClassLoader. */
   public GenericData(ClassLoader classLoader) {
     this.classLoader = (classLoader != null) ? classLoader : 
getClass().getClassLoader();
+    loadConversions();
   }
 
   /** Return the class loader that's used (by subclasses). */
@@ -122,6 +124,17 @@ public class GenericData {
     return classLoader;
   }
 
+  /**
+   * Use the Java 6 ServiceLoader to load conversions.
+   *
+   * @see #addLogicalTypeConversion(Conversion)
+   */
+  private void loadConversions() {
+    for (Conversion<?> conversion : ServiceLoader.load(Conversion.class, 
classLoader)) {
+      addLogicalTypeConversion(conversion);
+    }
+  }
+
   private Map<String, Conversion<?>> conversions = new HashMap<>();
 
   private Map<Class<?>, Map<String, Conversion<?>>> conversionsByClass = new 
IdentityHashMap<>();
@@ -132,19 +145,17 @@ public class GenericData {
 
   /**
    * Registers the given conversion to be used when reading and writing with 
this
-   * data model.
+   * data model. Conversions can also be registered automatically, as 
documented
+   * on the class {@link Conversion Conversion&lt;T&gt;}.
    *
    * @param conversion a logical type Conversion.
    */
   public void addLogicalTypeConversion(Conversion<?> conversion) {
     conversions.put(conversion.getLogicalTypeName(), conversion);
     Class<?> type = conversion.getConvertedType();
-    Map<String, Conversion<?>> conversions = conversionsByClass.get(type);
-    if (conversions == null) {
-      conversions = new LinkedHashMap<>();
-      conversionsByClass.put(type, conversions);
-    }
-    conversions.put(conversion.getLogicalTypeName(), conversion);
+    Map<String, Conversion<?>> conversionsForClass = 
conversionsByClass.computeIfAbsent(type,
+        k -> new LinkedHashMap<>());
+    conversionsForClass.put(conversion.getLogicalTypeName(), conversion);
   }
 
   /**
@@ -185,11 +196,11 @@ public class GenericData {
    * @return the conversion for the logical type, or null
    */
   @SuppressWarnings("unchecked")
-  public Conversion<Object> getConversionFor(LogicalType logicalType) {
+  public <T> Conversion<T> getConversionFor(LogicalType logicalType) {
     if (logicalType == null) {
       return null;
     }
-    return (Conversion<Object>) conversions.get(logicalType.getName());
+    return (Conversion<T>) conversions.get(logicalType.getName());
   }
 
   public static final String FAST_READER_PROP = "org.apache.avro.fastread";
diff --git 
a/lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java 
b/lang/java/avro/src/test/java/org/apache/avro/CustomType.java
similarity index 64%
copy from 
lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java
copy to lang/java/avro/src/test/java/org/apache/avro/CustomType.java
index 4957e3765..140ac901b 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/CustomType.java
@@ -15,16 +15,34 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.apache.avro;
 
-public class DummyLogicalTypeFactory implements 
LogicalTypes.LogicalTypeFactory {
+import java.util.Objects;
+
+public final class CustomType {
+  private final String name;
+
+  public CustomType(CharSequence name) {
+    this.name = name.toString();
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(name);
+  }
+
   @Override
-  public LogicalType fromSchema(Schema schema) {
-    return LogicalTypes.date();
+  public boolean equals(Object obj) {
+    return obj instanceof CustomType && name.equals(((CustomType) obj).name);
   }
 
   @Override
-  public String getTypeName() {
-    return "service-example";
+  public String toString() {
+    return "CustomType{name='" + name + "'}";
   }
 }
diff --git 
a/lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java 
b/lang/java/avro/src/test/java/org/apache/avro/CustomTypeConverter.java
similarity index 54%
copy from 
lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java
copy to lang/java/avro/src/test/java/org/apache/avro/CustomTypeConverter.java
index 4957e3765..de8fea02c 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/CustomTypeConverter.java
@@ -15,16 +15,34 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.apache.avro;
 
-public class DummyLogicalTypeFactory implements 
LogicalTypes.LogicalTypeFactory {
+public class CustomTypeConverter extends Conversion<CustomType> {
+  private static final CustomTypeLogicalTypeFactory logicalTypeFactory = new 
CustomTypeLogicalTypeFactory();
+
+  @Override
+  public Class<CustomType> getConvertedType() {
+    return CustomType.class;
+  }
+
+  @Override
+  public String getLogicalTypeName() {
+    return logicalTypeFactory.getTypeName();
+  }
+
+  @Override
+  public Schema getRecommendedSchema() {
+    return Schema.create(Schema.Type.STRING);
+  }
+
   @Override
-  public LogicalType fromSchema(Schema schema) {
-    return LogicalTypes.date();
+  public CustomType fromCharSequence(CharSequence value, Schema schema, 
LogicalType type) {
+    return new CustomType(value);
   }
 
   @Override
-  public String getTypeName() {
-    return "service-example";
+  public CharSequence toCharSequence(CustomType value, Schema schema, 
LogicalType type) {
+    return value.getName();
   }
 }
diff --git 
a/lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java 
b/lang/java/avro/src/test/java/org/apache/avro/CustomTypeLogicalTypeFactory.java
similarity index 86%
rename from 
lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java
rename to 
lang/java/avro/src/test/java/org/apache/avro/CustomTypeLogicalTypeFactory.java
index 4957e3765..3e121e024 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java
+++ 
b/lang/java/avro/src/test/java/org/apache/avro/CustomTypeLogicalTypeFactory.java
@@ -17,14 +17,14 @@
  */
 package org.apache.avro;
 
-public class DummyLogicalTypeFactory implements 
LogicalTypes.LogicalTypeFactory {
+public class CustomTypeLogicalTypeFactory implements 
LogicalTypes.LogicalTypeFactory {
   @Override
   public LogicalType fromSchema(Schema schema) {
-    return LogicalTypes.date();
+    return new LogicalType(getTypeName());
   }
 
   @Override
   public String getTypeName() {
-    return "service-example";
+    return "custom";
   }
 }
diff --git a/lang/java/avro/src/test/java/org/apache/avro/TestLogicalType.java 
b/lang/java/avro/src/test/java/org/apache/avro/TestLogicalType.java
index deadb2efc..40da41a06 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/TestLogicalType.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/TestLogicalType.java
@@ -290,8 +290,8 @@ public class TestLogicalType {
 
   @Test
   public void testRegisterLogicalTypeFactoryByServiceLoader() {
-    MatcherAssert.assertThat(LogicalTypes.getCustomRegisteredTypes(),
-        IsMapContaining.hasEntry(equalTo("service-example"), 
instanceOf(LogicalTypes.LogicalTypeFactory.class)));
+    assertThat(LogicalTypes.getCustomRegisteredTypes(),
+        IsMapContaining.hasEntry(equalTo("custom"), 
instanceOf(LogicalTypes.LogicalTypeFactory.class)));
   }
 
   public static void assertEqualsTrue(String message, Object o1, Object o2) {
diff --git 
a/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericLogicalTypes.java
 
b/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericLogicalTypes.java
index 593f759f8..272673cb3 100644
--- 
a/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericLogicalTypes.java
+++ 
b/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericLogicalTypes.java
@@ -18,9 +18,6 @@
 
 package org.apache.avro.generic;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
 import java.io.File;
 import java.io.IOException;
 import java.math.BigDecimal;
@@ -33,8 +30,10 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
+
 import org.apache.avro.Conversion;
 import org.apache.avro.Conversions;
+import org.apache.avro.CustomType;
 import org.apache.avro.LogicalType;
 import org.apache.avro.LogicalTypes;
 import org.apache.avro.Schema;
@@ -50,6 +49,11 @@ import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
 
+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.assertNotSame;
+
 public class TestGenericLogicalTypes {
 
   @TempDir
@@ -404,4 +408,53 @@ public class TestGenericLogicalTypes {
     Assertions.assertEquals(expected, 
read(GenericData.get().createDatumReader(timestampSchema), test),
         "Should read LocalDateTime as longs");
   }
+
+  @Test
+  public void testReadAutomaticallyRegisteredUri() throws IOException {
+    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));
+
+    CustomType ct1 = new CustomType("foo");
+    CustomType ct2 = new CustomType("bar");
+    List<CustomType> expected = Arrays.asList(ct1, ct2);
+
+    Conversion<CustomType> conversion = GENERIC.getConversionFor(customType);
+
+    // use the conversion directly instead of relying on the write side
+    CharSequence ct1String = conversion.toCharSequence(ct1, stringSchema, 
customType);
+    CharSequence ct2String = conversion.toCharSequence(ct2, stringSchema, 
customType);
+
+    File test = write(stringSchema, ct1String, ct2String);
+    assertEquals(expected, read(GENERIC.createDatumReader(customTypeSchema), 
test),
+        "Should convert string to CustomType");
+  }
+
+  @Test
+  public void testWriteAutomaticallyRegisteredUri() throws IOException {
+    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));
+
+    CustomType ct1 = new CustomType("foo");
+    CustomType ct2 = new CustomType("bar");
+
+    Conversion<CustomType> conversion = GENERIC.getConversionFor(customType);
+
+    // use the conversion directly instead of relying on the write side
+    CharSequence ct1String = conversion.toCharSequence(ct1, stringSchema, 
customType);
+    CharSequence ct2String = conversion.toCharSequence(ct2, stringSchema, 
customType);
+    List<CharSequence> expected = Arrays.asList(ct1String, ct2String);
+
+    File test = write(GENERIC, customTypeSchema, ct1, ct2);
+
+    // Note that this test still cannot read strings using the logical type
+    // schema, as all GenericData instances have the logical type and the
+    // conversions loaded. That's why this final assert is slightly different.
+
+    assertEquals(expected, 
read(GenericData.get().createDatumReader(stringSchema), test),
+        "Should read CustomType as strings");
+  }
 }
diff --git 
a/lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.LogicalTypes$LogicalTypeFactory
 
b/lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.Conversion
similarity index 95%
copy from 
lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.LogicalTypes$LogicalTypeFactory
copy to 
lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.Conversion
index e111a25c4..890ba7642 100644
--- 
a/lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.LogicalTypes$LogicalTypeFactory
+++ 
b/lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.Conversion
@@ -14,4 +14,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-org.apache.avro.DummyLogicalTypeFactory
+org.apache.avro.CustomTypeConverter
diff --git 
a/lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.LogicalTypes$LogicalTypeFactory
 
b/lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.LogicalTypes$LogicalTypeFactory
index e111a25c4..b55c233ae 100644
--- 
a/lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.LogicalTypes$LogicalTypeFactory
+++ 
b/lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.LogicalTypes$LogicalTypeFactory
@@ -14,4 +14,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-org.apache.avro.DummyLogicalTypeFactory
+org.apache.avro.CustomTypeLogicalTypeFactory

Reply via email to