Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
744ac0c
[kafka] Use the DDL table contract in Metadata
gyang94 Sep 10, 2026
c0c3816
[kafka] Discover qualified topics and isolate missing databases
gyang94 Sep 17, 2026
1ed86e1
[kafka] Preserve Metadata regressions on the updated PR03 base
gyang94 Oct 10, 2026
2c7e03d
[test] Wait for coordinator metadata before snapshot lease retry
gyang94 Oct 12, 2026
a23937d
[kafka] Apply persisted topic enablement to Metadata
gyang94 Oct 12, 2026
993d234
[kafka] Give topic aliases distinct stable wire IDs
gyang94 Oct 12, 2026
dcec633
[kafka] Validate Metadata against the updated PR03 contract
gyang94 Oct 14, 2026
5275f90
[kafka] Simplify Metadata wiring and regression tests
gyang94 Oct 14, 2026
ffdefa3
[kafka] Adapt Metadata tests to merged DDL configuration
gyang94 Oct 19, 2026
4c70505
[kafka] Rename default database topic ID namespace
gyang94 Oct 19, 2026
d20cf7c
[kafka] Add independently testable Produce protocol handling
gyang94 Sep 10, 2026
c568cd5
[kafka] Validate Produce batch offsets and stream compressed records
gyang94 Sep 17, 2026
91ef63c
[kafka] Preserve batch timestamp types in Produce commands
gyang94 Oct 10, 2026
a565b8a
[kafka] Verify Produce topic aliases preserve request names
gyang94 Oct 12, 2026
28e43ef
[kafka] Transcode mapped raw and string records to Arrow
gyang94 Sep 10, 2026
3762f51
[kafka] Stream record transcoding and reuse owned payloads
gyang94 Sep 17, 2026
ea5dc34
[kafka] Encode timestamp metadata as UTC TIMESTAMP values
gyang94 Sep 21, 2026
8b0a9c6
[kafka] Transcode binary and string into fixed system columns
gyang94 Oct 12, 2026
706ea4d
[kafka] Preserve metadata rejection on the updated PR05 base
gyang94 Oct 14, 2026
dfa5746
[kafka] Transcode three-field metadata from Produce records
gyang94 Oct 14, 2026
6985a0d
[kafka] Align Produce transcoding with current schema contract
gyang94 Oct 19, 2026
7c76aa2
[kafka] Connect Produce to native Fluss append
gyang94 Sep 10, 2026
78b4ac3
[kafka] Cache Produce plans and bound conversion execution
gyang94 Sep 17, 2026
e0ed833
[kafka] Skip null Produce values with write authorization
gyang94 Sep 21, 2026
5951011
[kafka] Verify Produce boundaries on the updated FIP base
gyang94 Oct 10, 2026
b2c1d53
[kafka] Apply persisted table contracts to Produce append
gyang94 Oct 12, 2026
8d5e234
[kafka] Wait for replicas before no-ack Produce tests
gyang94 Oct 14, 2026
0d41535
[kafka] Decouple Produce append from delayed fetch wakeups
gyang94 Oct 16, 2026
0a2b80c
[kafka] Persist null Produce values with native offsets
gyang94 Oct 16, 2026
fdaba29
[kafka] Align Produce plan with current metadata API
gyang94 Oct 19, 2026
8ca2825
[kafka] Drain Produce RPCs before closing event loops
gyang94 Oct 19, 2026
06cec44
[kafka] Cover Produce lifecycle and replication regressions
gyang94 Sep 11, 2026
16198b6
[kafka] Cover online leader handoff and qualified topics
gyang94 Sep 18, 2026
7f8b7e2
[kafka] Verify null value filtering with native raw and string readback
gyang94 Sep 21, 2026
241fc68
[kafka] Wait for bucket readiness in Produce round trips
gyang94 Oct 10, 2026
3993692
[kafka] Validate Produce contracts with isolated client matrix
gyang94 Oct 12, 2026
2410d04
[kafka] Verify metadata across schema changes and leader recovery
gyang94 Oct 15, 2026
6609679
[kafka] Verify null-value persistence and native offsets
gyang94 Oct 16, 2026
3590ef0
[kafka] Keep focused Produce integration regressions
gyang94 Oct 16, 2026
a39b974
[kafka] Use typed conversion options in regression tests
gyang94 Oct 19, 2026
72ca847
[kafka] Test nullable key schema validation
gyang94 Oct 19, 2026
50abb2d
[kafka] Separate value decoding and preserve record metadata
gyang94 Sep 11, 2026
4a74342
[kafka] Add strict JSON scalar conversion
gyang94 Sep 11, 2026
238ac26
[kafka] Fix JSON scalar and timestamp boundary conversions
gyang94 Sep 20, 2026
aa6158f
[kafka] Reuse public JSON schema validation for scalar converters
gyang94 Oct 12, 2026
3c4662f
[kafka] Cover JSON scalar edge cases on the updated FIP base
gyang94 Oct 15, 2026
e5dfff2
[kafka] Enable schema-aware JSON Produce for scalar tables
gyang94 Sep 11, 2026
54eed7c
[kafka] Bound JSON parsing and preserve floating-point zero
gyang94 Sep 20, 2026
18afb5e
[kafka] Verify JSON null filtering and timestamp readback
gyang94 Sep 21, 2026
025c590
[kafka] Align JSON schema test metadata with TIMESTAMP contract
gyang94 Sep 21, 2026
0c5c2ff
[kafka] Support flat and nested JSON table contracts
gyang94 Oct 12, 2026
933ac05
[kafka] Verify JSON metadata and floating-point boundary contracts
gyang94 Oct 15, 2026
4f41194
[kafka] Verify JSON null persistence on the updated base
gyang94 Oct 16, 2026
dc3d305
[kafka] Align JSON Produce tests with current table contracts
gyang94 Oct 19, 2026
acdc53e
[kafka] Support nested JSON values with resource bounds
gyang94 Sep 11, 2026
0d56349
[kafka] Bound nested JSON containers during parsing
gyang94 Sep 20, 2026
e3918d2
[kafka] Format JSON produce integration test
gyang94 Oct 12, 2026
8312648
[kafka] Align complex JSON conversion with public table contracts
gyang94 Oct 12, 2026
4771eeb
[test] Preserve complex JSON contracts after metadata migration
gyang94 Oct 15, 2026
ea3d602
[test] Verify complex JSON null persistence and constraints
gyang94 Oct 16, 2026
a714648
[test] Align complex JSON tests with nullable schema contract
gyang94 Oct 19, 2026
f7d8a9b
[kafka] Preserve unknown JSON fields in an optional rescue column
gyang94 Sep 11, 2026
7c191b2
[kafka] Reject lossy JSON values before rescue encoding
gyang94 Sep 20, 2026
c0faa88
[kafka] Rescue nullable JSON type errors without hiding validation fa…
gyang94 Sep 21, 2026
1ce2df9
[kafka] Keep rescue limited to unknown JSON fields
gyang94 Oct 10, 2026
8eb4d44
[kafka] Align rescue with the fixed Kafka table contract
gyang94 Oct 12, 2026
691d9c9
[test] Verify rescue with three-field Kafka metadata
gyang94 Oct 16, 2026
b51254e
[test] Verify rescue with persisted null Kafka values
gyang94 Oct 16, 2026
697bb68
[test] Keep Kafka metadata nullable in schema fixture
gyang94 Oct 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@

