Skip to content

Commit 7e1696a

Browse files
committed
wip
1 parent 792bfd7 commit 7e1696a

File tree

2 files changed

+62
-7
lines changed

2 files changed

+62
-7
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,22 @@ JtdSchema compileRefSchema(JsonObject obj) {
315315
if (!(refValue instanceof JsonString str)) {
316316
throw new IllegalArgumentException("ref must be a string");
317317
}
318-
return new JtdSchema.RefSchema(str.value());
318+
String refName = str.value();
319+
320+
// Resolve reference against definitions
321+
JsonValue definitionsValue = members.get("definitions");
322+
if (!(definitionsValue instanceof JsonObject definitions)) {
323+
throw new IllegalArgumentException("ref requires definitions object at root level");
324+
}
325+
326+
JsonValue definitionValue = definitions.members().get(refName);
327+
if (definitionValue == null) {
328+
throw new IllegalArgumentException("ref '" + refName + "' not found in definitions");
329+
}
330+
331+
// Compile the referenced schema
332+
JtdSchema resolvedSchema = compileSchema(definitionValue);
333+
return new JtdSchema.RefSchema(refName, resolvedSchema);
319334
}
320335

321336
JtdSchema compileTypeSchema(JsonObject obj) {

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

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import jdk.sandbox.java.util.json.*;
44

5+
import java.time.OffsetDateTime;
6+
import java.time.format.DateTimeFormatter;
57
import java.util.List;
68

79
/// JTD Schema interface - validates JSON instances against JTD schemas
@@ -73,15 +75,17 @@ public boolean validateWithFrame(Jtd.Frame frame, java.util.List<String> errors,
7375
}
7476

7577
/// Ref schema - references a definition in the schema's definitions
76-
record RefSchema(String ref) implements JtdSchema {
78+
record RefSchema(String ref, JtdSchema resolvedSchema) implements JtdSchema {
7779
@Override
7880
public Jtd.Result validate(JsonValue instance) {
79-
throw new AssertionError("not implemented");
81+
return resolvedSchema.validate(instance);
8082
}
8183

8284
@Override
8385
public boolean validateWithFrame(Jtd.Frame frame, java.util.List<String> errors, boolean verboseErrors) {
84-
throw new AssertionError("not implemented");
86+
// Create new frame with the resolved schema but same instance, path, and crumbs
87+
Jtd.Frame resolvedFrame = new Jtd.Frame(resolvedSchema, frame.instance(), frame.ptr(), frame.crumbs());
88+
return resolvedSchema.validateWithFrame(resolvedFrame, errors, verboseErrors);
8589
}
8690
}
8791

@@ -139,8 +143,18 @@ Jtd.Result validateString(JsonValue instance, boolean verboseErrors) {
139143
}
140144

141145
Jtd.Result validateTimestamp(JsonValue instance, boolean verboseErrors) {
142-
if (instance instanceof JsonString ignored) {
143-
throw new AssertionError("not implemented");
146+
if (instance instanceof JsonString str) {
147+
try {
148+
// Parse using RFC 3339 format (ISO_OFFSET_DATE_TIME)
149+
OffsetDateTime.parse(str.value(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
150+
return Jtd.Result.success();
151+
} catch (Exception e) {
152+
// Invalid RFC 3339 timestamp format
153+
String error = verboseErrors
154+
? Jtd.Error.EXPECTED_TIMESTAMP.message(instance, instance.getClass().getSimpleName())
155+
: Jtd.Error.EXPECTED_TIMESTAMP.message(instance.getClass().getSimpleName());
156+
return Jtd.Result.failure(error);
157+
}
144158
}
145159
String error = verboseErrors
146160
? Jtd.Error.EXPECTED_TIMESTAMP.message(instance, instance.getClass().getSimpleName())
@@ -151,11 +165,37 @@ Jtd.Result validateTimestamp(JsonValue instance, boolean verboseErrors) {
151165
Jtd.Result validateInteger(JsonValue instance, String type, boolean verboseErrors) {
152166
if (instance instanceof JsonNumber num) {
153167
Number value = num.toNumber();
168+
169+
// Check if the number is not integral (has fractional part)
154170
if (value instanceof Double d && d != Math.floor(d)) {
155171
return Jtd.Result.failure(Jtd.Error.EXPECTED_INTEGER.message());
156172
}
157-
throw new AssertionError("not implemented");
173+
174+
// Convert to long for range checking
175+
long longValue = value.longValue();
176+
177+
// Check ranges according to RFC 8927 §2.2.3.1
178+
boolean valid = switch (type) {
179+
case "int8" -> longValue >= -128 && longValue <= 127;
180+
case "uint8" -> longValue >= 0 && longValue <= 255;
181+
case "int16" -> longValue >= -32768 && longValue <= 32767;
182+
case "uint16" -> longValue >= 0 && longValue <= 65535;
183+
case "int32" -> longValue >= -2147483648L && longValue <= 2147483647L;
184+
case "uint32" -> longValue >= 0 && longValue <= 4294967295L;
185+
default -> false;
186+
};
187+
188+
if (valid) {
189+
return Jtd.Result.success();
190+
}
191+
192+
// Range violation
193+
String error = verboseErrors
194+
? Jtd.Error.EXPECTED_NUMERIC_TYPE.message(instance, type, instance.getClass().getSimpleName())
195+
: Jtd.Error.EXPECTED_NUMERIC_TYPE.message(type, instance.getClass().getSimpleName());
196+
return Jtd.Result.failure(error);
158197
}
198+
159199
String error = verboseErrors
160200
? Jtd.Error.EXPECTED_NUMERIC_TYPE.message(instance, type, instance.getClass().getSimpleName())
161201
: Jtd.Error.EXPECTED_NUMERIC_TYPE.message(type, instance.getClass().getSimpleName());

0 commit comments

Comments
 (0)