@@ -599,6 +599,100 @@ void testCircularReferenceDetection() throws Exception {
599599 assertThat (childNode .has ("properties" )).isFalse ();
600600 }
601601
602+ /**
603+ * Test that several properties referencing the same component are all expanded and
604+ * not mistaken for circular references.
605+ * @throws Exception if JSON parsing fails
606+ */
607+ @ SuppressWarnings ("unchecked" )
608+ @ Test
609+ void testSiblingReferencesToSameSchemaAreExpanded () throws Exception {
610+ Components components = new Components ();
611+
612+ Schema <Object > commonSchema = new Schema <>();
613+ commonSchema .setType ("object" );
614+ Map <String , Schema > commonProps = new LinkedHashMap <>();
615+ commonProps .put ("street" , new StringSchema ());
616+ commonSchema .setProperties (commonProps );
617+ components .addSchemas ("Common" , commonSchema );
618+
619+ Schema <?> firstRef = new Schema <>();
620+ firstRef .set$ref ("#/components/schemas/Common" );
621+ Schema <?> secondRef = new Schema <>();
622+ secondRef .set$ref ("#/components/schemas/Common" );
623+ Schema <Object > personSchema = new Schema <>();
624+ personSchema .setType ("object" );
625+ Map <String , Schema > personProps = new LinkedHashMap <>();
626+ personProps .put ("home" , firstRef );
627+ personProps .put ("work" , secondRef );
628+ personSchema .setProperties (personProps );
629+ components .addSchemas ("Person" , personSchema );
630+
631+ Schema <?> bodyRef = new Schema <>();
632+ bodyRef .set$ref ("#/components/schemas/Person" );
633+ Operation operation = new Operation ();
634+ operation .setRequestBody (new RequestBody ()
635+ .content (new Content ().addMediaType ("application/json" , new MediaType ().schema (bodyRef )))
636+ .required (true ));
637+
638+ String schemaJson = OpenApiSchemaConverter .buildInputSchema ("/test" , operation , components );
639+ JsonNode properties = objectMapper .readTree (schemaJson ).get ("properties" ).get ("body" ).get ("properties" );
640+
641+ assertThat (properties .get ("home" ).get ("properties" ).has ("street" )).isTrue ();
642+ assertThat (properties .get ("work" ).get ("properties" ).has ("street" )).isTrue ();
643+ }
644+
645+ /**
646+ * Test that a schema reused in sibling branches is expanded everywhere while a real
647+ * cycle below it is still cut off.
648+ * @throws Exception if JSON parsing fails
649+ */
650+ @ SuppressWarnings ("unchecked" )
651+ @ Test
652+ void testSiblingReferencesStillBreakCircularReferences () throws Exception {
653+ Components components = new Components ();
654+
655+ Schema <?> selfRef = new Schema <>();
656+ selfRef .set$ref ("#/components/schemas/Node" );
657+ Schema <Object > nodeSchema = new Schema <>();
658+ nodeSchema .setType ("object" );
659+ Map <String , Schema > nodeProps = new LinkedHashMap <>();
660+ nodeProps .put ("name" , new StringSchema ());
661+ nodeProps .put ("child" , selfRef );
662+ nodeSchema .setProperties (nodeProps );
663+ components .addSchemas ("Node" , nodeSchema );
664+
665+ Schema <?> leftRef = new Schema <>();
666+ leftRef .set$ref ("#/components/schemas/Node" );
667+ Schema <?> rightRef = new Schema <>();
668+ rightRef .set$ref ("#/components/schemas/Node" );
669+ Schema <Object > treeSchema = new Schema <>();
670+ treeSchema .setType ("object" );
671+ Map <String , Schema > treeProps = new LinkedHashMap <>();
672+ treeProps .put ("left" , leftRef );
673+ treeProps .put ("right" , rightRef );
674+ treeSchema .setProperties (treeProps );
675+ components .addSchemas ("Tree" , treeSchema );
676+
677+ Schema <?> bodyRef = new Schema <>();
678+ bodyRef .set$ref ("#/components/schemas/Tree" );
679+ Operation operation = new Operation ();
680+ operation .setRequestBody (new RequestBody ()
681+ .content (new Content ().addMediaType ("application/json" , new MediaType ().schema (bodyRef )))
682+ .required (true ));
683+
684+ String schemaJson = OpenApiSchemaConverter .buildInputSchema ("/test" , operation , components );
685+ JsonNode properties = objectMapper .readTree (schemaJson ).get ("properties" ).get ("body" ).get ("properties" );
686+
687+ for (String branch : List .of ("left" , "right" )) {
688+ JsonNode node = properties .get (branch );
689+ assertThat (node .get ("properties" ).has ("name" )).isTrue ();
690+ JsonNode child = node .get ("properties" ).get ("child" );
691+ assertThat (child .get ("type" ).asText ()).isEqualTo ("object" );
692+ assertThat (child .has ("properties" )).isFalse ();
693+ }
694+ }
695+
602696 /**
603697 * Test that validation constraints are correctly propagated to the JSON Schema.
604698 * @throws Exception if JSON parsing fails
0 commit comments