11package io .zenwave360 .jsonrefparser ;
22
33import com .fasterxml .jackson .annotation .JsonInclude ;
4+ import com .fasterxml .jackson .core .JsonGenerator ;
45import com .fasterxml .jackson .core .JsonProcessingException ;
5- import com .fasterxml .jackson .databind .DeserializationFeature ;
6- import com .fasterxml .jackson .databind .ObjectMapper ;
7- import com .fasterxml .jackson .databind .SerializationFeature ;
6+ import com .fasterxml .jackson .databind .*;
87import com .fasterxml .jackson .dataformat .yaml .YAMLFactory ;
8+ import com .fasterxml .jackson .databind .module .SimpleModule ;
99import io .zenwave360 .jsonrefparser .$RefParserOptions .OnMissing ;
1010import io .zenwave360 .jsonrefparser .resolver .HttpResolver ;
1111import io .zenwave360 .jsonrefparser .resolver .Resolver ;
1616import java .io .File ;
1717import java .io .IOException ;
1818import java .net .URI ;
19- import java .util .List ;
20- import java .util .Map ;
19+ import java .util .*;
2120
2221import static io .zenwave360 .jsonrefparser .$RefParserOptions .OnCircular .FAIL ;
2322
@@ -27,6 +26,10 @@ public class ParserTest {
2726 mapper .configure (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
2827 mapper .configure (SerializationFeature .FAIL_ON_EMPTY_BEANS , false );
2928 mapper .setSerializationInclusion (JsonInclude .Include .NON_EMPTY );
29+
30+ SimpleModule module = new SimpleModule ();
31+ module .addSerializer ((Class <Map <?, ?>>) (Class <?>) Map .class , new CycleBreakingMapSerializer ());
32+ mapper .registerModule (module );
3033 }
3134
3235 private void assertNoRefs (Object object ) throws JsonProcessingException {
@@ -193,8 +196,34 @@ public void testDereferenceAndMerge_MultipleAllOf() throws IOException {
193196 $Refs refs = parser .dereference ().mergeAllOf ().getRefs ();
194197
195198 assertNoRefs (refs .schema ());
199+ assertNoAllOfs (refs .schema ());
200+
201+ // Test merged properties from Test1 (test1a, test1b)
202+ var test1Properties = (Map ) refs .get ("$.components.schemas.Test1.properties" );
203+ Assert .assertEquals (2 , test1Properties .size ());
204+ Assert .assertTrue (test1Properties .containsKey ("test1a" ));
205+ Assert .assertTrue (test1Properties .containsKey ("test1b" ));
206+ Assert .assertEquals ("string" , ((Map ) test1Properties .get ("test1a" )).get ("type" ));
207+ Assert .assertEquals ("string" , ((Map ) test1Properties .get ("test1b" )).get ("type" ));
208+
209+ // Test merged properties from Test2 (test2a, test2b)
210+ var test2Properties = (Map ) refs .get ("$.components.schemas.Test2.properties" );
211+ Assert .assertEquals (2 , test2Properties .size ());
212+ Assert .assertTrue (test2Properties .containsKey ("test2a" ));
213+ Assert .assertTrue (test2Properties .containsKey ("test2b" ));
214+
215+ // Test final merged Test schema contains all 4 properties
196216 var properties = (Map ) refs .get ("$.components.schemas.Test.properties" );
197217 Assert .assertEquals (4 , properties .size ());
218+ Assert .assertTrue (properties .containsKey ("test1a" ));
219+ Assert .assertTrue (properties .containsKey ("test1b" ));
220+ Assert .assertTrue (properties .containsKey ("test2a" ));
221+ Assert .assertTrue (properties .containsKey ("test2b" ));
222+
223+ // Verify Test schema maintains its object type
224+ var testSchema = (Map ) refs .get ("$.components.schemas.Test" );
225+ Assert .assertEquals ("object" , testSchema .get ("type" ));
226+ Assert .assertFalse (testSchema .containsKey ("allOf" ));
198227 }
199228
200229 @ Test
@@ -204,8 +233,32 @@ public void testDereferenceAndMerge_MultipleAllOf2() throws IOException {
204233 $Refs refs = parser .dereference ().mergeAllOf ().getRefs ();
205234
206235 assertNoRefs (refs .schema ());
236+ assertNoAllOfs (refs .schema ());
237+
238+ // Test Test1b has merged properties (test1b, test1c)
239+ var test1bProperties = (Map ) refs .get ("$.components.schemas.Test1b.properties" );
240+ Assert .assertEquals (2 , test1bProperties .size ());
241+ Assert .assertTrue (test1bProperties .containsKey ("test1b" ));
242+ Assert .assertTrue (test1bProperties .containsKey ("test1c" ));
243+
244+ // Test Test1 has all 3 properties (test1a from itself + test1b, test1c from Test1b)
245+ var test1Properties = (Map ) refs .get ("$.components.schemas.Test1.properties" );
246+ Assert .assertEquals (3 , test1Properties .size ());
247+ Assert .assertTrue (test1Properties .containsKey ("test1a" ));
248+ Assert .assertTrue (test1Properties .containsKey ("test1b" ));
249+ Assert .assertTrue (test1Properties .containsKey ("test1c" ));
250+
251+ // Test final Test schema has all 5 properties
207252 var properties = (Map ) refs .get ("$.components.schemas.Test.properties" );
208253 Assert .assertEquals (5 , properties .size ());
254+ Assert .assertTrue (properties .containsKey ("test1a" ));
255+ Assert .assertTrue (properties .containsKey ("test1b" ));
256+ Assert .assertTrue (properties .containsKey ("test1c" ));
257+ Assert .assertTrue (properties .containsKey ("test2a" ));
258+ Assert .assertTrue (properties .containsKey ("test2b" ));
259+
260+ // Verify no circular references detected
261+ Assert .assertFalse (refs .circular );
209262 }
210263
211264 @ Test
@@ -358,25 +411,51 @@ public void testDereferenceOnMissingFail() throws IOException {
358411 }
359412
360413 @ Test
361- @ Ignore
362414 public void testMergeAllOfRecursive () throws IOException {
363415 File file = new File ("src/test/resources/asyncapi/orders-model.yml" );
364416 $RefParser parser = new $RefParser (file ).parse ();
365417 $Refs refs = parser .dereference ().mergeAllOf ().getRefs ();
366- System .out .println (mapper .writerWithDefaultPrettyPrinter ().writeValueAsString (refs .schema ()));
418+ // System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(refs.schema()));
419+ Assert .assertTrue (refs .circular );
367420 assertNoRefs (refs .schema ());
368421 assertNoAllOfs (refs .schema ());
369422 }
370423
371424 @ Test
372- // @Ignore
373425 public void testDetectCircularRecursive () throws IOException {
374426 File file = new File ("src/test/resources/asyncapi/orders-model.yml" );
375427 $RefParser parser = new $RefParser (file ).parse ();
376428 $Refs refs = parser .dereference ().getRefs ();
377429 Assert .assertTrue (refs .circular );
378- // System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(refs.schema()));
379- // assertNoRefs(refs.schema());
430+ // System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(refs.schema()));
431+ assertNoRefs (refs .schema ());
380432 }
381433
434+
435+ class CycleBreakingMapSerializer extends JsonSerializer <Map <?, ?>> {
436+ private final ThreadLocal <Set <Object >> SEEN =
437+ ThreadLocal .withInitial (() -> Collections .newSetFromMap (new IdentityHashMap <>()));
438+
439+ @ Override
440+ public void serialize (Map <?, ?> map , JsonGenerator gen , SerializerProvider provider )
441+ throws IOException {
442+ Set <Object > seen = SEEN .get ();
443+ if (seen .contains (map )) {
444+ gen .writeString ("CYCLE" ); // O gen.writeNull() para omitir
445+ return ;
446+ }
447+ seen .add (map );
448+ try {
449+ gen .writeStartObject ();
450+ for (Map .Entry <?, ?> entry : map .entrySet ()) {
451+ gen .writeFieldName (entry .getKey ().toString ());
452+ Object value = entry .getValue ();
453+ provider .defaultSerializeValue (value , gen ); // Usa serializador recursivo para valores Map
454+ }
455+ gen .writeEndObject ();
456+ } finally {
457+ seen .remove (map );
458+ }
459+ }
460+ }
382461}
0 commit comments