@@ -18,6 +18,9 @@ public class Jtd {
1818 /// Top-level definitions map for ref resolution
1919 private final Map <String , JtdSchema > definitions = new java .util .HashMap <>();
2020
21+ /// Raw definition values for context-aware ref resolution
22+ private final Map <String , JsonValue > rawDefinitions = new java .util .HashMap <>();
23+
2124 /// Stack frame for iterative validation with path and offset tracking
2225 record Frame (JtdSchema schema , JsonValue instance , String ptr , Crumbs crumbs , String discriminatorKey ) {
2326 /// Constructor for normal validation without discriminator context
@@ -282,6 +285,11 @@ void pushChildFrames(Frame frame, java.util.Deque<Frame> stack) {
282285
283286 /// Compiles a JsonValue into a JtdSchema based on RFC 8927 rules
284287 JtdSchema compileSchema (JsonValue schema ) {
288+ return compileSchema (schema , false ); // Default: not from ref resolution
289+ }
290+
291+ /// Compiles a JsonValue into a JtdSchema with context-aware handling of {}
292+ JtdSchema compileSchema (JsonValue schema , boolean fromRef ) {
285293 if (!(schema instanceof JsonObject obj )) {
286294 throw new IllegalArgumentException ("Schema must be an object" );
287295 }
@@ -299,17 +307,20 @@ JtdSchema compileSchema(JsonValue schema) {
299307 JsonObject defsObj = (JsonObject ) obj .members ().get ("definitions" );
300308 for (String key : defsObj .members ().keySet ()) {
301309 if (definitions .get (key ) == null ) {
302- JtdSchema compiled = compileSchema (defsObj .members ().get (key ));
310+ JsonValue rawDef = defsObj .members ().get (key );
311+ rawDefinitions .put (key , rawDef ); // Store raw definition for context-aware ref resolution
312+ // Compile definitions with fromRef=true for compatibility mode
313+ JtdSchema compiled = compileSchema (rawDef , true );
303314 definitions .put (key , compiled );
304315 }
305316 }
306317 }
307318
308- return compileObjectSchema (obj );
319+ return compileObjectSchema (obj , fromRef );
309320 }
310321
311- /// Compiles an object schema according to RFC 8927
312- JtdSchema compileObjectSchema (JsonObject obj ) {
322+ /// Compiles an object schema according to RFC 8927 with context-aware handling
323+ JtdSchema compileObjectSchema (JsonObject obj , boolean fromRef ) {
313324 // Check for mutually-exclusive schema forms
314325 List <String > forms = new ArrayList <>();
315326 Map <String , JsonValue > members = obj .members ();
@@ -336,8 +347,17 @@ JtdSchema compileObjectSchema(JsonObject obj) {
336347 // Parse the specific schema form
337348 JtdSchema schema ;
338349
339- if (forms .isEmpty ()) {
340- // Empty schema - accepts any value
350+ // Context-aware handling of {} - RFC vs compatibility mode
351+ if (forms .isEmpty () && obj .members ().isEmpty ()) {
352+ if (fromRef ) {
353+ // Compatibility mode: {} from ref resolution behaves as EmptySchema (accept anything)
354+ schema = new JtdSchema .EmptySchema ();
355+ } else {
356+ // RFC mode: {} at root or direct context behaves as PropertiesSchema (no properties allowed)
357+ schema = new JtdSchema .PropertiesSchema (Map .of (), Map .of (), false );
358+ }
359+ } else if (forms .isEmpty ()) {
360+ // Empty schema with no explicit form - default to EmptySchema for backwards compatibility
341361 schema = new JtdSchema .EmptySchema ();
342362 } else {
343363 String form = forms .getFirst ();
@@ -483,6 +503,11 @@ JtdSchema compileDiscriminatorSchema(JsonObject obj) {
483503 return new JtdSchema .DiscriminatorSchema (discStr .value (), mapping );
484504 }
485505
506+ /// Gets raw definition value for context-aware ref resolution
507+ JsonValue getRawDefinition (String ref ) {
508+ return rawDefinitions .get (ref );
509+ }
510+
486511 /// Extracts and stores top-level definitions for ref resolution
487512 private Map <String , JtdSchema > parsePropertySchemas (JsonObject propsObj ) {
488513 Map <String , JtdSchema > schemas = new java .util .HashMap <>();
0 commit comments