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.