Skip to content

Commit a65735c

Browse files
committed
tidy
1 parent 9e90c5e commit a65735c

File tree

1 file changed

+30
-176
lines changed

1 file changed

+30
-176
lines changed

json-java21-jtd/src/main/java/json/java21/jtd/JtdSchema.java

Lines changed: 30 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,25 @@
1111
/// Following RFC 8927 specification with eight mutually-exclusive schema forms
1212
sealed interface JtdSchema {
1313

14-
/// Validates a JSON instance against this schema
15-
/// @param instance The JSON value to validate
16-
/// @return Result containing errors if validation fails
17-
Jtd.Result validate(JsonValue instance);
14+
/// Core frame-based validation that all schema variants must implement.
15+
/// @param frame Current validation frame
16+
/// @param errors Accumulates error messages
17+
/// @param verboseErrors Whether to include verbose error details
18+
/// @return true if valid, false otherwise
19+
boolean validateWithFrame(Frame frame, java.util.List<String> errors, boolean verboseErrors);
1820

19-
/// Validates a JSON instance against this schema using stack-based validation
20-
/// @param frame The current validation frame containing schema, instance, path, and context
21-
/// @param errors List to accumulate error messages
22-
/// @param verboseErrors Whether to include full JSON values in error messages
23-
/// @return true if validation passes, false if validation fails
24-
default boolean validateWithFrame(Frame frame, java.util.List<String> errors, boolean verboseErrors) {
25-
// Default implementation delegates to existing validate method for backward compatibility
26-
Jtd.Result result = validate(frame.instance(), verboseErrors);
27-
if (!result.isValid()) {
28-
errors.addAll(result.errors());
29-
return false;
30-
}
31-
return true;
32-
}
33-
34-
/// Validates a JSON instance against this schema with optional verbose errors
35-
/// @param instance The JSON value to validate
36-
/// @param verboseErrors Whether to include full JSON values in error messages
37-
/// @return Result containing errors if validation fails
21+
/// Default verbose-capable validation entrypoint constructing a root frame.
3822
default Jtd.Result validate(JsonValue instance, boolean verboseErrors) {
39-
// Default implementation delegates to existing validate method
40-
// Individual schema implementations can override for verbose error support
41-
return validate(instance);
23+
final var errors = new ArrayList<String>();
24+
final var valid = validateWithFrame(new Frame(this, instance, "#", Crumbs.root()), errors, verboseErrors);
25+
return valid ? Jtd.Result.success() : Jtd.Result.failure(errors);
4226
}
43-
27+
28+
/// Non-verbose validation delegates to verbose variant.
29+
default Jtd.Result validate(JsonValue instance) {
30+
return validate(instance, false);
31+
}
32+
4433
/// Nullable schema wrapper - allows null values
4534
record NullableSchema(JtdSchema wrapped) implements JtdSchema {
4635
@Override
@@ -113,22 +102,6 @@ record TypeSchema(String type) implements JtdSchema {
113102
private static final java.util.regex.Pattern RFC3339 = java.util.regex.Pattern.compile(
114103
"^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:(\\d{2}|60)(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2}))$"
115104
);
116-
117-
@Override
118-
public Jtd.Result validate(JsonValue instance) {
119-
// Delegate to stack-based validation for consistency
120-
List<String> errors = new ArrayList<>();
121-
boolean valid = validateWithFrame(new Frame(this, instance, "#", Crumbs.root()), errors, false);
122-
return valid ? Jtd.Result.success() : Jtd.Result.failure(errors);
123-
}
124-
125-
@Override
126-
public Jtd.Result validate(JsonValue instance, boolean verboseErrors) {
127-
// Delegate to stack-based validation for consistency
128-
List<String> errors = new ArrayList<>();
129-
boolean valid = validateWithFrame(new Frame(this, instance, "#", Crumbs.root()), errors, verboseErrors);
130-
return valid ? Jtd.Result.success() : Jtd.Result.failure(errors);
131-
}
132105

133106
@SuppressWarnings("ClassEscapesDefinedScope")
134107
@Override
@@ -143,11 +116,11 @@ public boolean validateWithFrame(Frame frame, java.util.List<String> errors, boo
143116
default -> {
144117
String error = Jtd.Error.UNKNOWN_TYPE.message(type);
145118
errors.add(Jtd.enrichedError(error, frame, instance));
146-
yield false;
119+
yield false;
147120
}
148121
};
149122
}
150-
123+
151124
boolean validateBooleanWithFrame(Frame frame, java.util.List<String> errors, boolean verboseErrors) {
152125
JsonValue instance = frame.instance();
153126
if (instance instanceof JsonBoolean) {
@@ -191,108 +164,17 @@ boolean validateTimestampWithFrame(Frame frame, java.util.List<String> errors, b
191164
errors.add(Jtd.enrichedError(error, frame, instance));
192165
return false;
193166
}
194-
195-
Jtd.Result validateBoolean(JsonValue instance, boolean verboseErrors) {
196-
if (instance instanceof JsonBoolean) {
197-
return Jtd.Result.success();
198-
}
199-
String error = verboseErrors
200-
? Jtd.Error.EXPECTED_BOOLEAN.message(instance, instance.getClass().getSimpleName())
201-
: Jtd.Error.EXPECTED_BOOLEAN.message(instance.getClass().getSimpleName());
202-
return Jtd.Result.failure(error);
203-
}
204-
205-
Jtd.Result validateString(JsonValue instance, boolean verboseErrors) {
206-
if (instance instanceof JsonString) {
207-
return Jtd.Result.success();
208-
}
209-
String error = verboseErrors
210-
? Jtd.Error.EXPECTED_STRING.message(instance, instance.getClass().getSimpleName())
211-
: Jtd.Error.EXPECTED_STRING.message(instance.getClass().getSimpleName());
212-
return Jtd.Result.failure(error);
213-
}
214-
215-
Jtd.Result validateTimestamp(JsonValue instance, boolean verboseErrors) {
216-
if (instance instanceof JsonString str) {
217-
String value = str.value();
218-
if (RFC3339.matcher(value).matches()) {
219-
try {
220-
// Replace :60 with :59 to allow leap seconds through parsing
221-
String normalized = value.replace(":60", ":59");
222-
OffsetDateTime.parse(normalized, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
223-
return Jtd.Result.success();
224-
} catch (Exception ignore) {}
225-
}
226-
}
227-
String error = verboseErrors
228-
? Jtd.Error.EXPECTED_TIMESTAMP.message(instance, instance.getClass().getSimpleName())
229-
: Jtd.Error.EXPECTED_TIMESTAMP.message(instance.getClass().getSimpleName());
230-
return Jtd.Result.failure(error);
231-
}
232167

233-
Jtd.Result validateInteger(JsonValue instance, String type, boolean verboseErrors) {
234-
if (instance instanceof JsonNumber num) {
235-
Number value = num.toNumber();
236-
237-
// Check for fractional component first (applies to all Number types)
238-
if (hasFractionalComponent(value)) {
239-
return Jtd.Result.failure(Jtd.Error.EXPECTED_INTEGER.message());
240-
}
241-
242-
// Handle precision loss for large Double values
243-
if (value instanceof Double d) {
244-
if (d > Long.MAX_VALUE || d < Long.MIN_VALUE) {
245-
String error = verboseErrors
246-
? Jtd.Error.EXPECTED_NUMERIC_TYPE.message(instance, type, "out of range")
247-
: Jtd.Error.EXPECTED_NUMERIC_TYPE.message(type, "out of range");
248-
return Jtd.Result.failure(error);
249-
}
250-
}
251-
252-
// Convert to long for range checking
253-
long longValue = value.longValue();
254-
255-
// Check ranges according to RFC 8927 §2.2.3.1
256-
boolean valid = switch (type) {
257-
case "int8" -> longValue >= -128 && longValue <= 127;
258-
case "uint8" -> longValue >= 0 && longValue <= 255;
259-
case "int16" -> longValue >= -32768 && longValue <= 32767;
260-
case "uint16" -> longValue >= 0 && longValue <= 65535;
261-
case "int32" -> longValue >= -2147483648L && longValue <= 2147483647L;
262-
case "uint32" -> longValue >= 0 && longValue <= 4294967295L;
263-
default -> false;
264-
};
265-
266-
if (valid) {
267-
return Jtd.Result.success();
268-
}
269-
270-
// Range violation
271-
String error = verboseErrors
272-
? Jtd.Error.EXPECTED_NUMERIC_TYPE.message(instance, type, instance.getClass().getSimpleName())
273-
: Jtd.Error.EXPECTED_NUMERIC_TYPE.message(type, instance.getClass().getSimpleName());
274-
return Jtd.Result.failure(error);
275-
}
276-
277-
String error = verboseErrors
278-
? Jtd.Error.EXPECTED_NUMERIC_TYPE.message(instance, type, instance.getClass().getSimpleName())
279-
: Jtd.Error.EXPECTED_NUMERIC_TYPE.message(type, instance.getClass().getSimpleName());
280-
return Jtd.Result.failure(error);
281-
}
282-
283168
private boolean hasFractionalComponent(Number value) {
284-
if (value == null) return false;
285-
if (value instanceof Double d) {
286-
return d != Math.floor(d);
287-
}
288-
if (value instanceof Float f) {
289-
return f != Math.floor(f);
290-
}
291-
if (value instanceof java.math.BigDecimal bd) {
292-
return bd.remainder(java.math.BigDecimal.ONE).signum() != 0;
293-
}
294-
// Long, Integer, Short, Byte are always integers
295-
return false;
169+
return switch (value) {
170+
case null -> false;
171+
case Double d -> d != Math.floor(d);
172+
case Float f -> f != Math.floor(f);
173+
case java.math.BigDecimal bd -> bd.remainder(java.math.BigDecimal.ONE).signum() != 0;
174+
default ->
175+
// Long, Integer, Short, Byte are always integers
176+
false;
177+
};
296178
}
297179

298180
boolean validateIntegerWithFrame(Frame frame, String type, java.util.List<String> errors, boolean verboseErrors) {
@@ -358,36 +240,11 @@ boolean validateFloatWithFrame(Frame frame, String type, java.util.List<String>
358240
errors.add(Jtd.enrichedError(error, frame, instance));
359241
return false;
360242
}
361-
362-
Jtd.Result validateFloat(JsonValue instance, String type, boolean verboseErrors) {
363-
if (instance instanceof JsonNumber) {
364-
return Jtd.Result.success();
365-
}
366-
String error = verboseErrors
367-
? Jtd.Error.EXPECTED_NUMERIC_TYPE.message(instance, type, instance.getClass().getSimpleName())
368-
: Jtd.Error.EXPECTED_NUMERIC_TYPE.message(type, instance.getClass().getSimpleName());
369-
return Jtd.Result.failure(error);
370-
}
243+
371244
}
372245

373246
/// Enum schema - validates against a set of string values
374247
record EnumSchema(List<String> values) implements JtdSchema {
375-
@Override
376-
public Jtd.Result validate(JsonValue instance) {
377-
// Delegate to stack-based validation for consistency
378-
List<String> errors = new ArrayList<>();
379-
boolean valid = validateWithFrame(new Frame(this, instance, "#", Crumbs.root()), errors, false);
380-
return valid ? Jtd.Result.success() : Jtd.Result.failure(errors);
381-
}
382-
383-
@Override
384-
public Jtd.Result validate(JsonValue instance, boolean verboseErrors) {
385-
// Delegate to stack-based validation for consistency
386-
List<String> errors = new ArrayList<>();
387-
boolean valid = validateWithFrame(new Frame(this, instance, "#", Crumbs.root()), errors, verboseErrors);
388-
return valid ? Jtd.Result.success() : Jtd.Result.failure(errors);
389-
}
390-
391248
@SuppressWarnings("ClassEscapesDefinedScope")
392249
@Override
393250
public boolean validateWithFrame(Frame frame, java.util.List<String> errors, boolean verboseErrors) {
@@ -444,9 +301,7 @@ public boolean validateWithFrame(Frame frame, java.util.List<String> errors, boo
444301
JsonValue instance = frame.instance();
445302

446303
if (!(instance instanceof JsonArray)) {
447-
String error = verboseErrors
448-
? Jtd.Error.EXPECTED_ARRAY.message(instance, instance.getClass().getSimpleName())
449-
: Jtd.Error.EXPECTED_ARRAY.message(instance.getClass().getSimpleName());
304+
String error = Jtd.Error.EXPECTED_ARRAY.message(instance, instance.getClass().getSimpleName());
450305
String enrichedError = Jtd.enrichedError(error, frame, instance);
451306
errors.add(enrichedError);
452307
return false;
@@ -644,7 +499,6 @@ public Jtd.Result validate(JsonValue instance, boolean verboseErrors) {
644499
return Jtd.Result.success();
645500
}
646501

647-
// Otherwise, validate against the chosen variant schema
648502
return variantSchema.validate(instance, verboseErrors);
649503
}
650504

@@ -683,7 +537,7 @@ public boolean validateWithFrame(Frame frame, java.util.List<String> errors, boo
683537
return false;
684538
}
685539

686-
// For DiscriminatorSchema, push the variant schema for validation
540+
// Variant schema will be pushed by caller
687541
return true;
688542
}
689543
}

0 commit comments

Comments
 (0)