Skip to content

Commit efe179e

Browse files
committed
Improve error messages
1 parent e273ae1 commit efe179e

File tree

3 files changed

+109
-13
lines changed

3 files changed

+109
-13
lines changed

jsonschema/src/main/java/io/apicurio/schema/validation/json/JsonValidationResult.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*/
2424
public class JsonValidationResult {
2525

26-
protected static final JsonValidationResult SUCCESS = successfull();
26+
protected static final JsonValidationResult SUCCESS = successful();
2727

2828
private boolean success;
2929
private List<ValidationError> validationErrors;
@@ -54,7 +54,7 @@ public static JsonValidationResult fromErrors(List<ValidationError> errors) {
5454
return new JsonValidationResult(errors);
5555
}
5656

57-
public static JsonValidationResult successfull() {
57+
public static JsonValidationResult successful() {
5858
return new JsonValidationResult(null);
5959
}
6060

jsonschema/src/main/java/io/apicurio/schema/validation/json/JsonValidator.java

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.apicurio.registry.resolver.config.SchemaResolverConfig;
3232
import io.apicurio.registry.resolver.data.Record;
3333
import io.apicurio.registry.resolver.strategy.ArtifactReference;
34+
import io.apicurio.registry.rest.client.models.ProblemDetails;
3435
import io.apicurio.registry.types.ArtifactType;
3536
import io.apicurio.registry.utils.IoUtil;
3637
import org.json.JSONObject;
@@ -86,9 +87,15 @@ protected JsonValidator() {
8687
*/
8788
public JsonValidationResult validateByArtifactReference(Object bean) {
8889
Objects.requireNonNull(this.artifactReference, "ArtifactReference must be provided when creating JsonValidator in order to use this feature");
89-
SchemaLookupResult<JsonSchema> schema = this.schemaResolver.resolveSchemaByArtifactReference(this.artifactReference);
90-
JsonNode jsonPayload = createJSONObject(bean);
91-
return validate(schema.getParsedSchema().getParsedSchema(), jsonPayload);
90+
try {
91+
SchemaLookupResult<JsonSchema> schema = this.schemaResolver.resolveSchemaByArtifactReference(this.artifactReference);
92+
JsonNode jsonPayload = createJSONObject(bean);
93+
return validate(schema.getParsedSchema().getParsedSchema(), jsonPayload);
94+
} catch (Exception e) {
95+
return JsonValidationResult.fromErrors(List.of(
96+
new ValidationError("Failed to resolve schema from registry: " + extractErrorMessage(e), "SCHEMA_RESOLUTION_ERROR")
97+
));
98+
}
9299
}
93100

94101
/**
@@ -101,9 +108,15 @@ public JsonValidationResult validateByArtifactReference(Object bean) {
101108
* @return JsonValidationResult
102109
*/
103110
public JsonValidationResult validate(Record<Object> record) {
104-
SchemaLookupResult<JsonSchema> schema = this.schemaResolver.resolveSchema(record);
105-
JsonNode jsonPayload = createJSONObject(record.payload());
106-
return validate(schema.getParsedSchema().getParsedSchema(), jsonPayload);
111+
try {
112+
SchemaLookupResult<JsonSchema> schema = this.schemaResolver.resolveSchema(record);
113+
JsonNode jsonPayload = createJSONObject(record.payload());
114+
return validate(schema.getParsedSchema().getParsedSchema(), jsonPayload);
115+
} catch (Exception e) {
116+
return JsonValidationResult.fromErrors(List.of(
117+
new ValidationError("Failed to resolve schema from registry: " + extractErrorMessage(e), "SCHEMA_RESOLUTION_ERROR")
118+
));
119+
}
107120
}
108121

109122
protected JsonValidationResult validate(JsonSchema schema, JsonNode jsonPayload) {
@@ -142,6 +155,41 @@ private List<ValidationError> extractValidationErrors(Set<ValidationMessage> val
142155
return errors;
143156
}
144157

158+
private String extractErrorMessage(Exception e) {
159+
StringBuilder errorMessage = new StringBuilder();
160+
161+
// Start with the exception type and message
162+
errorMessage.append(e.getClass().getSimpleName());
163+
String message = getDetailedMessage(e);
164+
if (message != null && !message.isEmpty()) {
165+
errorMessage.append(": ").append(message);
166+
}
167+
168+
// Add cause chain for more context
169+
Throwable cause = e.getCause();
170+
while (cause != null) {
171+
errorMessage.append(" | Caused by: ").append(cause.getClass().getSimpleName());
172+
String causeMessage = getDetailedMessage(cause);
173+
if (causeMessage != null && !causeMessage.isEmpty()) {
174+
errorMessage.append(": ").append(causeMessage);
175+
}
176+
cause = cause.getCause();
177+
}
178+
179+
return errorMessage.toString();
180+
}
181+
182+
private String getDetailedMessage(Throwable throwable) {
183+
// Special handling for ProblemDetails from Apicurio Registry REST client
184+
if (throwable instanceof ProblemDetails) {
185+
String detail = ((ProblemDetails) throwable).getDetail();
186+
if (detail != null && !detail.isEmpty()) {
187+
return detail;
188+
}
189+
}
190+
return throwable.getMessage();
191+
}
192+
145193
public static class JsonSchemaParser implements SchemaParser<JsonSchema, Object> {
146194
@Override
147195
public String artifactType() {

protobuf/src/main/java/io/apicurio/schema/validation/protobuf/ProtobufValidator.java

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.apicurio.registry.resolver.config.SchemaResolverConfig;
77
import io.apicurio.registry.resolver.data.Record;
88
import io.apicurio.registry.resolver.strategy.ArtifactReference;
9+
import io.apicurio.registry.rest.client.models.ProblemDetails;
910
import io.apicurio.registry.rules.compatibility.protobuf.ProtobufCompatibilityCheckerLibrary;
1011
import io.apicurio.registry.utils.protobuf.schema.ProtobufFile;
1112
import io.apicurio.registry.utils.protobuf.schema.ProtobufSchema;
@@ -54,9 +55,15 @@ protected ProtobufValidator() {
5455
public ProtobufValidationResult validateByArtifactReference(Message bean) {
5556
Objects.requireNonNull(this.artifactReference,
5657
"ArtifactReference must be provided when creating JsonValidator in order to use this feature");
57-
SchemaLookupResult<ProtobufSchema> schema = this.schemaResolver.resolveSchemaByArtifactReference(
58-
this.artifactReference);
59-
return validate(schema.getParsedSchema(), new ProtobufRecord(bean, null));
58+
try {
59+
SchemaLookupResult<ProtobufSchema> schema = this.schemaResolver.resolveSchemaByArtifactReference(
60+
this.artifactReference);
61+
return validate(schema.getParsedSchema(), new ProtobufRecord(bean, null));
62+
} catch (Exception e) {
63+
return ProtobufValidationResult.fromErrors(List.of(
64+
new ValidationError("Failed to resolve schema from registry: " + extractErrorMessage(e), "SCHEMA_RESOLUTION_ERROR")
65+
));
66+
}
6067
}
6168

6269
/**
@@ -69,8 +76,14 @@ public ProtobufValidationResult validateByArtifactReference(Message bean) {
6976
* @return ProtobufValidationResult
7077
*/
7178
public ProtobufValidationResult validate(Record<Message> record) {
72-
SchemaLookupResult<ProtobufSchema> schema = this.schemaResolver.resolveSchema(record);
73-
return validate(schema.getParsedSchema(), record);
79+
try {
80+
SchemaLookupResult<ProtobufSchema> schema = this.schemaResolver.resolveSchema(record);
81+
return validate(schema.getParsedSchema(), record);
82+
} catch (Exception e) {
83+
return ProtobufValidationResult.fromErrors(List.of(
84+
new ValidationError("Failed to resolve schema from registry: " + extractErrorMessage(e), "SCHEMA_RESOLUTION_ERROR")
85+
));
86+
}
7487
}
7588

7689
protected ProtobufValidationResult validate(ParsedSchema<ProtobufSchema> schema, Record<Message> record) {
@@ -100,4 +113,39 @@ private List<ProtobufDifference> validate(ParsedSchema<ProtobufSchema> schemaFro
100113
fileAfter);
101114
return checker.findDifferences();
102115
}
116+
117+
private String extractErrorMessage(Exception e) {
118+
StringBuilder errorMessage = new StringBuilder();
119+
120+
// Start with the exception type and message
121+
errorMessage.append(e.getClass().getSimpleName());
122+
String message = getDetailedMessage(e);
123+
if (message != null && !message.isEmpty()) {
124+
errorMessage.append(": ").append(message);
125+
}
126+
127+
// Add cause chain for more context
128+
Throwable cause = e.getCause();
129+
while (cause != null) {
130+
errorMessage.append(" | Caused by: ").append(cause.getClass().getSimpleName());
131+
String causeMessage = getDetailedMessage(cause);
132+
if (causeMessage != null && !causeMessage.isEmpty()) {
133+
errorMessage.append(": ").append(causeMessage);
134+
}
135+
cause = cause.getCause();
136+
}
137+
138+
return errorMessage.toString();
139+
}
140+
141+
private String getDetailedMessage(Throwable throwable) {
142+
// Special handling for ProblemDetails from Apicurio Registry REST client
143+
if (throwable instanceof ProblemDetails) {
144+
String detail = ((ProblemDetails) throwable).getDetail();
145+
if (detail != null && !detail.isEmpty()) {
146+
return detail;
147+
}
148+
}
149+
return throwable.getMessage();
150+
}
103151
}

0 commit comments

Comments
 (0)