This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 9f0101ec14 GH-40878: [JAVA] Fix flight-sql-jdbc-driver shading issues
(#40879)
9f0101ec14 is described below
commit 9f0101ec14336b2baad45d57320fb56c71d9321b
Author: Laurent Goujon <[email protected]>
AuthorDate: Fri Mar 29 18:29:21 2024 -0700
GH-40878: [JAVA] Fix flight-sql-jdbc-driver shading issues (#40879)
### Rationale for this change
The `flight-sql-jdbc-driver` jar is not shaded properly:
* a reduced pom.xml file is not generated. The published pom.xml file
declares dependencies which are actually present in the jar and should not be
fetched externally
* several classes/files are not relocated properly
### What changes are included in this PR?
Fix pom.xml and relocations. Also removes annotations dependencies and
include a integration test to prevent future breakage.
### Are these changes tested?
Yes. A new integration test check the jar content
### Are there any user-facing changes?
Yes. The published pom.xml file on Maven will be cleaned of any dependency
* GitHub Issue: #40878
Authored-by: Laurent Goujon <[email protected]>
Signed-off-by: David Li <[email protected]>
---
java/flight/flight-sql-jdbc-driver/pom.xml | 51 ++++++--
.../arrow/driver/jdbc/ITDriverJarValidation.java | 141 +++++++++++++++++++++
2 files changed, 184 insertions(+), 8 deletions(-)
diff --git a/java/flight/flight-sql-jdbc-driver/pom.xml
b/java/flight/flight-sql-jdbc-driver/pom.xml
index 84ec1ff8c1..53d929afa7 100644
--- a/java/flight/flight-sql-jdbc-driver/pom.xml
+++ b/java/flight/flight-sql-jdbc-driver/pom.xml
@@ -148,13 +148,16 @@
<build>
<plugins>
<plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <enableAssertions>false</enableAssertions>
- <systemPropertyVariables>
-
<arrow.test.dataRoot>${project.basedir}/../../../testing/data</arrow.test.dataRoot>
- </systemPropertyVariables>
- </configuration>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -167,12 +170,22 @@
</goals>
<configuration>
<shadedArtifactAttached>false</shadedArtifactAttached>
-
<createDependencyReducedPom>false</createDependencyReducedPom>
+
<createDependencyReducedPom>true</createDependencyReducedPom>
<minimizeJar>false</minimizeJar>
<artifactSet>
<includes>
<include>*:*</include>
</includes>
+ <excludes>
+ <!-- Source annotations -->
+
<exclude>org.checkerframework:checker-qual</exclude>
+
<exclude>org.codehaus.mojo:animal-sniffer-annotations</exclude>
+
<exclude>javax.annotation:javax.annotation-api</exclude>
+
<exclude>com.google.android:annotations</exclude>
+
<exclude>com.google.errorprone:error_prone_annotations</exclude>
+
<exclude>com.google.code.findbugs:jsr305</exclude>
+
<exclude>com.google.j2objc:j2objc-annotations</exclude>
+ </excludes>
</artifactSet>
<relocations>
<relocation>
@@ -199,6 +212,14 @@
<pattern>io.</pattern>
<shadedPattern>cfjd.io.</shadedPattern>
</relocation>
+ <relocation>
+ <pattern>net.</pattern>
+ <shadedPattern>cfjd.net.</shadedPattern>
+ </relocation>
+ <relocation>
+ <pattern>mozilla.</pattern>
+
<shadedPattern>cfjd.mozilla.</shadedPattern>
+ </relocation>
<!-- Entries to relocate netty native
libraries -->
<relocation>
<pattern>META-INF.native.libnetty_</pattern>
@@ -213,12 +234,25 @@
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
<filters>
+ <filter>
+
<artifact>org.apache.arrow:arrow-vector</artifact>
+ <excludes>
+ <exclude>codegen/**</exclude>
+ </excludes>
+ </filter>
<filter>
<artifact>org.apache.calcite.avatica:*</artifact>
<excludes>
<exclude>META-INF/services/java.sql.Driver</exclude>
</excludes>
</filter>
+ <filter>
+
<artifact>org.eclipse.collections:*</artifact>
+ <excludes>
+ <exclude>about.html</exclude>
+ <exclude>LICENSE-*-1.0.txt</exclude>
+ </excludes>
+ </filter>
<filter>
<artifact>*:*</artifact>
<excludes>
@@ -227,6 +261,7 @@
<exclude>**/*.DSA</exclude>
<exclude>META-INF/native/libio_grpc_netty*</exclude>
<exclude>META-INF/native/io_grpc_netty_shaded*</exclude>
+ <exclude>**/*.proto</exclude>
</excludes>
</filter>
</filters>
diff --git
a/java/flight/flight-sql-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/ITDriverJarValidation.java
b/java/flight/flight-sql-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/ITDriverJarValidation.java
new file mode 100644
index 0000000000..fdb580d493
--- /dev/null
+++
b/java/flight/flight-sql-jdbc-driver/src/test/java/org/apache/arrow/driver/jdbc/ITDriverJarValidation.java
@@ -0,0 +1,141 @@
+/*
+ * 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
+ *
+ * http://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.arrow.driver.jdbc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Check the content of the JDBC driver jar
+ *
+ * After shading everything should be either under
org.apache.arrow.driver.jdbc.,
+ * org.slf4j., or cfjd. packages
+ */
+public class ITDriverJarValidation {
+ /**
+ * Use this property to provide path to the JDBC driver jar. Can be used to
run the test from an IDE
+ */
+ public static final String JDBC_DRIVER_PATH_OVERRIDE =
+ System.getProperty("arrow-flight-jdbc-driver.jar.override");
+
+ /**
+ * List of allowed prefixes a jar entry may match.
+ */
+ public static final Set<String> ALLOWED_PREFIXES = ImmutableSet.of(
+ "org/apache/arrow/driver/jdbc/",
+ "cfjd/",
+ "org/slf4j/",
+ "META-INF/");
+
+ /**
+ * List of allowed files a jar entry may match.
+ */
+ public static final Set<String> ALLOWED_FILES = ImmutableSet.of(
+ "arrow-git.properties",
+ "properties/flight.properties");
+
+ // This method is designed to work with Maven failsafe plugin and expects the
+ // JDBC driver jar to be present in the test classpath (instead of the
individual classes)
+ private static JarFile getJdbcJarFile() throws IOException {
+ // Check if an override has been set
+ if (JDBC_DRIVER_PATH_OVERRIDE != null) {
+ return new JarFile(new File(JDBC_DRIVER_PATH_OVERRIDE));
+ }
+
+ // Check classpath to find the driver jar
+ URL driverClassURL = ITDriverJarValidation.class.getClassLoader()
+
.getResource("org/apache/arrow/driver/jdbc/ArrowFlightJdbcDriver.class");
+
+ assertNotNull(driverClassURL, "Driver jar was not detected in the
classpath");
+ assertEquals("Driver jar was not detected in the classpath", "jar",
driverClassURL.getProtocol());
+
+ JarURLConnection connection = (JarURLConnection)
driverClassURL.openConnection();
+ return connection.getJarFile();
+ }
+
+ @ClassRule
+ public static final TestRule CLASS_TIMEOUT =
Timeout.builder().withTimeout(2, TimeUnit.MINUTES).build();
+
+ @Rule
+ public ErrorCollector collector = new ErrorCollector();
+
+ @Test
+ public void validateShadedJar() throws IOException {
+ // Validate the content of the jar to enforce all 3rd party dependencies
have
+ // been shaded
+ try (JarFile jar = getJdbcJarFile()) {
+ for (Enumeration<JarEntry> entries = jar.entries();
entries.hasMoreElements();) {
+ final JarEntry entry = entries.nextElement();
+ if (entry.isDirectory()) {
+ // Directories are ignored
+ continue;
+ }
+
+ try {
+ checkEntryAllowed(entry.getName());
+ } catch (AssertionError e) {
+ collector.addError(e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if a jar entry is allowed.
+ *
+ * <p>
+ * A jar entry is allowed if either it is part of the allowed files or it
+ * matches one of the allowed prefixes
+ *
+ * @param name the jar entry name
+ * @throws AssertionException if the entry is not allowed
+ */
+ private void checkEntryAllowed(String name) {
+ // Check if there's a matching file entry first
+ if (ALLOWED_FILES.contains(name)) {
+ return;
+ }
+
+ for (String prefix : ALLOWED_PREFIXES) {
+ if (name.startsWith(prefix)) {
+ return;
+ }
+ }
+
+ throw new AssertionError("'" + name + "' is not an allowed jar entry");
+ }
+}