Skip to content

Commit d2b185a

Browse files
Add types for all the Databricks error detail types. (#497)
## What changes are proposed in this pull request? This PR is a first step in adding support for all the Databricks error detail types. Specifically, this PR introduces AutoValue classes for each error detail and make sure that these are parsed properly. However, the types are not exposed yet in the actual DatabricksError exception, this will come in a subsequent PR. While it might not look as such, the change in `ApiErrorBody` is practically a no-op because: 1. The server can only return one error info. 2. Only error info types were extracted from the list of details. ## How is this tested? Unit tests focused on deserialization. NO_CHANGELOG=true
1 parent fcf14b7 commit d2b185a

File tree

18 files changed

+2294
-22
lines changed

18 files changed

+2294
-22
lines changed

databricks-sdk-java/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@
104104
<artifactId>jackson-datatype-jsr310</artifactId>
105105
<version>${jackson.version}</version>
106106
</dependency>
107+
<!-- Jackson Guava module needed to serialize/deserialize AutoValue classes -->
108+
<dependency>
109+
<groupId>com.fasterxml.jackson.datatype</groupId>
110+
<artifactId>jackson-datatype-guava</artifactId>
111+
<version>${jackson.version}</version>
112+
</dependency>
107113
<!-- Google Auto Value -->
108114
<dependency>
109115
<groupId>com.google.auto.value</groupId>

databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksError.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
* unrecoverable way and this exception should be thrown, potentially wrapped in another exception.
1515
*/
1616
public class DatabricksError extends DatabricksException {
17-
private static final String ERROR_INFO_TYPE = "type.googleapis.com/google.rpc.ErrorInfo";
18-
private final String message;
1917
private final Throwable cause;
2018
private final String errorCode;
2119
private final int statusCode;
@@ -51,14 +49,13 @@ private DatabricksError(
5149
List<ErrorDetail> details) {
5250
super(message, cause);
5351
this.errorCode = errorCode;
54-
this.message = message;
5552
this.cause = cause;
5653
this.statusCode = statusCode;
5754
this.details = details == null ? Collections.emptyList() : details;
5855
}
5956

6057
public List<ErrorDetail> getErrorInfo() {
61-
return this.getDetailsByType(ERROR_INFO_TYPE);
58+
return this.getDetailsByType("type.googleapis.com/google.rpc.ErrorInfo");
6259
}
6360

6461
public String getErrorCode() {

databricks-sdk-java/src/main/java/com/databricks/sdk/core/error/ApiErrorBody.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.databricks.sdk.core.error;
22

3+
import com.databricks.sdk.core.error.details.ErrorDetails;
34
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
45
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import java.util.Arrays;
7+
import java.util.Collections;
58
import java.util.List;
69

710
/**
@@ -21,21 +24,31 @@ public class ApiErrorBody {
2124

2225
public ApiErrorBody() {}
2326

27+
/**
28+
* Constructs an ApiErrorBody from the given parameters.
29+
*
30+
* <p>The error details are converted to a list of ErrorDetail objects. This only supports the
31+
* ErrorInfo type.
32+
*
33+
* @param errorCode The error code.
34+
* @param message The error message.
35+
* @param scimDetail The SCIM detail.
36+
*/
2437
public ApiErrorBody(
2538
@JsonProperty("error_code") String errorCode,
2639
@JsonProperty("message") String message,
2740
@JsonProperty("detail") String scimDetail,
2841
@JsonProperty("status") String scimStatus,
2942
@JsonProperty("scimType") String scimType,
3043
@JsonProperty("error") String api12Error,
31-
@JsonProperty("details") List<ErrorDetail> errorDetails) {
44+
@JsonProperty("details") ErrorDetails errorDetails) {
3245
this.errorCode = errorCode;
3346
this.message = message;
3447
this.scimDetail = scimDetail;
3548
this.scimStatus = scimStatus;
3649
this.scimType = scimType;
3750
this.api12Error = api12Error;
38-
this.errorDetails = errorDetails;
51+
this.errorDetails = fromDetails(errorDetails);
3952
}
4053

4154
public List<ErrorDetail> getErrorDetails() {
@@ -93,4 +106,26 @@ public String getApi12Error() {
93106
public void setApi12Error(String api12Error) {
94107
this.api12Error = api12Error;
95108
}
109+
110+
/**
111+
* Converts the error details to a list of ErrorDetail objects. This only supports the ErrorInfo
112+
* type.
113+
*
114+
* @param details The error details to convert.
115+
* @return A list of ErrorDetail objects.
116+
*/
117+
private static List<ErrorDetail> fromDetails(ErrorDetails details) {
118+
if (details == null) {
119+
return Collections.emptyList();
120+
}
121+
if (!details.errorInfo().isPresent()) {
122+
return Collections.emptyList();
123+
}
124+
return Arrays.asList(
125+
new ErrorDetail(
126+
"type.googleapis.com/google.rpc.ErrorInfo",
127+
details.errorInfo().get().reason(),
128+
details.errorInfo().get().domain(),
129+
details.errorInfo().get().metadata()));
130+
}
96131
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package com.databricks.sdk.core.error.details;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
6+
import com.google.auto.value.AutoValue;
7+
import java.util.Collections;
8+
import java.util.List;
9+
10+
/**
11+
* BadRequest describes violations in a client request. This error type focuses on the syntactic
12+
* aspects of the request.
13+
*
14+
* <p>BadRequest errors occur when the request format, structure, or content does not meet the
15+
* service's requirements. This is different from business logic errors or system failures - it
16+
* specifically indicates that the client sent a malformed or invalid request.
17+
*
18+
* <p>Examples of bad request violations might include:
19+
*
20+
* <ul>
21+
* <li>Missing required fields
22+
* <li>Invalid field values (wrong type, format, or range)
23+
* <li>Malformed JSON or XML
24+
* <li>Unsupported field combinations
25+
* <li>Invalid enum values
26+
* <li>Field length or size violations
27+
* </ul>
28+
*
29+
* <p>This information helps clients:
30+
*
31+
* <ul>
32+
* <li>Identify what's wrong with their request
33+
* <li>Fix the request format before retrying
34+
* <li>Understand the service's input requirements
35+
* <li>Implement proper input validation
36+
* </ul>
37+
*/
38+
@AutoValue
39+
@JsonDeserialize(builder = AutoValue_BadRequest.Builder.class)
40+
@JsonIgnoreProperties(ignoreUnknown = true)
41+
public abstract class BadRequest {
42+
43+
/**
44+
* Describes all field violations in the request.
45+
*
46+
* <p>This list contains details about each specific field or aspect of the request that violated
47+
* the service's requirements. Multiple violations can occur if the request has multiple problems.
48+
*
49+
* @return the list of field violations
50+
*/
51+
@JsonProperty("field_violations")
52+
public abstract List<BadRequestFieldViolation> fieldViolations();
53+
54+
/**
55+
* Creates a new builder for constructing BadRequest instances.
56+
*
57+
* @return a new builder instance
58+
*/
59+
public static Builder builder() {
60+
return new AutoValue_BadRequest.Builder();
61+
}
62+
63+
/** Builder for constructing BadRequest instances. */
64+
@AutoValue.Builder
65+
@JsonIgnoreProperties(ignoreUnknown = true)
66+
public abstract static class Builder {
67+
68+
/**
69+
* Sets the field violations.
70+
*
71+
* @param fieldViolations the list of field violations
72+
* @return this builder for method chaining
73+
*/
74+
@JsonProperty("field_violations")
75+
public abstract Builder setFieldViolations(List<BadRequestFieldViolation> fieldViolations);
76+
77+
/**
78+
* Builds the BadRequest instance.
79+
*
80+
* @return a new BadRequest instance
81+
*/
82+
public BadRequest build() {
83+
if (fieldViolations() == null) {
84+
setFieldViolations(Collections.emptyList());
85+
}
86+
return autoBuild();
87+
}
88+
89+
abstract List<BadRequestFieldViolation> fieldViolations();
90+
91+
abstract BadRequest autoBuild();
92+
}
93+
94+
/**
95+
* BadRequestFieldViolation describes a specific field violation in a request.
96+
*
97+
* <p>Each violation provides details about what specific field or aspect of the request was
98+
* invalid and how the client can fix it.
99+
*/
100+
@AutoValue
101+
@JsonDeserialize(builder = AutoValue_BadRequest_BadRequestFieldViolation.Builder.class)
102+
@JsonIgnoreProperties(ignoreUnknown = true)
103+
public abstract static class BadRequestFieldViolation {
104+
105+
/**
106+
* A path leading to a field in the request body.
107+
*
108+
* <p>This field identifies the specific location of the violation within the request structure.
109+
* The path format depends on the request format but typically follows a hierarchical structure.
110+
*
111+
* <p>Examples of field paths:
112+
*
113+
* <ul>
114+
* <li>"name" - top-level field
115+
* <li>"user.email" - nested field
116+
* <li>"items[0].id" - array element field
117+
* <li>"metadata.api_key" - deeply nested field
118+
* <li>"settings.notifications.enabled" - multi-level nested field
119+
* </ul>
120+
*
121+
* <p>This path helps clients quickly locate and fix the problematic field in their request.
122+
*
123+
* @return the path to the violating field
124+
*/
125+
@JsonProperty("field")
126+
public abstract String field();
127+
128+
/**
129+
* A description of why the request element is bad.
130+
*
131+
* <p>This field provides a human-readable explanation of what's wrong with the field and how to
132+
* fix it. The description should be clear enough for developers to understand and resolve the
133+
* issue.
134+
*
135+
* <p>Examples of field violation descriptions:
136+
*
137+
* <ul>
138+
* <li>"Field is required and cannot be empty"
139+
* <li>"Value must be a positive integer"
140+
* <li>"Invalid email format"
141+
* <li>"String length must be between 1 and 100 characters"
142+
* <li>"Unsupported enum value. Must be one of: [A, B, C]"
143+
* <li>"Field cannot contain special characters"
144+
* <li>"Date must be in ISO 8601 format (YYYY-MM-DD)"
145+
* </ul>
146+
*
147+
* @return description of why the field is invalid
148+
*/
149+
@JsonProperty("description")
150+
public abstract String description();
151+
152+
/**
153+
* Creates a new builder for constructing BadRequestFieldViolation instances.
154+
*
155+
* @return a new builder instance
156+
*/
157+
public static Builder builder() {
158+
return new AutoValue_BadRequest_BadRequestFieldViolation.Builder();
159+
}
160+
161+
/** Builder for constructing BadRequestFieldViolation instances. */
162+
@AutoValue.Builder
163+
@JsonIgnoreProperties(ignoreUnknown = true)
164+
public abstract static class Builder {
165+
166+
/**
167+
* Sets the field path.
168+
*
169+
* @param field the path to the violating field
170+
* @return this builder for method chaining
171+
*/
172+
@JsonProperty("field")
173+
public abstract Builder setField(String field);
174+
175+
/**
176+
* Sets the violation description.
177+
*
178+
* @param description description of why the field is invalid
179+
* @return this builder for method chaining
180+
*/
181+
@JsonProperty("description")
182+
public abstract Builder setDescription(String description);
183+
184+
/**
185+
* Builds the BadRequestFieldViolation instance.
186+
*
187+
* @return a new BadRequestFieldViolation instance
188+
*/
189+
public abstract BadRequestFieldViolation build();
190+
}
191+
}
192+
}

0 commit comments

Comments
 (0)