You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by rs...@apache.org on 2022/03/18 19:20:12 UTC
[avro] branch master updated: AVRO-3441: ServiceLoader for LogicalTypeFactory (#1590)
This is an automated email from the ASF dual-hosted git repository.
rskraba pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/master by this push:
new ee4725c AVRO-3441: ServiceLoader for LogicalTypeFactory (#1590)
ee4725c is described below
commit ee4725c64807549ec74e20e83d35cfc1fe8e90a8
Author: Oscar Westra van Holthe - Kind <op...@users.noreply.github.com>
AuthorDate: Fri Mar 18 20:18:52 2022 +0100
AVRO-3441: ServiceLoader for LogicalTypeFactory (#1590)
Automatically register LogicalTypeFactory classes using the Java 6
service loader upon startup. This works for any LogicalTypeFactory that
does not need constructor parameters.
---
.../main/java/org/apache/avro/LogicalTypes.java | 23 +++++++++++++++++
.../org/apache/avro/DummyLogicalTypeFactory.java | 30 ++++++++++++++++++++++
.../test/java/org/apache/avro/TestLogicalType.java | 19 ++++++++++----
...org.apache.avro.LogicalTypes$LogicalTypeFactory | 17 ++++++++++++
4 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/lang/java/avro/src/main/java/org/apache/avro/LogicalTypes.java b/lang/java/avro/src/main/java/org/apache/avro/LogicalTypes.java
index 5b03e15..7bb00f8 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/LogicalTypes.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/LogicalTypes.java
@@ -21,6 +21,7 @@ package org.apache.avro;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
+import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
@@ -30,6 +31,22 @@ public class LogicalTypes {
private static final Logger LOG = LoggerFactory.getLogger(LogicalTypes.class);
+ /**
+ * Factory interface and SPI for logical types. A {@code LogicalTypeFactory} can
+ * be registered in two ways:
+ *
+ * <ol>
+ * <li>Manually, via {@link #register(LogicalTypeFactory)} or
+ * {@link #register(String, LogicalTypeFactory)}</li>
+ *
+ * <li>Automatically, when the {@code LogicalTypeFactory} implementation is a
+ * public class with a public no-arg constructor, is named in a file called
+ * {@code /META-INF/services/org.apache.avro.LogicalTypes$LogicalTypeFactory},
+ * and both are available in the classpath</li>
+ * </ol>
+ *
+ * @see ServiceLoader
+ */
public interface LogicalTypeFactory {
LogicalType fromSchema(Schema schema);
@@ -40,6 +57,12 @@ public class LogicalTypes {
private static final Map<String, LogicalTypeFactory> REGISTERED_TYPES = new ConcurrentHashMap<>();
+ static {
+ for (LogicalTypeFactory logicalTypeFactory : ServiceLoader.load(LogicalTypeFactory.class)) {
+ register(logicalTypeFactory);
+ }
+ }
+
/**
* Register a logical type.
*
diff --git a/lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java b/lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java
new file mode 100644
index 0000000..4957e37
--- /dev/null
+++ b/lang/java/avro/src/test/java/org/apache/avro/DummyLogicalTypeFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.avro;
+
+public class DummyLogicalTypeFactory implements LogicalTypes.LogicalTypeFactory {
+ @Override
+ public LogicalType fromSchema(Schema schema) {
+ return LogicalTypes.date();
+ }
+
+ @Override
+ public String getTypeName() {
+ return "service-example";
+ }
+}
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 7b1f5bf..deadb2e 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
@@ -26,6 +26,9 @@ import org.hamcrest.collection.IsMapContaining;
import org.junit.Assert;
import org.junit.Test;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.instanceOf;
+
public class TestLogicalType {
@Test
@@ -285,14 +288,20 @@ public class TestLogicalType {
IsMapContaining.hasEntry("logicalTypeName", factory));
}
+ @Test
+ public void testRegisterLogicalTypeFactoryByServiceLoader() {
+ MatcherAssert.assertThat(LogicalTypes.getCustomRegisteredTypes(),
+ IsMapContaining.hasEntry(equalTo("service-example"), instanceOf(LogicalTypes.LogicalTypeFactory.class)));
+ }
+
public static void assertEqualsTrue(String message, Object o1, Object o2) {
- Assert.assertTrue("Should be equal (forward): " + message, o1.equals(o2));
- Assert.assertTrue("Should be equal (reverse): " + message, o2.equals(o1));
+ Assert.assertEquals("Should be equal (forward): " + message, o1, o2);
+ Assert.assertEquals("Should be equal (reverse): " + message, o2, o1);
}
public static void assertEqualsFalse(String message, Object o1, Object o2) {
- Assert.assertFalse("Should be equal (forward): " + message, o1.equals(o2));
- Assert.assertFalse("Should be equal (reverse): " + message, o2.equals(o1));
+ Assert.assertNotEquals("Should be equal (forward): " + message, o1, o2);
+ Assert.assertNotEquals("Should be equal (reverse): " + message, o2, o1);
}
/**
@@ -305,7 +314,7 @@ public class TestLogicalType {
* @param callable A Callable that is expected to throw the exception
*/
public static void assertThrows(String message, Class<? extends Exception> expected, String containedInMessage,
- Callable callable) {
+ Callable<?> callable) {
try {
callable.call();
Assert.fail("No exception was thrown (" + message + "), expected: " + expected.getName());
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
new file mode 100644
index 0000000..e111a25
--- /dev/null
+++ b/lang/java/avro/src/test/resources/META-INF/services/org.apache.avro.LogicalTypes$LogicalTypeFactory
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+org.apache.avro.DummyLogicalTypeFactory