diff --git a/databricks-sdk-java/pom.xml b/databricks-sdk-java/pom.xml
index cdcea322f..0eed8fa0c 100644
--- a/databricks-sdk-java/pom.xml
+++ b/databricks-sdk-java/pom.xml
@@ -103,5 +103,16 @@
jackson-datatype-jsr310
${jackson.version}
+
+
+ com.google.protobuf
+ protobuf-java
+ 3.25.1
+
+
+ com.google.protobuf
+ protobuf-java-util
+ 3.25.1
+
diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/DurationDeserializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/DurationDeserializer.java
new file mode 100644
index 000000000..765dccd66
--- /dev/null
+++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/DurationDeserializer.java
@@ -0,0 +1,23 @@
+package com.databricks.sdk.core.serialization;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.google.protobuf.Duration;
+import com.google.protobuf.util.Durations;
+import java.io.IOException;
+
+public class DurationDeserializer extends JsonDeserializer {
+ @Override
+ public Duration deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ String durationStr = p.getValueAsString();
+ if (durationStr == null || durationStr.isEmpty()) {
+ return null;
+ }
+ try {
+ return Durations.parse(durationStr); // Parses duration format like "3.000s"
+ } catch (Exception e) {
+ throw new IOException("Failed to parse duration: " + durationStr, e);
+ }
+ }
+}
diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/DurationSerializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/DurationSerializer.java
new file mode 100644
index 000000000..27fde56b6
--- /dev/null
+++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/DurationSerializer.java
@@ -0,0 +1,21 @@
+package com.databricks.sdk.core.serialization;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.google.protobuf.Duration;
+import com.google.protobuf.util.Durations;
+import java.io.IOException;
+
+public class DurationSerializer extends JsonSerializer {
+ @Override
+ public void serialize(Duration value, JsonGenerator gen, SerializerProvider serializers)
+ throws IOException {
+ if (value != null) {
+ String durationStr = Durations.toString(value); // Converts to "3.000s"
+ gen.writeString(durationStr);
+ } else {
+ gen.writeNull();
+ }
+ }
+}
diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/FieldMaskDeserializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/FieldMaskDeserializer.java
new file mode 100644
index 000000000..5061f4b3e
--- /dev/null
+++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/FieldMaskDeserializer.java
@@ -0,0 +1,23 @@
+package com.databricks.sdk.core.serialization;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.google.protobuf.FieldMask;
+import com.google.protobuf.util.FieldMaskUtil;
+import java.io.IOException;
+
+public class FieldMaskDeserializer extends JsonDeserializer {
+ @Override
+ public FieldMask deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ String fieldMaskStr = p.getValueAsString();
+ if (fieldMaskStr == null || fieldMaskStr.isEmpty()) {
+ return null;
+ }
+ try {
+ return FieldMaskUtil.fromJsonString(fieldMaskStr); // Parses JSON string format
+ } catch (Exception e) {
+ throw new IOException("Failed to parse field mask: " + fieldMaskStr, e);
+ }
+ }
+}
diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/FieldMaskSerializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/FieldMaskSerializer.java
new file mode 100644
index 000000000..301f0b5bb
--- /dev/null
+++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/FieldMaskSerializer.java
@@ -0,0 +1,21 @@
+package com.databricks.sdk.core.serialization;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.google.protobuf.FieldMask;
+import com.google.protobuf.util.FieldMaskUtil;
+import java.io.IOException;
+
+public class FieldMaskSerializer extends JsonSerializer {
+ @Override
+ public void serialize(FieldMask value, JsonGenerator gen, SerializerProvider serializers)
+ throws IOException {
+ if (value != null) {
+ String fieldMaskStr = FieldMaskUtil.toJsonString(value); // Converts to JSON string format
+ gen.writeString(fieldMaskStr);
+ } else {
+ gen.writeNull();
+ }
+ }
+}
diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/TimestampDeserializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/TimestampDeserializer.java
new file mode 100644
index 000000000..b5474bdc6
--- /dev/null
+++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/TimestampDeserializer.java
@@ -0,0 +1,23 @@
+package com.databricks.sdk.core.serialization;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.google.protobuf.Timestamp;
+import com.google.protobuf.util.Timestamps;
+import java.io.IOException;
+
+public class TimestampDeserializer extends JsonDeserializer {
+ @Override
+ public Timestamp deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ String timestampStr = p.getValueAsString();
+ if (timestampStr == null || timestampStr.isEmpty()) {
+ return null;
+ }
+ try {
+ return Timestamps.parse(timestampStr); // Parses RFC 3339 format
+ } catch (Exception e) {
+ throw new IOException("Failed to parse timestamp: " + timestampStr, e);
+ }
+ }
+}
diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/TimestampSerializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/TimestampSerializer.java
new file mode 100644
index 000000000..a760b4749
--- /dev/null
+++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/serialization/TimestampSerializer.java
@@ -0,0 +1,21 @@
+package com.databricks.sdk.core.serialization;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.google.protobuf.Timestamp;
+import com.google.protobuf.util.Timestamps;
+import java.io.IOException;
+
+public class TimestampSerializer extends JsonSerializer {
+ @Override
+ public void serialize(Timestamp value, JsonGenerator gen, SerializerProvider serializers)
+ throws IOException {
+ if (value != null) {
+ String timestampStr = Timestamps.toString(value); // Converts to RFC 3339 format
+ gen.writeString(timestampStr);
+ } else {
+ gen.writeNull();
+ }
+ }
+}
diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/DurationDeserializerTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/DurationDeserializerTest.java
new file mode 100644
index 000000000..19a33ff18
--- /dev/null
+++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/DurationDeserializerTest.java
@@ -0,0 +1,46 @@
+package com.databricks.sdk.core.serialization;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.google.protobuf.Duration;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class DurationDeserializerTest {
+ private static class TestClass {
+ @JsonDeserialize(using = DurationDeserializer.class)
+ private Duration duration;
+
+ public Duration getDuration() {
+ return duration;
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("durationDeserializationTestCases")
+ public void testDurationDeserialization(String inputJson, Duration expectedDuration)
+ throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ TestClass obj = mapper.readValue(inputJson, TestClass.class);
+ assertEquals(expectedDuration, obj.getDuration());
+ }
+
+ static Stream durationDeserializationTestCases() {
+ return Stream.of(
+ // Duration with seconds and nanos
+ Arguments.of(
+ "{\"duration\":\"3.500s\"}",
+ Duration.newBuilder().setSeconds(3).setNanos(500000000).build()),
+ // Duration with only seconds
+ Arguments.of("{\"duration\":\"5s\"}", Duration.newBuilder().setSeconds(5).build()),
+ // Duration with only nanos
+ Arguments.of(
+ "{\"duration\":\"0.123456789s\"}", Duration.newBuilder().setNanos(123456789).build()),
+ // Null duration
+ Arguments.of("{\"duration\":null}", null));
+ }
+}
diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/DurationSerializerTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/DurationSerializerTest.java
new file mode 100644
index 000000000..f703972a1
--- /dev/null
+++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/DurationSerializerTest.java
@@ -0,0 +1,49 @@
+package com.databricks.sdk.core.serialization;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.protobuf.Duration;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class DurationSerializerTest {
+
+ private static class TestClass {
+ @JsonSerialize(using = DurationSerializer.class)
+ private Duration duration;
+
+ public TestClass(Duration duration) {
+ this.duration = duration;
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("durationSerializationTestCases")
+ public void testDurationSerialization(Duration duration, String expectedJson) throws Exception {
+ TestClass testObject = new TestClass(duration);
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(testObject);
+ assertEquals(expectedJson, json);
+ }
+
+ static Stream durationSerializationTestCases() {
+ return Stream.of(
+ // Duration of 3 seconds
+ Arguments.of(Duration.newBuilder().setSeconds(3).build(), "{\"duration\":\"3s\"}"),
+ // Duration of 3.5 seconds (3 seconds + 500000000 nanoseconds)
+ Arguments.of(
+ Duration.newBuilder().setSeconds(3).setNanos(500000000).build(),
+ "{\"duration\":\"3.500s\"}"),
+ // Duration of 0 seconds
+ Arguments.of(Duration.newBuilder().setSeconds(0).build(), "{\"duration\":\"0s\"}"),
+ // Duration with only nanos
+ Arguments.of(
+ Duration.newBuilder().setNanos(123456789).build(), "{\"duration\":\"0.123456789s\"}"),
+ // Null duration
+ Arguments.of(null, "{\"duration\":null}"));
+ }
+}
diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/FieldMaskDeserializerTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/FieldMaskDeserializerTest.java
new file mode 100644
index 000000000..0fe41e2a6
--- /dev/null
+++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/FieldMaskDeserializerTest.java
@@ -0,0 +1,54 @@
+package com.databricks.sdk.core.serialization;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.google.protobuf.FieldMask;
+import com.google.protobuf.util.FieldMaskUtil;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class FieldMaskDeserializerTest {
+ private static class TestClass {
+ @JsonDeserialize(using = FieldMaskDeserializer.class)
+ private FieldMask fieldMask;
+
+ public FieldMask getFieldMask() {
+ return fieldMask;
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("fieldMaskDeserializationTestCases")
+ public void testFieldMaskDeserialization(String inputJson, List expectedFieldPaths)
+ throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ TestClass obj = mapper.readValue(inputJson, TestClass.class);
+
+ if (expectedFieldPaths == null) {
+ assertNull(obj.getFieldMask());
+ } else {
+ FieldMask expected = FieldMaskUtil.fromStringList(expectedFieldPaths);
+ assertEquals(expected, obj.getFieldMask());
+ }
+ }
+
+ static Stream fieldMaskDeserializationTestCases() {
+ return Stream.of(
+ // Simple field mask
+ Arguments.of("{\"fieldMask\":\"foo,bar.baz\"}", Arrays.asList("foo", "bar.baz")),
+ // Single field
+ Arguments.of("{\"fieldMask\":\"name\"}", Arrays.asList("name")),
+ // Nested fields
+ Arguments.of(
+ "{\"fieldMask\":\"user.profile.email,user.profile.name\"}",
+ Arrays.asList("user.profile.email", "user.profile.name")),
+ // Null field mask
+ Arguments.of("{\"fieldMask\":null}", null));
+ }
+}
diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/FieldMaskSerializerTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/FieldMaskSerializerTest.java
new file mode 100644
index 000000000..83baf0936
--- /dev/null
+++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/FieldMaskSerializerTest.java
@@ -0,0 +1,54 @@
+package com.databricks.sdk.core.serialization;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.protobuf.FieldMask;
+import com.google.protobuf.util.FieldMaskUtil;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class FieldMaskSerializerTest {
+ private static class TestClass {
+ @JsonSerialize(using = FieldMaskSerializer.class)
+ private FieldMask fieldMask;
+
+ public TestClass(FieldMask fieldMask) {
+ this.fieldMask = fieldMask;
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("fieldMaskSerializationTestCases")
+ public void testFieldMaskSerialization(List fieldPaths, String expectedJson)
+ throws Exception {
+ FieldMask fieldMask = null;
+ if (fieldPaths != null) {
+ fieldMask = FieldMaskUtil.fromStringList(fieldPaths);
+ }
+
+ TestClass testObject = new TestClass(fieldMask);
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(testObject);
+ assertEquals(expectedJson, json);
+ }
+
+ static Stream fieldMaskSerializationTestCases() {
+ return Stream.of(
+ // Simple field mask
+ Arguments.of(Arrays.asList("foo", "bar.baz"), "{\"fieldMask\":\"foo,bar.baz\"}"),
+ // Single field
+ Arguments.of(Arrays.asList("name"), "{\"fieldMask\":\"name\"}"),
+ // Nested fields
+ Arguments.of(
+ Arrays.asList("user.profile.email", "user.profile.name"),
+ "{\"fieldMask\":\"user.profile.email,user.profile.name\"}"),
+ // Null field mask
+ Arguments.of(null, "{\"fieldMask\":null}"));
+ }
+}
diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/TimestampDeserializerTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/TimestampDeserializerTest.java
new file mode 100644
index 000000000..270bd56bd
--- /dev/null
+++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/TimestampDeserializerTest.java
@@ -0,0 +1,45 @@
+package com.databricks.sdk.core.serialization;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.google.protobuf.Timestamp;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class TimestampDeserializerTest {
+ private static class TestClass {
+ @JsonDeserialize(using = TimestampDeserializer.class)
+ private Timestamp timestamp;
+
+ public Timestamp getTimestamp() {
+ return timestamp;
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("timestampDeserializationTestCases")
+ public void testTimestampDeserialization(String inputJson, Timestamp expectedTimestamp)
+ throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ TestClass obj = mapper.readValue(inputJson, TestClass.class);
+ assertEquals(expectedTimestamp, obj.getTimestamp());
+ }
+
+ static Stream timestampDeserializationTestCases() {
+ return Stream.of(
+ // Timestamp without nanos
+ Arguments.of(
+ "{\"timestamp\":\"2024-06-20T12:34:56Z\"}",
+ Timestamp.newBuilder().setSeconds(1718886896L).build()),
+ // Timestamp with nanos
+ Arguments.of(
+ "{\"timestamp\":\"2024-06-20T12:34:56.123456789Z\"}",
+ Timestamp.newBuilder().setSeconds(1718886896L).setNanos(123456789).build()),
+ // Null timestamp
+ Arguments.of("{\"timestamp\":null}", null));
+ }
+}
diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/TimestampSerializerTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/TimestampSerializerTest.java
new file mode 100644
index 000000000..05b9c567d
--- /dev/null
+++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/serialization/TimestampSerializerTest.java
@@ -0,0 +1,46 @@
+package com.databricks.sdk.core.serialization;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.protobuf.Timestamp;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class TimestampSerializerTest {
+ private static class TestClass {
+ @JsonSerialize(using = TimestampSerializer.class)
+ private Timestamp timestamp;
+
+ public TestClass(Timestamp timestamp) {
+ this.timestamp = timestamp;
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("timestampSerializationTestCases")
+ public void testTimestampSerialization(Timestamp timestamp, String expectedJson)
+ throws Exception {
+ TestClass testObject = new TestClass(timestamp);
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(testObject);
+ assertEquals(expectedJson, json);
+ }
+
+ static Stream timestampSerializationTestCases() {
+ return Stream.of(
+ // Basic timestamp without nanos
+ Arguments.of(
+ Timestamp.newBuilder().setSeconds(1718886896L).build(),
+ "{\"timestamp\":\"2024-06-20T12:34:56Z\"}"),
+ // Timestamp with nanos
+ Arguments.of(
+ Timestamp.newBuilder().setSeconds(1718886896L).setNanos(123456789).build(),
+ "{\"timestamp\":\"2024-06-20T12:34:56.123456789Z\"}"),
+ // Null timestamp
+ Arguments.of(null, "{\"timestamp\":null}"));
+ }
+}