import org.apache.fluss.client.Connection;
import org.apache.fluss.client.ConnectionFactory;
import org.apache.fluss.client.FlussConnection;
import org.apache.fluss.client.metadata.KvSnapshotMetadata;
import org.apache.fluss.client.metadata.KvSnapshots;
import org.apache.fluss.client.metadata.MetadataUpdater;
import org.apache.fluss.client.metadata.TestingMetadataUpdater;
import org.apache.fluss.client.table.Table;
import org.apache.fluss.client.table.writer.AppendWriter;
Expand Down Expand Up @@ -1211,19 +1213,24 @@ void testKvSnapshotLeaseAfterCoordinatorServerRestart() throws Exception {
assertThat(zkClient.getKvSnapshotLeaseMetadata(lease.leaseId())).isPresent();

restartCoordinatorServer(zkClient);
FLUSS_CLUSTER_EXTENSION.waitUntilAllGatewayHasSameMetadata();

lease.dropLease().get();
assertThat(zkClient.getKvSnapshotLeaseMetadata(lease.leaseId())).isNotPresent();
}

private void restartCoordinatorServer(ZooKeeperClient zkClient) throws Exception {
MetadataUpdater metadataUpdater = ((FlussConnection) conn).getMetadataUpdater();
ServerNode cachedCoordinator = metadataUpdater.getCoordinatorServer();
FLUSS_CLUSTER_EXTENSION.stopCoordinatorServer();
waitUntil(
() -> !zkClient.getCoordinatorLeaderAddress().isPresent(),
Duration.ofMinutes(1),
"Coordinator server node still exists in ZooKeeper");
FLUSS_CLUSTER_EXTENSION.startCoordinatorServer();
// Election completes before the new coordinator address reaches every tablet server.
// Wait for server metadata to converge so that the client's retry can discover it.
FLUSS_CLUSTER_EXTENSION.waitUntilAllGatewayHasSameMetadata();
// Keep the client cache stale to exercise the lease's metadata refresh and retry.
assertThat(metadataUpdater.getCoordinatorServer()).isEqualTo(cachedCoordinator);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,8 @@ public long toEpochMicros() {

/** Converts this {@link TimestampNtz} object to a {@link LocalDateTime}. */
public LocalDateTime toLocalDateTime() {
int date = (int) (millisecond / MILLIS_PER_DAY);
long time = millisecond % MILLIS_PER_DAY;
if (time < 0) {
--date;
time += MILLIS_PER_DAY;
}
long date = Math.floorDiv(millisecond, MILLIS_PER_DAY);
long time = Math.floorMod(millisecond, MILLIS_PER_DAY);
long nanoOfDay = time * 1_000_000L + nanoOfMillisecond;
LocalDate localDate = LocalDate.ofEpochDay(date);
LocalTime localTime = LocalTime.ofNanoOfDay(nanoOfDay);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ public TimestampLtz getTimestampLtz(int i, int precision) {
return TimestampLtz.fromEpochMillis(((TimeStampMilliVector) valueVector).get(i));
} else if (valueVector instanceof TimeStampMicroVector) {
long micros = ((TimeStampMicroVector) valueVector).get(i);
return TimestampLtz.fromEpochMillis(micros / 1000, (int) (micros % 1000) * 1000);
return TimestampLtz.fromEpochMillis(
Math.floorDiv(micros, 1_000L), (int) Math.floorMod(micros, 1_000L) * 1_000);
} else {
long nanos = ((TimeStampNanoVector) valueVector).get(i);
return TimestampLtz.fromEpochMillis(nanos / 1_000_000, (int) (nanos % 1_000_000));
return TimestampLtz.fromEpochMillis(
Math.floorDiv(nanos, 1_000_000L), (int) Math.floorMod(nanos, 1_000_000L));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ public TimestampNtz getTimestampNtz(int i, int precision) {
return TimestampNtz.fromMillis(((TimeStampMilliVector) valueVector).get(i));
} else if (valueVector instanceof TimeStampMicroVector) {
long micros = ((TimeStampMicroVector) valueVector).get(i);
return TimestampNtz.fromMillis(micros / 1000, (int) (micros % 1000) * 1000);
return TimestampNtz.fromMillis(
Math.floorDiv(micros, 1_000L), (int) Math.floorMod(micros, 1_000L) * 1_000);
} else {
long nanos = ((TimeStampNanoVector) valueVector).get(i);
return TimestampNtz.fromMillis(nanos / 1_000_000, (int) (nanos % 1_000_000));
return TimestampNtz.fromMillis(
Math.floorDiv(nanos, 1_000_000L), (int) Math.floorMod(nanos, 1_000_000L));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.apache.fluss.shaded.arrow.org.apache.arrow.vector.TimeStampVector;
import org.apache.fluss.shaded.arrow.org.apache.arrow.vector.types.pojo.ArrowType;

import static org.apache.fluss.utils.DateTimeUtils.timestampToMicros;
import static org.apache.fluss.utils.DateTimeUtils.timestampToNanos;
import static org.apache.fluss.utils.Preconditions.checkState;

/** {@link ArrowFieldWriter} for TimestampLtz. */
Expand Down Expand Up @@ -64,16 +66,17 @@ public void doWrite(int rowIndex, DataGetters row, int ordinal, boolean handleSa
}
} else if (vector instanceof TimeStampMicroVector) {
long microSec =
timestamp.getEpochMillisecond() * 1000
+ timestamp.getNanoOfMillisecond() / 1000;
timestampToMicros(
timestamp.getEpochMillisecond(), timestamp.getNanoOfMillisecond());
if (handleSafe) {
vector.setSafe(rowIndex, microSec);
} else {
vector.set(rowIndex, microSec);
}
} else {
long nanoSec =
timestamp.getEpochMillisecond() * 1_000_000 + timestamp.getNanoOfMillisecond();
timestampToNanos(
timestamp.getEpochMillisecond(), timestamp.getNanoOfMillisecond());
if (handleSafe) {
vector.setSafe(rowIndex, nanoSec);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.apache.fluss.shaded.arrow.org.apache.arrow.vector.TimeStampVector;
import org.apache.fluss.shaded.arrow.org.apache.arrow.vector.types.pojo.ArrowType;

import static org.apache.fluss.utils.DateTimeUtils.timestampToMicros;
import static org.apache.fluss.utils.DateTimeUtils.timestampToNanos;
import static org.apache.fluss.utils.Preconditions.checkState;

/** {@link ArrowFieldWriter} for TimestampNtz. */
Expand Down Expand Up @@ -64,15 +66,15 @@ public void doWrite(int rowIndex, DataGetters row, int ordinal, boolean handleSa
}
} else if (vector instanceof TimeStampMicroVector) {
long microSec =
timestamp.getMillisecond() * 1000 + timestamp.getNanoOfMillisecond() / 1000;
timestampToMicros(timestamp.getMillisecond(), timestamp.getNanoOfMillisecond());
if (handleSafe) {
vector.setSafe(rowIndex, microSec);
} else {
vector.set(rowIndex, microSec);
}
} else {
long nanoSec =
timestamp.getMillisecond() * 1_000_000 + timestamp.getNanoOfMillisecond();
timestampToNanos(timestamp.getMillisecond(), timestamp.getNanoOfMillisecond());
if (handleSafe) {
vector.setSafe(rowIndex, nanoSec);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,35 @@ public class DateTimeUtils {
.optionalEnd()
.toFormatter();

/**
* Converts a timestamp's milliseconds and nanoseconds within the millisecond to microseconds.
* Sub-microsecond digits are discarded.
*
* @throws ArithmeticException if the result does not fit in a long
*/
public static long timestampToMicros(long millisecond, int nanoOfMillisecond) {
return scaleTimestamp(millisecond, MICROS_PER_MILLIS, nanoOfMillisecond / NANOS_PER_MICROS);
}

/**
* Converts a timestamp's milliseconds and nanoseconds within the millisecond to nanoseconds.
*
* @throws ArithmeticException if the result does not fit in a long
*/
public static long timestampToNanos(long millisecond, int nanoOfMillisecond) {
return scaleTimestamp(millisecond, 1_000_000L, nanoOfMillisecond);
}

private static long scaleTimestamp(long millisecond, long unitsPerMillis, long fraction) {
if (millisecond < 0) {
// The non-negative fraction can bring the final value back into range even when
// multiplying the floor-rounded millisecond would underflow at Long.MIN_VALUE.
return Math.addExact(
Math.multiplyExact(millisecond + 1, unitsPerMillis), fraction - unitsPerMillis);
}
return Math.addExact(Math.multiplyExact(millisecond, unitsPerMillis), fraction);
}

public static LocalDate toLocalDate(int date) {
return julianToLocalDate(date + EPOCH_JULIAN);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

import org.junit.jupiter.api.Test;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.TimeZone;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -46,6 +48,29 @@ public void testNormal() {
assertThat(TimestampNtz.fromLocalDateTime(ldt3).toLocalDateTime()).isEqualTo(ldt3);
}

@Test
void testToLocalDateTimeAcrossMillisecondRange() {
long[] milliseconds = {
Long.MIN_VALUE,
(long) Integer.MIN_VALUE * 86_400_000 - 1,
-86_400_001,
-1,
0,
86_400_000,
((long) Integer.MAX_VALUE + 1) * 86_400_000,
Long.MAX_VALUE
};
for (long millis : milliseconds) {
for (int nanos : new int[] {0, 999_999}) {
LocalDateTime expected =
LocalDateTime.ofInstant(
Instant.ofEpochMilli(millis).plusNanos(nanos), ZoneOffset.UTC);
assertThat(TimestampNtz.fromMillis(millis, nanos).toLocalDateTime())
.isEqualTo(expected);
}
}
}

@Test
public void testDaylightSavingTime() {
TimeZone tz = TimeZone.getDefault();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* 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.fluss.row.arrow;

import org.apache.fluss.row.GenericRow;
import org.apache.fluss.row.TimestampLtz;
import org.apache.fluss.row.TimestampNtz;
import org.apache.fluss.row.arrow.writers.ArrowFieldWriter;
import org.apache.fluss.row.columnar.ColumnVector;
import org.apache.fluss.row.columnar.ColumnarRow;
import org.apache.fluss.shaded.arrow.org.apache.arrow.memory.RootAllocator;
import org.apache.fluss.shaded.arrow.org.apache.arrow.vector.TimeStampVector;
import org.apache.fluss.shaded.arrow.org.apache.arrow.vector.VectorSchemaRoot;
import org.apache.fluss.types.DataType;
import org.apache.fluss.types.DataTypes;
import org.apache.fluss.types.RowType;
import org.apache.fluss.utils.ArrowUtils;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/** Verifies timestamp range checks and round trips through Arrow vectors. */
class ArrowTimestampWriterTest {

@ParameterizedTest
@MethodSource("timestampWriters")
void testRoundTripsTimestampBoundaries(int precision, boolean withZone, boolean handleSafe) {
DataType type =
withZone ? DataTypes.TIMESTAMP_LTZ(precision) : DataTypes.TIMESTAMP(precision);
RowType rowType = DataTypes.ROW(type);
long unitsPerMilli = precision == 6 ? 1_000 : 1_000_000;
int nanosPerUnit = precision == 6 ? 1_000 : 1;
try (RootAllocator allocator = new RootAllocator(1024 * 1024);
VectorSchemaRoot root =
VectorSchemaRoot.create(ArrowUtils.toArrowSchema(rowType), allocator)) {
root.allocateNew();
TimeStampVector vector = (TimeStampVector) root.getVector(0);
ArrowFieldWriter writer = ArrowUtils.createArrowFieldWriter(vector, type);
long[] values = {
Long.MIN_VALUE,
-1_000_001,
-unitsPerMilli,
-unitsPerMilli + 1,
-1,
0,
1,
1_000_001,
Long.MAX_VALUE
};
for (int i = 0; i < values.length; i++) {
long millis = Math.floorDiv(values[i], unitsPerMilli);
int nanos = (int) Math.floorMod(values[i], unitsPerMilli) * nanosPerUnit;
writer.write(i, timestampRow(millis, nanos, withZone), 0, handleSafe);
assertThat(vector.get(i)).isEqualTo(values[i]);
}
root.setRowCount(values.length);
ArrowReader reader =
new ArrowReader(
new ColumnVector[] {ArrowUtils.createArrowColumnVector(vector, type)},
root.getRowCount());
for (int i = 0; i < values.length; i++) {
long millis = Math.floorDiv(values[i], unitsPerMilli);
int nanos = (int) Math.floorMod(values[i], unitsPerMilli) * nanosPerUnit;
ColumnarRow row = reader.read(i);
if (withZone) {
assertThat(row.getTimestampLtz(0, precision))
.isEqualTo(TimestampLtz.fromEpochMillis(millis, nanos));
} else {
assertThat(row.getTimestampNtz(0, precision))
.isEqualTo(TimestampNtz.fromMillis(millis, nanos));
}
}
}
}

@ParameterizedTest
@MethodSource("timestampWriters")
void testRejectsOverflowBeforeChangingVector(
int precision, boolean withZone, boolean handleSafe) {
DataType type =
withZone ? DataTypes.TIMESTAMP_LTZ(precision) : DataTypes.TIMESTAMP(precision);
RowType rowType = DataTypes.ROW(type);
long unitsPerMilli = precision == 6 ? 1_000 : 1_000_000;
int nanosPerUnit = precision == 6 ? 1_000 : 1;
try (RootAllocator allocator = new RootAllocator(1024 * 1024);
VectorSchemaRoot root =
VectorSchemaRoot.create(ArrowUtils.toArrowSchema(rowType), allocator)) {
root.allocateNew();
TimeStampVector vector = (TimeStampVector) root.getVector(0);
ArrowFieldWriter writer = ArrowUtils.createArrowFieldWriter(vector, type);
vector.set(0, 42);
for (long limit : new long[] {Long.MIN_VALUE, Long.MAX_VALUE}) {
long millis = Math.floorDiv(limit, unitsPerMilli);
int nanos = (int) Math.floorMod(limit, unitsPerMilli) * nanosPerUnit;
int outsideNanos = nanos + (limit < 0 ? -nanosPerUnit : nanosPerUnit);
assertThatThrownBy(
() ->
writer.write(
0,
timestampRow(millis, outsideNanos, withZone),
0,
handleSafe))
.isInstanceOf(ArithmeticException.class);
long outsideMillis = millis + (limit < 0 ? -1 : 1);
assertThatThrownBy(
() ->
writer.write(
0,
timestampRow(outsideMillis, nanos, withZone),
0,
handleSafe))
.isInstanceOf(ArithmeticException.class);
assertThat(vector.get(0)).isEqualTo(42);
}
}
}

private static GenericRow timestampRow(long millis, int nanos, boolean withZone) {
return GenericRow.of(
withZone
? TimestampLtz.fromEpochMillis(millis, nanos)
: TimestampNtz.fromMillis(millis, nanos));
}

private static Stream<Arguments> timestampWriters() {
return Stream.of(
Arguments.of(6, false, false), Arguments.of(6, false, true),
Arguments.of(6, true, false), Arguments.of(6, true, true),
Arguments.of(9, false, false), Arguments.of(9, false, true),
Arguments.of(9, true, false), Arguments.of(9, true, true));
}
}
11 changes: 11 additions & 0 deletions fluss-kafka/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,18 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.apache.fluss</groupId>
<artifactId>fluss-shaded-jackson</artifactId>
</dependency>

<!-- test dependency -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>fluss-client</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-test</artifactId>
Expand Down
Loading
Loading