3333import java .util .stream .Stream ;
3434
3535import tools .jackson .core .JacksonException ;
36+ import tools .jackson .core .JsonGenerator ;
3637import tools .jackson .core .json .JsonReadFeature ;
3738import tools .jackson .core .type .TypeReference ;
3839import tools .jackson .core .util .DefaultPrettyPrinter ;
4142import tools .jackson .databind .DeserializationFeature ;
4243import tools .jackson .databind .JsonNode ;
4344import tools .jackson .databind .ObjectMapper ;
45+ import tools .jackson .databind .SerializationContext ;
46+ import tools .jackson .databind .ValueSerializer ;
4447import tools .jackson .databind .json .JsonMapper ;
48+ import tools .jackson .databind .module .SimpleModule ;
4549import tools .jackson .databind .node .ArrayNode ;
4650import tools .jackson .databind .node .BaseJsonNode ;
4751import tools .jackson .databind .node .DoubleNode ;
4852import tools .jackson .databind .node .JsonNodeType ;
4953import tools .jackson .databind .node .ObjectNode ;
5054import tools .jackson .databind .node .ValueNode ;
5155
56+ import com .vaadin .flow .component .Component ;
57+ import com .vaadin .flow .dom .Element ;
58+ import com .vaadin .flow .dom .Node ;
59+
5260import elemental .json .Json ;
5361import elemental .json .JsonArray ;
5462import elemental .json .JsonBoolean ;
@@ -71,10 +79,17 @@ public final class JacksonUtils {
7179
7280 private static final String CANNOT_CONVERT_NULL_TO_OBJECT = "Cannot convert null to Java object" ;
7381
74- private static final ObjectMapper objectMapper = JsonMapper .builder ()
75- .enable (JsonReadFeature .ALLOW_SINGLE_QUOTES )
76- .disable (DeserializationFeature .FAIL_ON_NULL_FOR_PRIMITIVES )
77- .build ();
82+ private static final ObjectMapper objectMapper = createConfiguredMapper ();
83+
84+ private static ObjectMapper createConfiguredMapper () {
85+ SimpleModule module = new SimpleModule ();
86+ module .addSerializer (Component .class , new ComponentSerializer ());
87+ module .addSerializer (Node .class , new NodeSerializer ());
88+
89+ return JsonMapper .builder ().enable (JsonReadFeature .ALLOW_SINGLE_QUOTES )
90+ .disable (DeserializationFeature .FAIL_ON_NULL_FOR_PRIMITIVES )
91+ .addModule (module ).build ();
92+ }
7893
7994 public static ObjectMapper getMapper () {
8095 return objectMapper ;
@@ -632,4 +647,63 @@ public static String toFileJson(JsonNode node) throws JacksonException {
632647 .withObjectNameValueSpacing (Spacing .AFTER ));
633648 return objectMapper .writer ().with (filePrinter ).writeValueAsString (node );
634649 }
650+
651+ /**
652+ * Custom Jackson serializer for Component that delegates to NodeSerializer.
653+ */
654+ public static class ComponentSerializer extends ValueSerializer <Component > {
655+ private final NodeSerializer nodeSerializer = new NodeSerializer ();
656+
657+ @ Override
658+ public void serialize (Component component , JsonGenerator gen ,
659+ SerializationContext serializers ) {
660+ try {
661+ if (component != null ) {
662+ // Delegate to NodeSerializer using the component's element
663+ nodeSerializer .serialize (component .getElement (), gen ,
664+ serializers );
665+ } else {
666+ gen .writeNull ();
667+ }
668+ } catch (Exception e ) {
669+ throw new RuntimeException ("Failed to serialize Component" , e );
670+ }
671+ }
672+ }
673+
674+ /**
675+ * Custom Jackson serializer for Node types (Element, ShadowRoot) that
676+ * serializes attached nodes as @v-node references for client-side DOM
677+ * manipulation.
678+ */
679+ @ SuppressWarnings ("rawtypes" )
680+ public static class NodeSerializer extends ValueSerializer <Node > {
681+ @ Override
682+ @ SuppressWarnings ("unchecked" )
683+ public void serialize (Node node , JsonGenerator gen ,
684+ SerializationContext serializers ) {
685+ try {
686+ if (node != null ) {
687+ // Serialize attached nodes as @v-node references containing
688+ // the StateNode ID
689+ // This allows the client to identify and manipulate the
690+ // corresponding DOM element
691+ if (node .getNode ().isAttached ()) {
692+ gen .writeStartObject ();
693+ gen .writeNumberProperty ("@v-node" ,
694+ node .getNode ().getId ());
695+ gen .writeEndObject ();
696+ } else {
697+ // Detached nodes cannot be referenced on the client, so
698+ // serialize as null
699+ gen .writeNull ();
700+ }
701+ } else {
702+ gen .writeNull ();
703+ }
704+ } catch (Exception e ) {
705+ throw new RuntimeException ("Failed to serialize Node" , e );
706+ }
707+ }
708+ }
635709}
0 commit comments