From 01b1d9b2dfab5c693c73ccef05e87b934c26d15f Mon Sep 17 00:00:00 2001 From: Miles Yucht Date: Tue, 25 Jul 2023 12:39:41 +0200 Subject: [PATCH 1/9] Fix list query history --- .../com/databricks/sdk/core/ApiClient.java | 16 +--- .../databricks/sdk/core/HeaderSerializer.java | 83 +++++++++++++++++++ .../com/databricks/sdk/support/Paginator.java | 3 + .../com/databricks/sdk/integration/SqlIT.java | 28 +++++++ 4 files changed, 117 insertions(+), 13 deletions(-) create mode 100644 databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java create mode 100644 databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java index 404b1c72f..cb550d26d 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java @@ -93,21 +93,11 @@ private Request withQuery(Request in, I entity) { } try { // deterministic query string: in the order of class fields - for (Field field : entity.getClass().getDeclaredFields()) { - QueryParam param = field.getAnnotation(QueryParam.class); - if (param == null) { - continue; - } - field.setAccessible(true); - Object value = field.get(entity); - field.setAccessible(false); - if (value == null) { - continue; - } - in.withQueryParam(param.value(), value.toString()); + for (Map.Entry e : HeaderSerializer.serialize(entity).entrySet()) { + in.withQueryParam(e.getKey(), mapper.writeValueAsString(e.getValue())); } return in; - } catch (IllegalAccessException e) { + } catch (JsonProcessingException e) { throw new DatabricksException("Cannot create query string: " + e.getMessage(), e); } } diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java new file mode 100644 index 000000000..174b697b9 --- /dev/null +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java @@ -0,0 +1,83 @@ +package com.databricks.sdk.core; + +import com.databricks.sdk.support.QueryParam; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class HeaderSerializer { + public static Map serialize(Object o) { + Map flattened = flattenObject(o); + for (Field f : o.getClass().getDeclaredFields()) { + QueryParam queryParam = f.getAnnotation(QueryParam.class); + if (queryParam == null) { + flattened.remove(getFieldName(f)); + } + } + + return flattened; + } + + private static final List> primitiveTypes = Arrays.asList( + boolean.class, + Boolean.class, + byte.class, + Byte.class, + char.class, + Character.class, + short.class, + Short.class, + int.class, + Integer.class, + long.class, + Long.class, + float.class, + Float.class, + double.class, + Double.class, + String.class + ); + + private static String getFieldName(Field f) { + JsonProperty jsonProperty = f.getAnnotation(JsonProperty.class); + if (jsonProperty != null) { + return jsonProperty.value(); + } else { + return f.getName(); + } + } + + private static Map flattenObject(Object o) { + Map result = new HashMap<>(); + Field[] fields = o.getClass().getDeclaredFields(); + for (Field f : fields) { + f.setAccessible(true); + try { + String name = getFieldName(f); + Object value = f.get(o); + if (value == null) { + continue; + } + // check if object is a primitive type + if (primitiveTypes.contains(f.getType()) || Iterable.class.isAssignableFrom(f.getType())) { + result.put(name, value); + } else { + // recursively flatten the object + Map flattened = flattenObject(value); + for (Map.Entry entry : flattened.entrySet()) { + result.put(name + "." + entry.getKey(), entry.getValue()); + } + } + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } finally { + f.setAccessible(false); + } + } + return result; + } +} diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/support/Paginator.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/support/Paginator.java index 1e08692fb..fcb8e3510 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/support/Paginator.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/support/Paginator.java @@ -71,6 +71,9 @@ private Iterator outerIterator() { return new Iterator() { @Override public boolean hasNext() { + if (currentPage == null) { + return false; + } if (currentPage.hasNext()) { return true; } diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java new file mode 100644 index 000000000..d1d5722f6 --- /dev/null +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java @@ -0,0 +1,28 @@ +package com.databricks.sdk.integration; + +import com.databricks.sdk.WorkspaceClient; +import com.databricks.sdk.integration.framework.EnvContext; +import com.databricks.sdk.integration.framework.EnvTest; +import com.databricks.sdk.service.sql.ListQueryHistoryRequest; +import com.databricks.sdk.service.sql.QueryFilter; +import com.databricks.sdk.service.sql.QueryInfo; +import com.databricks.sdk.service.sql.TimeRange; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@EnvContext("workspace") +@ExtendWith(EnvTest.class) +public class SqlIT { + @Test + void listQueryHistory(WorkspaceClient w) { + TimeRange timeRange = new TimeRange() + .setStartTimeMs(1690243200000L) + .setEndTimeMs(1690329600000L); + ListQueryHistoryRequest request = new ListQueryHistoryRequest() + .setFilterBy(new QueryFilter().setQueryStartTimeRange(timeRange)); + Iterable queries = w.queryHistory().list(request); + for (QueryInfo query : queries) { + System.out.println(query); + } + } +} From 37002e67b5a1b3f1d7f337a3cc45a5c0efd4cc2a Mon Sep 17 00:00:00 2001 From: Miles Yucht Date: Tue, 25 Jul 2023 12:46:00 +0200 Subject: [PATCH 2/9] fmt --- .../com/databricks/sdk/core/ApiClient.java | 2 - .../databricks/sdk/core/HeaderSerializer.java | 39 +++++++++---------- .../com/databricks/sdk/integration/SqlIT.java | 10 ++--- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java index cb550d26d..3898347b4 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java @@ -6,7 +6,6 @@ import com.databricks.sdk.core.http.Response; import com.databricks.sdk.core.utils.RealTimer; import com.databricks.sdk.core.utils.Timer; -import com.databricks.sdk.support.QueryParam; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -14,7 +13,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import java.io.IOException; -import java.lang.reflect.Field; import java.util.Collection; import java.util.Map; import java.util.Random; diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java index 174b697b9..312ec5c3d 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java @@ -2,7 +2,6 @@ import com.databricks.sdk.support.QueryParam; import com.fasterxml.jackson.annotation.JsonProperty; - import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; @@ -22,25 +21,25 @@ public static Map serialize(Object o) { return flattened; } - private static final List> primitiveTypes = Arrays.asList( - boolean.class, - Boolean.class, - byte.class, - Byte.class, - char.class, - Character.class, - short.class, - Short.class, - int.class, - Integer.class, - long.class, - Long.class, - float.class, - Float.class, - double.class, - Double.class, - String.class - ); + private static final List> primitiveTypes = + Arrays.asList( + boolean.class, + Boolean.class, + byte.class, + Byte.class, + char.class, + Character.class, + short.class, + Short.class, + int.class, + Integer.class, + long.class, + Long.class, + float.class, + Float.class, + double.class, + Double.class, + String.class); private static String getFieldName(Field f) { JsonProperty jsonProperty = f.getAnnotation(JsonProperty.class); diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java index d1d5722f6..f4bb396ce 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java @@ -15,11 +15,11 @@ public class SqlIT { @Test void listQueryHistory(WorkspaceClient w) { - TimeRange timeRange = new TimeRange() - .setStartTimeMs(1690243200000L) - .setEndTimeMs(1690329600000L); - ListQueryHistoryRequest request = new ListQueryHistoryRequest() - .setFilterBy(new QueryFilter().setQueryStartTimeRange(timeRange)); + TimeRange timeRange = + new TimeRange().setStartTimeMs(1690243200000L).setEndTimeMs(1690329600000L); + ListQueryHistoryRequest request = + new ListQueryHistoryRequest() + .setFilterBy(new QueryFilter().setQueryStartTimeRange(timeRange)); Iterable queries = w.queryHistory().list(request); for (QueryInfo query : queries) { System.out.println(query); From 2289da713a78eb6010cbb13dc2f4bbf3daf179a1 Mon Sep 17 00:00:00 2001 From: Miles Yucht Date: Tue, 25 Jul 2023 12:51:48 +0200 Subject: [PATCH 3/9] fix tests --- .../java/com/databricks/sdk/core/ApiClient.java | 11 +++-------- .../com/databricks/sdk/core/HeaderSerializer.java | 13 +++++++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java index 3898347b4..adea4ce0b 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java @@ -89,15 +89,10 @@ private Request withQuery(Request in, I entity) { if (entity == null) { return in; } - try { - // deterministic query string: in the order of class fields - for (Map.Entry e : HeaderSerializer.serialize(entity).entrySet()) { - in.withQueryParam(e.getKey(), mapper.writeValueAsString(e.getValue())); - } - return in; - } catch (JsonProcessingException e) { - throw new DatabricksException("Cannot create query string: " + e.getMessage(), e); + for (Map.Entry e : HeaderSerializer.serialize(entity).entrySet()) { + in.withQueryParam(e.getKey(), e.getValue().toString()); } + return in; } public Collection getCollection(String path, I in, Class element) { diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java index 312ec5c3d..987297995 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java @@ -3,10 +3,7 @@ import com.databricks.sdk.support.QueryParam; import com.fasterxml.jackson.annotation.JsonProperty; import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class HeaderSerializer { public static Map serialize(Object o) { @@ -42,8 +39,11 @@ public static Map serialize(Object o) { String.class); private static String getFieldName(Field f) { + QueryParam queryParam = f.getAnnotation(QueryParam.class); JsonProperty jsonProperty = f.getAnnotation(JsonProperty.class); - if (jsonProperty != null) { + if (queryParam != null) { + return queryParam.value(); + } else if (jsonProperty != null) { return jsonProperty.value(); } else { return f.getName(); @@ -51,7 +51,8 @@ private static String getFieldName(Field f) { } private static Map flattenObject(Object o) { - Map result = new HashMap<>(); + // LinkedHashMap ensures consistent ordering of fields. + Map result = new LinkedHashMap<>(); Field[] fields = o.getClass().getDeclaredFields(); for (Field f : fields) { f.setAccessible(true); From 6db34fa7361b4bb767f941fd0456227004bacdb1 Mon Sep 17 00:00:00 2001 From: Miles Yucht Date: Tue, 25 Jul 2023 13:19:57 +0200 Subject: [PATCH 4/9] handle lists appropriately --- .../com/databricks/sdk/core/ApiClient.java | 4 +- ...GrpcTranscodingQueryParamsSerializer.java} | 56 ++++++++++++++++++- .../databricks/sdk/core/http/FormRequest.java | 12 +++- .../com/databricks/sdk/core/http/Request.java | 21 ++++--- .../com/databricks/sdk/integration/SqlIT.java | 14 ++++- 5 files changed, 92 insertions(+), 15 deletions(-) rename databricks-sdk-java/src/main/java/com/databricks/sdk/core/{HeaderSerializer.java => GrpcTranscodingQueryParamsSerializer.java} (53%) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java index adea4ce0b..833569696 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java @@ -89,8 +89,8 @@ private Request withQuery(Request in, I entity) { if (entity == null) { return in; } - for (Map.Entry e : HeaderSerializer.serialize(entity).entrySet()) { - in.withQueryParam(e.getKey(), e.getValue().toString()); + for (GrpcTranscodingQueryParamsSerializer.HeaderEntry e : GrpcTranscodingQueryParamsSerializer.serialize(entity)) { + in.withQueryParam(e.getKey(), e.getValue()); } return in; } diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java similarity index 53% rename from databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java rename to databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java index 987297995..149bc2745 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HeaderSerializer.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java @@ -5,8 +5,46 @@ import java.lang.reflect.Field; import java.util.*; -public class HeaderSerializer { - public static Map serialize(Object o) { +/** + * Serializes an object into a list of query parameter entries compatible with gRPC-transcoding. + * + *

The Databricks REST API uses gRPC transcoding to expose gRPC services as REST APIs. This + * serializer is used to serialize objects into a map of query parameter entries that can be used to invoke a + * gRPC service via REST. + * + *

See the + * documentation for gRPC transcoding for more details. + */ +public class GrpcTranscodingQueryParamsSerializer { + public static class HeaderEntry { + private final String key; + private final String value; + public HeaderEntry(String key, String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } + } + /** + * Serializes an object into a map of query parameter values compatible with gRPC-transcoding. + *

+ * This method respects the QueryParam and JsonProperty annotations on the object's fields when serializing the + * field name. If both annotations are present, the value of the QueryParam annotation is used. + *

+ * The returned object does not contain any top-level fields that are not annotated with QueryParam. All nested fields + * are included, even if they are not annotated with QueryParam. + * @param o The object to serialize. + * @return A list of query parameter entries compatible with gRPC-transcoding. + */ + public static List serialize(Object o) { Map flattened = flattenObject(o); for (Field f : o.getClass().getDeclaredFields()) { QueryParam queryParam = f.getAnnotation(QueryParam.class); @@ -15,7 +53,19 @@ public static Map serialize(Object o) { } } - return flattened; + List result = new ArrayList<>(); + for (Map.Entry entry : flattened.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof Collection) { + for (Object v : (Collection) value) { + result.add(new HeaderEntry(key, v.toString())); + } + } else { + result.add(new HeaderEntry(key, value.toString())); + } + } + return result; } private static final List> primitiveTypes = diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/FormRequest.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/FormRequest.java index 5929fafac..5b49bc4f0 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/FormRequest.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/FormRequest.java @@ -1,6 +1,6 @@ package com.databricks.sdk.core.http; -import java.util.Map; +import java.util.*; public class FormRequest extends Request { public FormRequest(String url, Map form) { @@ -8,7 +8,15 @@ public FormRequest(String url, Map form) { } public FormRequest(String method, String url, Map form) { - super(method, url, mapToQuery(form)); + super(method, url, mapToQuery(wrapValuesInList(form))); withHeader("Content-Type", "application/x-www-form-urlencoded"); } + + static Map> wrapValuesInList(Map map) { + Map> m = new HashMap<>(); + for (Map.Entry entry : map.entrySet()) { + m.put(entry.getKey(), Collections.singletonList(entry.getValue())); + } + return m; + } } diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/Request.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/Request.java index 4734caf45..d2002df48 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/Request.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/Request.java @@ -16,7 +16,7 @@ public class Request { private final String method; private String url; private final Map headers = new HashMap<>(); - private final Map query = new TreeMap<>(); + private final Map> query = new TreeMap<>(); private final String body; public Request(String method, String url) { @@ -40,7 +40,12 @@ public Request withHeader(String key, String value) { } public Request withQueryParam(String key, String value) { - query.put(key, value); + List values = query.get(key); + if (values == null) { + values = new ArrayList<>(); + } + values.add(value); + query.put(key, values); return this; } @@ -49,13 +54,15 @@ public Request withUrl(String url) { return this; } - protected static String mapToQuery(Map in) { + protected static String mapToQuery(Map> in) { StringJoiner joiner = new StringJoiner("&"); - for (Map.Entry entry : in.entrySet()) { + for (Map.Entry> entry : in.entrySet()) { try { String encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.name()); - String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name()); - joiner.add(encodedKey + "=" + encodedValue); + for (String value : entry.getValue()) { + String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8.name()); + joiner.add(encodedKey + "=" + encodedValue); + } } catch (UnsupportedEncodingException e) { throw new DatabricksException("Unable to encode query parameter: " + e.getMessage(), e); } @@ -116,7 +123,7 @@ public Map getHeaders() { return headers; } - public Map getQuery() { + public Map> getQuery() { return query; } diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java index f4bb396ce..b8b20eec0 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java @@ -10,11 +10,13 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import java.util.Arrays; + @EnvContext("workspace") @ExtendWith(EnvTest.class) public class SqlIT { @Test - void listQueryHistory(WorkspaceClient w) { + void listQueryHistoryTimeRange(WorkspaceClient w) { TimeRange timeRange = new TimeRange().setStartTimeMs(1690243200000L).setEndTimeMs(1690329600000L); ListQueryHistoryRequest request = @@ -25,4 +27,14 @@ void listQueryHistory(WorkspaceClient w) { System.out.println(query); } } + @Test + void listQueryHistoryUserIds(WorkspaceClient w) { + ListQueryHistoryRequest request = + new ListQueryHistoryRequest() + .setFilterBy(new QueryFilter().setUserIds(Arrays.asList(123L, 456L))); + Iterable queries = w.queryHistory().list(request); + for (QueryInfo query : queries) { + System.out.println(query); + } + } } From a301b6f5a3a1e816c65c86e6c0efd11f16060365 Mon Sep 17 00:00:00 2001 From: Miles Yucht Date: Tue, 25 Jul 2023 13:21:44 +0200 Subject: [PATCH 5/9] fixes --- .../com/databricks/sdk/core/ApiClient.java | 3 ++- .../GrpcTranscodingQueryParamsSerializer.java | 19 +++++++++++-------- .../com/databricks/sdk/integration/SqlIT.java | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java index 833569696..5bd02d015 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ApiClient.java @@ -89,7 +89,8 @@ private Request withQuery(Request in, I entity) { if (entity == null) { return in; } - for (GrpcTranscodingQueryParamsSerializer.HeaderEntry e : GrpcTranscodingQueryParamsSerializer.serialize(entity)) { + for (GrpcTranscodingQueryParamsSerializer.HeaderEntry e : + GrpcTranscodingQueryParamsSerializer.serialize(entity)) { in.withQueryParam(e.getKey(), e.getValue()); } return in; diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java index 149bc2745..71f489abe 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java @@ -9,8 +9,8 @@ * Serializes an object into a list of query parameter entries compatible with gRPC-transcoding. * *

The Databricks REST API uses gRPC transcoding to expose gRPC services as REST APIs. This - * serializer is used to serialize objects into a map of query parameter entries that can be used to invoke a - * gRPC service via REST. + * serializer is used to serialize objects into a map of query parameter entries that can be used to + * invoke a gRPC service via REST. * *

See the @@ -20,6 +20,7 @@ public class GrpcTranscodingQueryParamsSerializer { public static class HeaderEntry { private final String key; private final String value; + public HeaderEntry(String key, String value) { this.key = key; this.value = value; @@ -35,12 +36,14 @@ public String getValue() { } /** * Serializes an object into a map of query parameter values compatible with gRPC-transcoding. - *

- * This method respects the QueryParam and JsonProperty annotations on the object's fields when serializing the - * field name. If both annotations are present, the value of the QueryParam annotation is used. - *

- * The returned object does not contain any top-level fields that are not annotated with QueryParam. All nested fields - * are included, even if they are not annotated with QueryParam. + * + *

This method respects the QueryParam and JsonProperty annotations on the object's fields when + * serializing the field name. If both annotations are present, the value of the QueryParam + * annotation is used. + * + *

The returned object does not contain any top-level fields that are not annotated with + * QueryParam. All nested fields are included, even if they are not annotated with QueryParam. + * * @param o The object to serialize. * @return A list of query parameter entries compatible with gRPC-transcoding. */ diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java index b8b20eec0..f4a6cc7dd 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/integration/SqlIT.java @@ -7,11 +7,10 @@ import com.databricks.sdk.service.sql.QueryFilter; import com.databricks.sdk.service.sql.QueryInfo; import com.databricks.sdk.service.sql.TimeRange; +import java.util.Arrays; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import java.util.Arrays; - @EnvContext("workspace") @ExtendWith(EnvTest.class) public class SqlIT { @@ -27,6 +26,7 @@ void listQueryHistoryTimeRange(WorkspaceClient w) { System.out.println(query); } } + @Test void listQueryHistoryUserIds(WorkspaceClient w) { ListQueryHistoryRequest request = From b36ffbcaaf3434bdd8b14023f40a3f3e9de1d8db Mon Sep 17 00:00:00 2001 From: Miles Yucht Date: Tue, 25 Jul 2023 13:29:28 +0200 Subject: [PATCH 6/9] spotless --- .../main/java/com/databricks/sdk/core/http/FormRequest.java | 2 +- .../java/com/databricks/sdk/core/http/FormRequestTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/FormRequest.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/FormRequest.java index 5b49bc4f0..3c213233b 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/FormRequest.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/FormRequest.java @@ -13,7 +13,7 @@ public FormRequest(String method, String url, Map form) { } static Map> wrapValuesInList(Map map) { - Map> m = new HashMap<>(); + Map> m = new LinkedHashMap<>(); for (Map.Entry entry : map.entrySet()) { m.put(entry.getKey(), Collections.singletonList(entry.getValue())); } diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/FormRequestTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/FormRequestTest.java index 164c5c8e1..0721c67ee 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/FormRequestTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/FormRequestTest.java @@ -2,14 +2,14 @@ import static org.junit.jupiter.api.Assertions.*; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.TreeMap; import org.junit.jupiter.api.Test; class FormRequestTest { @Test public void itWorks() { - Map data = new TreeMap<>(); + Map data = new LinkedHashMap<>(); data.put("foo", "bar"); data.put("new", "foo"); FormRequest request = new FormRequest("/foo", data); From 307ecdae56c9a0b101276fb273fc5f48f9e56821 Mon Sep 17 00:00:00 2001 From: Miles Yucht Date: Thu, 27 Jul 2023 06:24:39 +0200 Subject: [PATCH 7/9] small fix --- .../main/java/com/databricks/sdk/core/http/Request.java | 6 +----- .../java/com/databricks/sdk/core/http/RequestTest.java | 7 +++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/Request.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/Request.java index d2002df48..a8c7a8767 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/Request.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/http/Request.java @@ -40,12 +40,8 @@ public Request withHeader(String key, String value) { } public Request withQueryParam(String key, String value) { - List values = query.get(key); - if (values == null) { - values = new ArrayList<>(); - } + List values = query.computeIfAbsent(key, k -> new ArrayList<>()); values.add(value); - query.put(key, values); return this; } diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/RequestTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/RequestTest.java index 53fd95aca..a07213c1d 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/RequestTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/RequestTest.java @@ -31,4 +31,11 @@ void requestUriWithQueryWithForwardSlash() { URI uri = new Request("GET", "/foo").withQueryParam("foo", "bar/baz").getUri(); assertEquals("/foo?foo=bar%2Fbaz", uri.toString()); } + + // Test that multiple values for the same query parameter are appropriately encoded. + @Test + void requestUriWithQueryWithMultipleValues() { + URI uri = new Request("GET", "/foo").withQueryParam("foo", "bar").withQueryParam("foo", "baz").getUri(); + assertEquals("/foo?foo=bar&foo=baz", uri.toString()); + } } From 7a4ef88868bc61e9cfe1080bf320d96bdf4b6ef0 Mon Sep 17 00:00:00 2001 From: Miles Yucht Date: Thu, 27 Jul 2023 06:26:50 +0200 Subject: [PATCH 8/9] comment --- .../sdk/core/GrpcTranscodingQueryParamsSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java index 71f489abe..7fc7f802d 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/GrpcTranscodingQueryParamsSerializer.java @@ -115,7 +115,7 @@ private static Map flattenObject(Object o) { if (value == null) { continue; } - // check if object is a primitive type + // check if object is a primitive type or a collection of some kind if (primitiveTypes.contains(f.getType()) || Iterable.class.isAssignableFrom(f.getType())) { result.put(name, value); } else { From 64a2cf4f236e113ca573c4a72868dc1f6422b595 Mon Sep 17 00:00:00 2001 From: Miles Yucht Date: Thu, 27 Jul 2023 06:27:24 +0200 Subject: [PATCH 9/9] fmt --- .../test/java/com/databricks/sdk/core/http/RequestTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/RequestTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/RequestTest.java index a07213c1d..0954b36f5 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/RequestTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/http/RequestTest.java @@ -35,7 +35,11 @@ void requestUriWithQueryWithForwardSlash() { // Test that multiple values for the same query parameter are appropriately encoded. @Test void requestUriWithQueryWithMultipleValues() { - URI uri = new Request("GET", "/foo").withQueryParam("foo", "bar").withQueryParam("foo", "baz").getUri(); + URI uri = + new Request("GET", "/foo") + .withQueryParam("foo", "bar") + .withQueryParam("foo", "baz") + .getUri(); assertEquals("/foo?foo=bar&foo=baz", uri.toString()); } }