blob: 216e34cc9d738e10c77712d3e09880d95daab521 [file]
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>be-java-extensions</artifactId>
<groupId>org.apache.doris</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hive-apache-shade</artifactId>
<packaging>jar</packaging>
<name>Doris BE Java Extensions - Hive Apache Shade</name>
<description>
Hive as Trino repackages it, holding one copy of Hive's storage API rather than two.
io.trino.hive:hive-apache carries its own copy of the ~104 classes that Hive also publishes
standalone as org.apache.hive:hive-storage-api - the column vectors, search arguments and
Hive value types that a reader touches on every row. A plugin that reads Hudi needs both
jars: hive-apache for the serdes and object inspectors, hive-storage-api because ORC and
Hudi are compiled against it and call methods that only the newer standalone artifact has
(TimestampColumnVector.changeCalendar, VectorizedRowBatch as a MutableFilterContext).
With both jars in a plugin directory, which copy answers is decided by the order the plugin
classloader reads the directory in - and the older one sorts first. Before isolation the
same collision was resolved per class by whichever copy a fat jar assembly happened to
unpack last, which is why a Hudi table on ORC works today and would not afterwards.
So the two are merged here into one jar, with the standalone artifact's copies kept, and
HiveApacheShadeTest asserts exactly that of the jar this module produces.
</description>
<properties>
<hive-apache.version>3.1.2-22</hive-apache.version>
<hive-storage-api.version>2.8.1</hive-storage-api.version>
<!-- The module's own class output, so a reactor build sees the merged tree the
same way it sees compiled sources - before any jar exists. -->
<merged.classes>${project.build.outputDirectory}</merged.classes>
<source.jars>${project.build.directory}/source-jars</source.jars>
</properties>
<dependencies>
<!--
Both are optional with everything excluded, the way hive-udf-shade declares its source:
the classes are baked into this module's jar, so a consumer must not resolve either
artifact again - that would put the second copy right back into its plugin directory.
-->
<dependency>
<groupId>io.trino.hive</groupId>
<artifactId>hive-apache</artifactId>
<version>${hive-apache.version}</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-storage-api</artifactId>
<version>${hive-storage-api.version}</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--
Not optional, and the only one: hive's date and time handling is written against joda,
which is what hive-apache brings along and a consumer therefore still needs.
-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.8.1</version>
</dependency>
</dependencies>
<build>
<finalName>hive-apache-shade</finalName>
<directory>${project.basedir}/target/</directory>
<plugins>
<!--
The two unpacks below MERGE into a directory that build.sh does not clean: it runs
`mvn package` without `clean`, so whatever the previous build left in target/classes
is still there. maven-dependency-plugin only ever adds, so a version bump would leave
the old hive's classes beside the new one's - two hive versions in one jar, and all
three tests still green, because they only look at classes the NEW jars also carry.
The META-INF/maven exclusion on each unpack has the same hole: it stops the entry from
being written again, not from surviving.
So the merge starts from an empty directory, every time. Bound to generate-resources,
which is the phase before the unpacks, and scoped to this one directory rather than
the whole of target/ so that an incremental build keeps everything else.
-->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<executions>
<execution>
<id>empty-merged-classes-before-unpack</id>
<phase>generate-resources</phase>
<goals>
<goal>clean</goal>
</goals>
<configuration>
<excludeDefaultDirectories>true</excludeDefaultDirectories>
<filesets>
<fileset>
<directory>${merged.classes}</directory>
</fileset>
</filesets>
</configuration>
</execution>
</executions>
</plugin>
<!--
The merge, stated as an order rather than as a list of classes: unpack the repackaged
hive, then unpack the standalone storage API on top of it. The overlapping classes are
whichever ones the second unpack happens to bring, so bumping either version keeps
working without anyone editing a list here - and the shade plugin was the wrong tool
for this precisely because its order is not something a pom can state (it keeps the
first copy it meets, walking dependencies by groupId).
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-repackaged-hive</id>
<phase>process-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>io.trino.hive</groupId>
<artifactId>hive-apache</artifactId>
<version>${hive-apache.version}</version>
<overWrite>true</overWrite>
<outputDirectory>${merged.classes}</outputDirectory>
<!--
Everything BUT the source artifacts' maven coordinates. Unpacking
two jars over each other merges their META-INF/ as well, and
META-INF/maven/<g>/<a>/pom.properties is what an SBOM or CVE scanner
reads a jar's identity from - so this 34MB jar, which carries the
whole of hive 3.1.2-22, would be reported as whichever of the two
unpacked last. META-INF/services is deliberately kept: the
FileSystem service file is what redirects file:// to hive's
ProxyLocalFileSystem, which the hudi reader depends on.
-->
<excludes>META-INF/maven/**</excludes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
<!-- Hands the test the two jars it compares the merged tree against. -->
<execution>
<id>copy-source-artifacts</id>
<phase>process-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${source.jars}</outputDirectory>
<artifactItems>
<artifactItem>
<groupId>io.trino.hive</groupId>
<artifactId>hive-apache</artifactId>
<version>${hive-apache.version}</version>
</artifactItem>
<artifactItem>
<groupId>org.apache.hive</groupId>
<artifactId>hive-storage-api</artifactId>
<version>${hive-storage-api.version}</version>
</artifactItem>
</artifactItems>
</configuration>
</execution>
<execution>
<id>unpack-standalone-storage-api</id>
<phase>process-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.apache.hive</groupId>
<artifactId>hive-storage-api</artifactId>
<version>${hive-storage-api.version}</version>
<overWrite>true</overWrite>
<outputDirectory>${merged.classes}</outputDirectory>
<!-- See the note on the first unpack. -->
<excludes>META-INF/maven/**</excludes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<merged.classes>${merged.classes}</merged.classes>
<source.jars>${source.jars}</source.jars>
</systemPropertyVariables>
</configuration>
</plugin>
<!--
The merged tree is what this module packages; it has no sources of its own. Both
jars' signatures are dropped with them - a repackaged jar is not the signed one.
-->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>