PageSourceSearch

https://lionweb.io/assets/js/40f724b7.5828c817.js

js lionweb.io collected 2026-10-03 23:15:55 UTC 14,081 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunklionweb_python_docs=self.webpackChunklionweb_python_docs||[]).push([[5433],{6893:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>a,toc:()=>d});const a=JSON.parse('{"id":"Guides-JVM/Guides-Java/serialization","title":"Serialization","description":"The LionWeb Java library provides robust support for serializing and deserializing models composed of nodes. These nodes can represent instances of a language as well as the language definitions themselves.","source":"@site/docs/Guides-JVM/Guides-Java/serialization.md","sourceDirName":"Guides-JVM/Guides-Java","slug":"/Guides-JVM/Guides-Java/serialization","permalink":"/Guides-JVM/Guides-Java/serialization","draft":false,"unlisted":false,"editUrl":"https://github.com/lionweb-io/LionWeb-io.github.io/tree/main/website/docs/Guides-JVM/Guides-Java/serialization.md","tags":[],"version":"current","sidebarPosition":43,"frontMatter":{"sidebar_position":43},"sidebar":"tutorialSidebar","previous":{"title":"Creating and Working with Nodes in LionWeb","permalink":"/Guides-JVM/Guides-Java/working-with-nodes"},"next":{"title":"Working with the LionWeb Server","permalink":"/Guides-JVM/Guides-Java/working-with-repository"}}');var s=i(4848),t=i(8453);const r={sidebar_position:43},o="Serialization",l={},d=[{value:"Homogeneous Serialization",id:"homogeneous-serialization",level:2},{value:"Custom Deserialization with Heterogeneous Nodes",id:"custom-deserialization-with-heterogeneous-nodes",level:2},{value:"Example",id:"example",level:3},{value:"Serializing Language Definitions",id:"serializing-language-definitions",level:2},{value:"A complete example",id:"a-complete-example",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"serialization",children:"Serialization"})}),"\n",(0,s.jsxs)(n.p,{children:["The LionWeb Java library provides robust support for ",(0,s.jsx)(n.strong,{children:"serializing"})," and ",(0,s.jsx)(n.strong,{children:"deserializing"})," models composed of nodes. These nodes can represent instances of a language as well as the language definitions themselves."]}),"\n",(0,s.jsx)(n.p,{children:"Serialization is essential to:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Communicate with a LionWeb-compliant repository."}),"\n",(0,s.jsx)(n.li,{children:"Store models on disk or transmit them over the network."}),"\n",(0,s.jsx)(n.li,{children:"Load them back into memory and process them."}),"\n",(0,s.jsx)(n.li,{children:"Maintain compatibility across clients and systems."}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"homogeneous-serialization",children:"Homogeneous Serialization"}),"\n",(0,s.jsxs)(n.p,{children:["When working with the ",(0,s.jsx)(n.strong,{children:"homogeneous API"}),", such as ",(0,s.jsx)(n.code,{children:"DynamicNode"}),", the LionWeb Java library provides default serialization mechanisms that can be used out of the box."]}),"\n",(0,s.jsx)(n.p,{children:"The following example demonstrates how to:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["Define a small language consisting of ",(0,s.jsx)(n.code,{children:"TaskList"})," and ",(0,s.jsx)(n.code,{children:"Task"})," concepts."]}),"\n",(0,s.jsxs)(n.li,{children:["Create model instances using ",(0,s.jsx)(n.code,{children:"DynamicNode"})," subclasses."]}),"\n",(0,s.jsx)(n.li,{children:"Serialize the model using the standard JSON serializer."}),"\n",(0,s.jsx)(n.li,{children:"Deserialize the JSON back into nodes."}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-java",children:"// After creating nodes (see below), serialize them:\nJsonSerialization serialization = SerializationProvider.getStandardJsonSerialization();\nString serialized = serialization.serializeTreesToJsonString(taskList);\n\n// Deserialize with DynamicNode support:\nserialization.enableDynamicNodes();\nNode deserialized = serialization.deserializeToNodes(serialized).get(0);\n"})}),"\n",(0,s.jsx)(n.p,{children:"If you do not enable dynamic nodes or register deserializers, the deserialization of unknown node types will throw an error."}),"\n",(0,s.jsx)(n.h2,{id:"custom-deserialization-with-heterogeneous-nodes",children:"Custom Deserialization with Heterogeneous Nodes"}),"\n",(0,s.jsxs)(n.p,{children:["When using custom node classes (i.e., heterogeneous nodes), you need to ",(0,s.jsx)(n.strong,{children:"register a custom deserializer"})," per concept to instantiate the correct subclass:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-java",children:"serialization.getInstantiator().registerCustomDeserializer(taskConcept.getID(),\n    (Instantiator.ClassifierSpecificInstantiator<Task>)\n      (classifier, serializedInstance, deserializedNodesByID, propertiesValues) -> \n        new Task(serializedInstance.getID(), (String) propertiesValues.get(nameProperty)));\n"})}),"\n",(0,s.jsx)(n.p,{children:"This allows you to benefit from type-safe APIs and static checking during development."}),"\n",(0,s.jsx)(n.h3,{id:"example",children:"Example"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-java",children:'// Create a task list and tasks\nTaskList errands = new TaskList();\nTask task1 = new Task("Buy milk");\nTask task2 = new Task("Write report");\nerrands.addTask(task1);\nerrands.addTask(task2);\n\n// Validate\nValidationResult res = new NodeTreeValidator().validate(errands);\nif (!res.isSuccessful()) {\n    throw new IllegalStateException("Invalid model");\n}
1\n\n// Serialize\nJsonSerialization serialization = SerializationProvider.getStandardJsonSerialization();\nString json = serialization.serializeTreesToJsonString(errands);\nSystem.out.println(json);\n\n// Deserialize\nserialization.enableDynamicNodes(); // or register deserializers\nNode restored = serialization.deserializeToNodes(json).get(0);\n'})}),"\n",(0,s.jsx)(n.h2,{id:"serializing-language-definitions",children:"Serializing Language Definitions"}),"\n",(0,s.jsx)(n.p,{children:"LionWeb Java treats languages as regular node trees:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Concepts, Properties, Containments, and the Language itself are just nodes."}),"\n",(0,s.jsx)(n.li,{children:"The default serializer knows how to instantiate these standard types."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"So, you can also do:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-java",children:"String languageJson = serialization.serializeTreesToJsonString(myLanguage);\nList<Node> deserializedLanguageElements = serialization.deserializeToNodes(languageJson);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["No special registration is required for built-in language elements like ",(0,s.jsx)(n.code,{children:"Language"}),", ",(0,s.jsx)(n.code,{children:"Concept"}),", etc.\u2014their deserializers are pre-registered in the standard serializer."]}),"\n",(0,s.jsx)(n.h2,{id:"a-complete-example",children:"A complete example"}),"\n",(0,s.jsx)(n.p,{children:"By combining dynamic and custom deserialization strategies, LionWeb Java offers both flexibility and strong typing for working with serialized models and metamodels."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-java",children:'package com.example;\n\nimport io.lionweb.lioncore.java.language.*;\nimport io.lionweb.lioncore.java.model.ClassifierInstance;\nimport io.lionweb.lioncore.java.model.Node;\nimport io.lionweb.lioncore.java.model.impl.DynamicNode;\nimport io.lionweb.lioncore.java.serialization.Instantiator;\nimport io.lionweb.lioncore.java.serialization.JsonSerialization;\nimport io.lionweb.lioncore.java.serialization.SerializationProvider;\nimport io.lionweb.lioncore.java.serialization.data.SerializedClassifierInstance;\nimport io.lionweb.lioncore.java.utils.NodeTreeValidator;\nimport io.lionweb.lioncore.java.utils.ValidationResult;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.stream.Collectors;\n\npublic class SerializationAPIExample {\n\n  private static Concept taskListConcept;\n  private static Concept taskConcept;\n  private static Property nameProperty;\n  private static Containment tasksContainment;\n  private static Language taskLanguage;\n\n  {\n    defineLanguage();\n  }\n\n  private static class TaskList extends DynamicNode {\n    TaskList(String id) {\n      super(id, taskListConcept);\n    }\n\n    TaskList() {\n      this(UUID.randomUUID().toString());\n    }\n\n    void addTask(Task task) {\n      addChild(tasksContainment, task);\n    }\n\n    List<Task> getTasks() {\n      return getChildren(tasksContainment).stream().map(n -> (Task) n).collect(Collectors.toList());\n    }\n  }\n\n  private static class Task extends DynamicNode {\n    Task(String name) {\n      this(UUID.randomUUID().toString(), name);\n    }\n\n    Task(String id, String name) {\n      super(id, taskConcept);\n      setName(name);\n    }\n\n    void setName(String name) {\n      setPropertyValue(nameProperty, name);\n    }\n\n    String getName() {\n      return (String) getPropertyValue(nameProperty);\n    }\n  }\n\n  public static void defineLanguage() {\n    // Define the \'TaskList\' concept\n    taskListConcept = new Concept("TaskList");\n    taskListConcept.setID("TaskList-id");\n    taskListConcept.setName("TaskList");\n    taskListConcept.setKey("TaskList");\n    taskListConcept.setAbstract(false);\n    taskListConcept.setPartition(true);\n\n    // Define the \'Task\' concept\n    taskConcept = new Concept("Task");\n    taskConcept.setID("Task-id");\n    taskConcept.setName("Task");\n    taskConcept.setKey("Task");\n    taskConcept.setAbstract(false);\n\n    // Add a \'tasks\' containment\n    tasksContainment =\n        new Containment()\n            .setID("TasksList-tasks-id")\n            .setName("tasks")\n            .setKey("TasksList-tasks")\n            .setMultiple(true)\n            .setOptional(false)\n            .setType(taskConcept);\n    taskListConcept.addFeature(tasksContainment);\n\n    // Add a \'name\' property\n    nameProperty = new Property();\n    nameProperty.setID("task-name-id");\n    nameProperty.setName("name");\n    nameProperty.setKey("task-name");\n    nameProperty.setType(LionCoreBuiltins.getString());\n    taskConcept.addFeature(nameProperty);\n\n    // Define the language container\n    taskLanguage = new Language();\n    taskLanguage.setID("task-id");\n    taskLanguage.setKey("task");\n    taskLanguage.setName("Task Language");\n    taskLanguage.setVersion("1.0");\n    taskLanguage.addElement(taskListConcept);\n    taskLanguage.addElement(taskConcept);\n  }\n\n  public TaskList createTaskList() {\n    // Create the model\n    TaskList errands = new TaskList();\n\n    Task task1 = new Task("My Task #1");\n    errands.addTask(task1);\n\n    Task task2 = new Task("My Task #2");\n    errands.addTask(task2);\n\n    ValidationResult res = new NodeTreeValidator().validate(errands);\n    if (!res.isSuccessful()) {\n      throw new IllegalStateException("The tree is invali
1d: " + res);\n    }\n\n    return errands;\n  }\n\n  public static void main(String[] args) {\n    SerializationAPIExample example = new SerializationAPIExample();\n    TaskList taskList = example.createTaskList();\n    JsonSerialization serialization = SerializationProvider.getStandardJsonSerialization();\n\n    String serialized = serialization.serializeTreesToJsonString(taskList);\n    System.out.println("== Tasks list ==");\n    System.out.println(serialized);\n    System.out.println();\n\n    try {\n      serialization.deserializeToNodes(serialized);\n      throw new RuntimeException("We expect an exception");\n    } catch (IllegalArgumentException e) {\n      // We expect this\n      System.out.println("Expected error: " + e.getMessage());\n    }\n\n    serialization.enableDynamicNodes();;\n    Node deserialized1 = serialization.deserializeToNodes(serialized).get(0);\n    System.out.println("First deserialization - Deserialized as " + deserialized1.getClass().getSimpleName());\n    if (!taskList.equals(deserialized1)) {\n      throw new IllegalStateException();\n    }\n\n    serialization.getInstantiator().registerCustomDeserializer(taskListConcept.getID(),\n            (Instantiator.ClassifierSpecificInstantiator<TaskList>)\n                    (classifier,\n                     serializedClassifierInstance,\n                     deserializedNodesByID,\n                     propertiesValues) -> {\n                      return new TaskList(serializedClassifierInstance.getID());\n                    });\n    serialization.getInstantiator().registerCustomDeserializer(taskConcept.getID(),\n            (Instantiator.ClassifierSpecificInstantiator<Task>)\n                    (classifier,\n                     serializedClassifierInstance,\n                     deserializedNodesByID,\n                     propertiesValues) -> {\n                      return new Task(serializedClassifierInstance.getID(), (String) propertiesValues.get(nameProperty));\n                    });\n    Node deserialized2 = serialization.deserializeToNodes(serialized).get(0);\n    System.out.println("Second deserialization - Deserialized as " + deserialized2.getClass().getSimpleName());\n    if (!taskList.equals(deserialized2)) {\n      throw new IllegalStateException();\n    }\n  }\n}\n'})})]})}function p(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>o});var a=i(6540);const s={},t=a.createContext(s);function r(e){const n=a.useContext(t);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),a.createElement(t.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.