diff --git a/CHANGELOG.md b/CHANGELOG.md index 55633856..af3afe7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # 1.2.8 +* Reduce archive size by removing unnecessary dependencies from the jar * Fix NPE on V1 client when Clickhouse has table with Array(Nested...) field # 1.2.7 diff --git a/build.gradle.kts b/build.gradle.kts index 3ddeb3ce..780d5c03 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -72,13 +72,9 @@ dependencies { implementation("com.clickhouse:clickhouse-http-client:${project.extra["clickHouseDriverVersion"]}") implementation("com.clickhouse:clickhouse-data:${project.extra["clickHouseDriverVersion"]}") implementation("com.clickhouse:client-v2:${project.extra["clickHouseDriverVersion"]}") - implementation("io.projectreactor:reactor-core:3.7.0") implementation("com.google.code.gson:gson:2.11.0") // https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5 implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1") - // https://mvnrepository.com/artifact/com.google.guava/guava - implementation("com.google.guava:guava:33.3.1-jre") - // Avoid telescoping constructors problem with the builder pattern using Lombok compileOnly("org.projectlombok:lombok:1.18.34") @@ -100,7 +96,6 @@ dependencies { Will in side the Confluent Archive */ clickhouseDependencies("org.apache.httpcomponents.client5:httpclient5:5.3.1") - clickhouseDependencies("io.lettuce:lettuce-core:6.5.0.RELEASE") clickhouseDependencies("com.clickhouse:clickhouse-client:${project.extra["clickHouseDriverVersion"]}") clickhouseDependencies("com.clickhouse:client-v2:${project.extra["clickHouseDriverVersion"]}") clickhouseDependencies("com.clickhouse:clickhouse-http-client:${project.extra["clickHouseDriverVersion"]}") diff --git a/src/main/java/com/clickhouse/kafka/connect/sink/db/mapping/Column.java b/src/main/java/com/clickhouse/kafka/connect/sink/db/mapping/Column.java index 251a739d..53f8b62a 100644 --- a/src/main/java/com/clickhouse/kafka/connect/sink/db/mapping/Column.java +++ b/src/main/java/com/clickhouse/kafka/connect/sink/db/mapping/Column.java @@ -8,9 +8,9 @@ import lombok.experimental.Accessors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import reactor.util.function.Tuple2; -import reactor.util.function.Tuple3; -import reactor.util.function.Tuples; +import com.clickhouse.kafka.connect.util.reactor.function.Tuple2; +import com.clickhouse.kafka.connect.util.reactor.function.Tuple3; +import com.clickhouse.kafka.connect.util.reactor.function.Tuples; import java.util.ArrayList; import java.util.Comparator; diff --git a/src/main/java/com/clickhouse/kafka/connect/util/reactor/function/Tuple2.java b/src/main/java/com/clickhouse/kafka/connect/util/reactor/function/Tuple2.java new file mode 100644 index 00000000..7ac8ba34 --- /dev/null +++ b/src/main/java/com/clickhouse/kafka/connect/util/reactor/function/Tuple2.java @@ -0,0 +1,169 @@ +package com.clickhouse.kafka.connect.util.reactor.function; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; + +/** + * A tuple that holds two non-null values. + * + * @param The type of the first non-null value held by this tuple + * @param The type of the second non-null value held by this tuple + * @author Jon Brisbin + * @author Stephane Maldini + */ +@SuppressWarnings("rawtypes") +public class Tuple2 implements Iterable, Serializable { + + private static final long serialVersionUID = -3518082018884860684L; + + final T1 t1; + final T2 t2; + + Tuple2(T1 t1, T2 t2) { + this.t1 = Objects.requireNonNull(t1, "t1"); + this.t2 = Objects.requireNonNull(t2, "t2"); + } + + /** + * Type-safe way to get the first object of this {@link Tuples}. + * + * @return The first object + */ + public T1 getT1() { + return t1; + } + + /** + * Type-safe way to get the second object of this {@link Tuples}. + * + * @return The second object + */ + public T2 getT2() { + return t2; + } + + /** + * Map the left-hand part (T1) of this {@link reactor.util.function.Tuple2} into a different value and type, + * keeping the right-hand part (T2). + * + * @param mapper the mapping {@link Function} for the left-hand part + * @param the new type for the left-hand part + * @return a new {@link reactor.util.function.Tuple2} with a different left (T1) value + */ + public com.clickhouse.kafka.connect.util.reactor.function.Tuple2 mapT1(Function mapper) { + return new com.clickhouse.kafka.connect.util.reactor.function.Tuple2<>(mapper.apply(t1), t2); + } + + /** + * Map the right-hand part (T2) of this {@link reactor.util.function.Tuple2} into a different value and type, + * keeping the left-hand part (T1). + * + * @param mapper the mapping {@link Function} for the right-hand part + * @param the new type for the right-hand part + * @return a new {@link reactor.util.function.Tuple2} with a different right (T2) value + */ + public com.clickhouse.kafka.connect.util.reactor.function.Tuple2 mapT2(Function mapper) { + return new com.clickhouse.kafka.connect.util.reactor.function.Tuple2<>(t1, mapper.apply(t2)); + } + + /** + * Get the object at the given index. + * + * @param index The index of the object to retrieve. Starts at 0. + * @return The object or {@literal null} if out of bounds. + */ + public Object get(int index) { + switch (index) { + case 0: + return t1; + case 1: + return t2; + default: + return null; + } + } + + /** + * Turn this {@code Tuple} into a {@link List List<Object>}. + * The list isn't tied to this Tuple but is a copy with limited + * mutability ({@code add} and {@code remove} are not supported, but {@code set} is). + * + * @return A copy of the tuple as a new {@link List List<Object>}. + */ + public List toList() { + return Arrays.asList(toArray()); + } + + /** + * Turn this {@code Tuple} into a plain {@code Object[]}. + * The array isn't tied to this Tuple but is a copy. + * + * @return A copy of the tuple as a new {@link Object Object[]}. + */ + public Object[] toArray() { + return new Object[]{t1, t2}; + } + + /** + * Return an immutable {@link Iterator Iterator<Object>} around + * the content of this {@code Tuple}. + * + * @implNote As an {@link Iterator} is always tied to its {@link Iterable} source by + * definition, the iterator cannot be mutable without the iterable also being mutable. + * Since {@link Tuples} are immutable, so is the {@link Iterator} + * returned by this method. + * + * @return An unmodifiable {@link Iterator} over the elements in this Tuple. + */ + @Override + public Iterator iterator() { + return Collections.unmodifiableList(toList()).iterator(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + com.clickhouse.kafka.connect.util.reactor.function.Tuple2 tuple2 = (com.clickhouse.kafka.connect.util.reactor.function.Tuple2) o; + + return t1.equals(tuple2.t1) && t2.equals(tuple2.t2); + + } + + @Override + public int hashCode() { + int result = size(); + result = 31 * result + t1.hashCode(); + result = 31 * result + t2.hashCode(); + return result; + } + + /** + * Return the number of elements in this {@literal Tuples}. + * + * @return The size of this {@literal Tuples}. + */ + public int size() { + return 2; + } + + /** + * A Tuple String representation is the comma separated list of values, enclosed + * in square brackets. + * @return the Tuple String representation + */ + @Override + public final String toString() { + return Tuples.tupleStringRepresentation(toArray()).insert(0, '[').append(']').toString(); + } +} diff --git a/src/main/java/com/clickhouse/kafka/connect/util/reactor/function/Tuple3.java b/src/main/java/com/clickhouse/kafka/connect/util/reactor/function/Tuple3.java new file mode 100644 index 00000000..bae59792 --- /dev/null +++ b/src/main/java/com/clickhouse/kafka/connect/util/reactor/function/Tuple3.java @@ -0,0 +1,113 @@ +package com.clickhouse.kafka.connect.util.reactor.function; + +import java.util.Objects; +import java.util.function.Function; + +/** + * A tuple that holds three non-null values. + * + * @param The type of the first non-null value held by this tuple + * @param The type of the second non-null value held by this tuple + * @param The type of the third non-null value held by this tuple + * @author Jon Brisbin + * @author Stephane Maldini + */ +public class Tuple3 extends Tuple2 { + + private static final long serialVersionUID = -4430274211524723033L; + + final T3 t3; + + Tuple3(T1 t1, T2 t2, T3 t3) { + super(t1, t2); + this.t3 = Objects.requireNonNull(t3, "t3"); + } + + /** + * Type-safe way to get the third object of this {@link Tuples}. + * + * @return The third object + */ + public T3 getT3() { + return t3; + } + + /** + * Map the 1st part (T1) of this {@link reactor.util.function.Tuple3} into a different value and type, + * keeping the other parts. + * + * @param mapper the mapping {@link Function} for the T1 part + * @param the new type for the T1 part + * @return a new {@link reactor.util.function.Tuple3} with a different T1 value + */ + public com.clickhouse.kafka.connect.util.reactor.function.Tuple3 mapT1(Function mapper) { + return new com.clickhouse.kafka.connect.util.reactor.function.Tuple3<>(mapper.apply(t1), t2, t3); + } + + /** + * Map the 2nd part (T2) of this {@link reactor.util.function.Tuple3} into a different value and type, + * keeping the other parts. + * + * @param mapper the mapping {@link Function} for the T2 part + * @param the new type for the T2 part + * @return a new {@link reactor.util.function.Tuple3} with a different T2 value + */ + public com.clickhouse.kafka.connect.util.reactor.function.Tuple3 mapT2(Function mapper) { + return new com.clickhouse.kafka.connect.util.reactor.function.Tuple3<>(t1, mapper.apply(t2), t3); + } + + /** + * Map the 3rd part (T3) of this {@link reactor.util.function.Tuple3} into a different value and type, + * keeping the other parts. + * + * @param mapper the mapping {@link Function} for the T3 part + * @param the new type for the T3 part + * @return a new {@link reactor.util.function.Tuple3} with a different T3 value + */ + public com.clickhouse.kafka.connect.util.reactor.function.Tuple3 mapT3(Function mapper) { + return new com.clickhouse.kafka.connect.util.reactor.function.Tuple3<>(t1, t2, mapper.apply(t3)); + } + + @Override + public Object get(int index) { + switch (index) { + case 0: + return t1; + case 1: + return t2; + case 2: + return t3; + default: + return null; + } + } + + @Override + public Object[] toArray() { + return new Object[]{t1, t2, t3}; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof com.clickhouse.kafka.connect.util.reactor.function.Tuple3)) return false; + if (!super.equals(o)) return false; + + @SuppressWarnings("rawtypes") + com.clickhouse.kafka.connect.util.reactor.function.Tuple3 tuple3 = (com.clickhouse.kafka.connect.util.reactor.function.Tuple3) o; + + return t3.equals(tuple3.t3); + } + + @Override + public int size() { + return 3; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + t3.hashCode(); + return result; + } +} diff --git a/src/main/java/com/clickhouse/kafka/connect/util/reactor/function/Tuples.java b/src/main/java/com/clickhouse/kafka/connect/util/reactor/function/Tuples.java new file mode 100644 index 00000000..fa3b30db --- /dev/null +++ b/src/main/java/com/clickhouse/kafka/connect/util/reactor/function/Tuples.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2016-2021 VMware Inc. or its affiliates, All Rights Reserved. + * + * Licensed 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 com.clickhouse.kafka.connect.util.reactor.function; + +import java.util.Collection; +import java.util.function.Function; + +/** + * A {@literal Tuples} is an immutable {@link Collection} of objects, each of which can be of an arbitrary type. + * + * @author Jon Brisbin + * @author Stephane Maldini + */ +@SuppressWarnings({"rawtypes"}) +public abstract class Tuples implements Function { + + /** + * Create a {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple2} with the given array if it is small + * enough to fit inside a {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple2} to {@link Tuple3}. + * + * @param list the content of the Tuple (size 1 to 8) + * @return The new {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple2}. + * @throws IllegalArgumentException if the array is not of length 1-8 + */ + public static com.clickhouse.kafka.connect.util.reactor.function.Tuple2 fromArray(Object[] list) { + //noinspection ConstantConditions + if (list == null || list.length < 2) { + throw new IllegalArgumentException("null or too small array, need between 2 and 8 values"); + } + + switch (list.length){ + case 2: + return of(list[0], list[1]); + case 3: + return of(list[0], list[1], list[2]); + } + throw new IllegalArgumentException("too many arguments ("+ list.length + "), need between 2 and 8 values"); + } + + /** + * Create a {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple2} with the given objects. + * + * @param t1 The first value in the tuple. Not null. + * @param t2 The second value in the tuple. Not null. + * @param The type of the first value. + * @param The type of the second value. + * @return The new {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple2}. + */ + public static com.clickhouse.kafka.connect.util.reactor.function.Tuple2 of(T1 t1, T2 t2) { + return new com.clickhouse.kafka.connect.util.reactor.function.Tuple2<>(t1, t2); + } + + /** + * Create a {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple3} with the given objects. + * + * @param t1 The first value in the tuple. Not null. + * @param t2 The second value in the tuple. Not null. + * @param t3 The third value in the tuple. Not null. + * @param The type of the first value. + * @param The type of the second value. + * @param The type of the third value. + * @return The new {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple3}. + */ + public static com.clickhouse.kafka.connect.util.reactor.function.Tuple3 of(T1 t1, T2 t2, T3 t3) { + return new com.clickhouse.kafka.connect.util.reactor.function.Tuple3<>(t1, t2, t3); + } + + /** + * A converting function from Object array to {@link Tuples} + * + * @return The unchecked conversion function to {@link Tuples}. + */ + @SuppressWarnings("unchecked") + public static Function fnAny() { + return empty; + } + + /** + * A converting function from Object array to {@link Tuples} to R. + * + * @param The type of the return value. + * @param delegate the function to delegate to + * + * @return The unchecked conversion function to R. + */ + public static Function fnAny(final Function delegate) { + return objects -> delegate.apply(Tuples.fnAny().apply(objects)); + } + + /** + * A converting function from Object array to {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple2} + * + * @param The type of the first value. + * @param The type of the second value. + * + * @return The unchecked conversion function to {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple2}. + */ + @SuppressWarnings("unchecked") + public static Function> fn2() { + return empty; + } + + + /** + * A converting function from Object array to {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple3} + * + * @param The type of the first value. + * @param The type of the second value. + * @param The type of the third value. + * + * @return The unchecked conversion function to {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple3}. + */ + @SuppressWarnings("unchecked") + public static Function> fn3() { + return empty; + } + + /** + * A converting function from Object array to {@link com.clickhouse.kafka.connect.util.reactor.function.Tuple3} to R. + * + * @param The type of the first value. + * @param The type of the second value. + * @param The type of the third value. + * @param The type of the return value. + * @param delegate the function to delegate to + * + * @return The unchecked conversion function to R. + */ + public static Function fn3(final Function, R> delegate) { + return objects -> delegate.apply(Tuples.fn3().apply(objects)); + } + + @Override + public Tuple2 apply(Object o) { + return fromArray((Object[])o); + } + + /** + * Prepare a string representation of the values suitable for a Tuple of any + * size by accepting an array of elements. This builds a {@link StringBuilder} + * containing the String representation of each object, comma separated. It manages + * nulls as well by putting an empty string and the comma. + * + * @param values the values of the tuple to represent + * @return a {@link StringBuilder} initialized with the string representation of the + * values in the Tuple. + */ + static StringBuilder tupleStringRepresentation(Object... values) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < values.length; i++) { + Object t = values[i]; + if (i != 0) { + sb.append(','); + } + if (t != null) { + sb.append(t); + } + } + return sb; + } + + + static final Tuples empty = new Tuples(){}; + + Tuples(){} +}