blob: 40192ab4d3c01ae026cb01d18dcd30c30c990555 [file]
"use strict";(self.webpackChunkfory_site=self.webpackChunkfory_site||[]).push([["2910"],{49308(e,i,r){r.r(i),r.d(i,{metadata:()=>n,default:()=>h,frontMatter:()=>t,contentTitle:()=>l,toc:()=>c,assets:()=>o});var n=JSON.parse('{"id":"guide/serialization","title":"GraalVM Guide","description":"GraalVM Native Image","source":"@site/versioned_docs/version-0.16/guide/graalvm_guide.md","sourceDirName":"guide","slug":"/guide/serialization","permalink":"/docs/0.16/guide/serialization","draft":false,"unlisted":false,"editUrl":"https://github.com/apache/fory-site/tree/main/docs/guide/graalvm_guide.md","tags":[],"version":"0.16","sidebarPosition":19,"frontMatter":{"title":"GraalVM Guide","sidebar_position":19,"id":"serialization","license":"Licensed to the Apache Software Foundation (ASF) under one or more\\ncontributor license agreements. See the NOTICE file distributed with\\nthis work for additional information regarding copyright ownership.\\nThe ASF licenses this file to You under the Apache License, Version 2.0\\n(the \\"License\\"); you may not use this file except in compliance with\\nthe License. You may obtain a copy of the License at\\n\\n http://www.apache.org/licenses/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\"AS IS\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n"},"sidebar":"docsSidebar","previous":{"title":"Troubleshooting","permalink":"/docs/0.16/guide/xlang/troubleshooting"},"next":{"title":"Development","permalink":"/docs/0.16/guide/development"}}'),s=r(74848),a=r(28453);let t={title:"GraalVM Guide",sidebar_position:19,id:"serialization",license:'Licensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements. See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the "License"); you may not use this file except in compliance with\nthe License. You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an "AS IS" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n'},l,o={},c=[{value:"GraalVM Native Image",id:"graalvm-native-image",level:2},{value:"How It Works",id:"how-it-works",level:2},{value:"Basic Usage",id:"basic-usage",level:2},{value:"Step 1: Create Fory and Register Classes",id:"step-1-create-fory-and-register-classes",level:3},{value:"Step 2: Configure Build-Time Initialization",id:"step-2-configure-build-time-initialization",level:3},{value:"ForyGraalVMFeature (Optional)",id:"forygraalvmfeature-optional",level:2},{value:"Adding the Dependency",id:"adding-the-dependency",level:3},{value:"Enabling the Feature",id:"enabling-the-feature",level:3},{value:"What ForyGraalVMFeature Handles",id:"what-forygraalvmfeature-handles",level:3},{value:"Example with Private Record",id:"example-with-private-record",level:3},{value:"Example with Dynamic Proxy",id:"example-with-dynamic-proxy",level:3},{value:"Thread-Safe Fory",id:"thread-safe-fory",level:2},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:"&quot;Type is instantiated reflectively but was never registered&quot;",id:"type-is-instantiated-reflectively-but-was-never-registered",level:3},{value:"Framework Integration",id:"framework-integration",level:2},{value:"Benchmark",id:"benchmark",level:2},{value:"Struct Benchmark",id:"struct-benchmark",level:3},{value:"Class Fields",id:"class-fields",level:4},{value:"Benchmark Results",id:"benchmark-results",level:4},{value:"Pojo Benchmark",id:"pojo-benchmark",level:3},{value:"Class Fields",id:"class-fields-1",level:4},{value:"Benchmark Results",id:"benchmark-results-1",level:4}];function d(e){let i={a:"a",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h2,{id:"graalvm-native-image",children:"GraalVM Native Image"}),"\n",(0,s.jsxs)(i.p,{children:["GraalVM ",(0,s.jsx)(i.code,{children:"native image"})," compiles Java code into native executables ahead-of-time, resulting in faster startup and lower memory usage. However, native images don't support runtime JIT compilation or reflection without explicit configuration."]}),"\n",(0,s.jsxs)(i.p,{children:["Apache Fory\u2122 works excellently with GraalVM native image by using ",(0,s.jsx)(i.strong,{children:"codegen instead of reflection"}),". All serializer code is generated at build time, eliminating the need for reflection configuration files in most cases."]}),"\n",(0,s.jsx)(i.h2,{id:"how-it-works",children:"How It Works"}),"\n",(0,s.jsx)(i.p,{children:"Fory generates serialization code at GraalVM build time when you:"}),"\n",(0,s.jsxs)(i.ol,{children:["\n",(0,s.jsxs)(i.li,{children:["Create Fory as a ",(0,s.jsx)(i.strong,{children:"static"})," field"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Register"})," all classes in a static initializer"]}),"\n",(0,s.jsxs)(i.li,{children:["Call ",(0,s.jsx)(i.code,{children:"fory.ensureSerializersCompiled()"})," to compile serializers"]}),"\n",(0,s.jsxs)(i.li,{children:["Configure the class to initialize at build time via ",(0,s.jsx)(i.code,{children:"native-image.properties"})]}),"\n"]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"The main benefit"}),": You don't need to configure ",(0,s.jsx)(i.a,{href:"https://www.graalvm.org/latest/reference-manual/native-image/metadata/#specifying-reflection-metadata-in-json",children:"reflection json"})," or ",(0,s.jsx)(i.a,{href:"https://www.graalvm.org/latest/reference-manual/native-image/metadata/#serialization",children:"serialization json"})," for most serializable classes."]}),"\n",(0,s.jsxs)(i.p,{children:["Note: Fory's ",(0,s.jsx)(i.code,{children:"asyncCompilationEnabled"})," option is automatically disabled for GraalVM native image since runtime JIT is not supported."]}),"\n",(0,s.jsx)(i.h2,{id:"basic-usage",children:"Basic Usage"}),"\n",(0,s.jsx)(i.h3,{id:"step-1-create-fory-and-register-classes",children:"Step 1: Create Fory and Register Classes"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-java",children:"import org.apache.fory.Fory;\n\npublic class Example {\n // Must be static field\n static Fory fory;\n\n static {\n fory = Fory.builder().build();\n fory.register(MyClass.class);\n fory.register(AnotherClass.class);\n // Compile all serializers at build time\n fory.ensureSerializersCompiled();\n }\n\n public static void main(String[] args) {\n byte[] bytes = fory.serialize(new MyClass());\n MyClass obj = (MyClass) fory.deserialize(bytes);\n }\n}\n"})}),"\n",(0,s.jsx)(i.h3,{id:"step-2-configure-build-time-initialization",children:"Step 2: Configure Build-Time Initialization"}),"\n",(0,s.jsxs)(i.p,{children:["Create ",(0,s.jsx)(i.code,{children:"resources/META-INF/native-image/your-group/your-artifact/native-image.properties"}),":"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-properties",children:"Args = --initialize-at-build-time=com.example.Example\n"})}),"\n",(0,s.jsx)(i.h2,{id:"forygraalvmfeature-optional",children:"ForyGraalVMFeature (Optional)"}),"\n",(0,s.jsx)(i.p,{children:"For most types with public constructors, the basic setup above is sufficient. However, some advanced cases require reflection registration:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Private constructors"})," (classes without accessible no-arg constructor)"]}),"\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.strong,{children:"Private inner classes/records"})}),"\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.strong,{children:"Dynamic proxy serialization"})}),"\n"]}),"\n",(0,s.jsxs)(i.p,{children:["The ",(0,s.jsx)(i.code,{children:"fory-graalvm-feature"})," module automatically handles these cases, eliminating the need for manual ",(0,s.jsx)(i.code,{children:"reflect-config.json"})," configuration."]}),"\n",(0,s.jsx)(i.h3,{id:"adding-the-dependency",children:"Adding the Dependency"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-xml",children:"<dependency>\n <groupId>org.apache.fory</groupId>\n <artifactId>fory-graalvm-feature</artifactId>\n <version>${fory.version}</version>\n</dependency>\n"})}),"\n",(0,s.jsx)(i.h3,{id:"enabling-the-feature",children:"Enabling the Feature"}),"\n",(0,s.jsxs)(i.p,{children:["Add to your ",(0,s.jsx)(i.code,{children:"native-image.properties"}),":"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-properties",children:"Args = --initialize-at-build-time=com.example.Example \\\n --features=org.apache.fory.graalvm.feature.ForyGraalVMFeature\n"})}),"\n",(0,s.jsx)(i.h3,{id:"what-forygraalvmfeature-handles",children:"What ForyGraalVMFeature Handles"}),"\n",(0,s.jsxs)(i.table,{children:[(0,s.jsx)(i.thead,{children:(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.th,{children:"Scenario"}),(0,s.jsx)(i.th,{children:"Without Feature"}),(0,s.jsx)(i.th,{children:"With Feature"})]})}),(0,s.jsxs)(i.tbody,{children:[(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.td,{children:"Public classes with no-arg ctor"}),(0,s.jsx)(i.td,{children:"\u2705 Works"}),(0,s.jsx)(i.td,{children:"\u2705 Works"})]}),(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.td,{children:"Private constructors"}),(0,s.jsx)(i.td,{children:"\u274C Needs reflect-config.json"}),(0,s.jsx)(i.td,{children:"\u2705 Auto-registered"})]}),(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.td,{children:"Private inner records"}),(0,s.jsx)(i.td,{children:"\u274C Needs reflect-config.json"}),(0,s.jsx)(i.td,{children:"\u2705 Auto-registered"})]}),(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.td,{children:"Dynamic proxies"}),(0,s.jsx)(i.td,{children:"\u274C Needs manual config"}),(0,s.jsx)(i.td,{children:"\u2705 Auto-registered"})]})]})]}),"\n",(0,s.jsx)(i.h3,{id:"example-with-private-record",children:"Example with Private Record"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-java",children:"public class Example {\n // Private inner record - requires ForyGraalVMFeature\n private record PrivateRecord(int id, String name) {}\n\n static Fory fory;\n\n static {\n fory = Fory.builder().build();\n fory.register(PrivateRecord.class);\n fory.ensureSerializersCompiled();\n }\n}\n"})}),"\n",(0,s.jsx)(i.h3,{id:"example-with-dynamic-proxy",children:"Example with Dynamic Proxy"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-java",children:"import org.apache.fory.util.GraalvmSupport;\n\npublic class ProxyExample {\n public interface MyService {\n String execute();\n }\n\n static Fory fory;\n\n static {\n fory = Fory.builder().build();\n // Register proxy interface for serialization\n GraalvmSupport.registerProxySupport(MyService.class);\n fory.ensureSerializersCompiled();\n }\n}\n"})}),"\n",(0,s.jsx)(i.h2,{id:"thread-safe-fory",children:"Thread-Safe Fory"}),"\n",(0,s.jsxs)(i.p,{children:["For multi-threaded applications, use ",(0,s.jsx)(i.code,{children:"ThreadLocalFory"}),":"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-java",children:'import org.apache.fory.Fory;\nimport org.apache.fory.ThreadLocalFory;\nimport org.apache.fory.ThreadSafeFory;\n\npublic class ThreadSafeExample {\n public record Foo(int f1, String f2, List<String> f3) {}\n\n static ThreadSafeFory fory;\n\n static {\n fory = new ThreadLocalFory(classLoader -> {\n Fory f = Fory.builder().build();\n f.register(Foo.class);\n f.ensureSerializersCompiled();\n return f;\n });\n }\n\n public static void main(String[] args) {\n Foo foo = new Foo(10, "abc", List.of("str1", "str2"));\n byte[] bytes = fory.serialize(foo);\n Foo result = (Foo) fory.deserialize(bytes);\n }\n}\n'})}),"\n",(0,s.jsx)(i.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,s.jsx)(i.h3,{id:"type-is-instantiated-reflectively-but-was-never-registered",children:'"Type is instantiated reflectively but was never registered"'}),"\n",(0,s.jsx)(i.p,{children:"If you see this error:"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{children:"Type com.example.MyClass is instantiated reflectively but was never registered\n"})}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Solution"}),": Register the class with Fory (don't add to reflect-config.json):"]}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-java",children:"fory.register(MyClass.class);\nfory.ensureSerializersCompiled();\n"})}),"\n",(0,s.jsx)(i.p,{children:"If the class has a private constructor, either:"}),"\n",(0,s.jsxs)(i.ol,{children:["\n",(0,s.jsxs)(i.li,{children:["Add ",(0,s.jsx)(i.code,{children:"fory-graalvm-feature"})," dependency, or"]}),"\n",(0,s.jsxs)(i.li,{children:["Create a ",(0,s.jsx)(i.code,{children:"reflect-config.json"})," for that specific class"]}),"\n"]}),"\n",(0,s.jsx)(i.h2,{id:"framework-integration",children:"Framework Integration"}),"\n",(0,s.jsx)(i.p,{children:"For framework developers integrating Fory:"}),"\n",(0,s.jsxs)(i.ol,{children:["\n",(0,s.jsx)(i.li,{children:"Provide a configuration file for users to list serializable classes"}),"\n",(0,s.jsxs)(i.li,{children:["Load those classes and call ",(0,s.jsx)(i.code,{children:"fory.register(Class<?>)"})," for each"]}),"\n",(0,s.jsxs)(i.li,{children:["Call ",(0,s.jsx)(i.code,{children:"fory.ensureSerializersCompiled()"})," after all registrations"]}),"\n",(0,s.jsx)(i.li,{children:"Configure your integration class for build-time initialization"}),"\n"]}),"\n",(0,s.jsx)(i.h2,{id:"benchmark",children:"Benchmark"}),"\n",(0,s.jsx)(i.p,{children:"Performance comparison between Fory and GraalVM JDK Serialization:"}),"\n",(0,s.jsxs)(i.table,{children:[(0,s.jsx)(i.thead,{children:(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.th,{children:"Type"}),(0,s.jsx)(i.th,{children:"Compression"}),(0,s.jsx)(i.th,{children:"Speed"}),(0,s.jsx)(i.th,{children:"Size"})]})}),(0,s.jsxs)(i.tbody,{children:[(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.td,{children:"Struct"}),(0,s.jsx)(i.td,{children:"Off"}),(0,s.jsx)(i.td,{children:"46x faster"}),(0,s.jsx)(i.td,{children:"43%"})]}),(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.td,{children:"Struct"}),(0,s.jsx)(i.td,{children:"On"}),(0,s.jsx)(i.td,{children:"24x faster"}),(0,s.jsx)(i.td,{children:"31%"})]}),(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.td,{children:"Pojo"}),(0,s.jsx)(i.td,{children:"Off"}),(0,s.jsx)(i.td,{children:"12x faster"}),(0,s.jsx)(i.td,{children:"56%"})]}),(0,s.jsxs)(i.tr,{children:[(0,s.jsx)(i.td,{children:"Pojo"}),(0,s.jsx)(i.td,{children:"On"}),(0,s.jsx)(i.td,{children:"12x faster"}),(0,s.jsx)(i.td,{children:"48%"})]})]})]}),"\n",(0,s.jsxs)(i.p,{children:["See ",(0,s.jsx)(i.a,{href:"https://github.com/apache/fory/blob/main/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java",children:"Benchmark.java"})," for benchmark code."]}),"\n",(0,s.jsx)(i.h3,{id:"struct-benchmark",children:"Struct Benchmark"}),"\n",(0,s.jsx)(i.h4,{id:"class-fields",children:"Class Fields"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-java",children:"public class Struct implements Serializable {\n public int f1;\n public long f2;\n public float f3;\n public double f4;\n public int f5;\n public long f6;\n public float f7;\n public double f8;\n public int f9;\n public long f10;\n public float f11;\n public double f12;\n}\n"})}),"\n",(0,s.jsx)(i.h4,{id:"benchmark-results",children:"Benchmark Results"}),"\n",(0,s.jsx)(i.p,{children:"No compression:"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{children:"Benchmark repeat number: 400000\nObject type: class org.apache.fory.graalvm.Struct\nCompress number: false\nFory size: 76.0\nJDK size: 178.0\nFory serialization took mills: 49\nJDK serialization took mills: 2254\nCompare speed: Fory is 45.70x speed of JDK\nCompare size: Fory is 0.43x size of JDK\n"})}),"\n",(0,s.jsx)(i.p,{children:"Compress number:"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{children:"Benchmark repeat number: 400000\nObject type: class org.apache.fory.graalvm.Struct\nCompress number: true\nFory size: 55.0\nJDK size: 178.0\nFory serialization took mills: 130\nJDK serialization took mills: 3161\nCompare speed: Fory is 24.16x speed of JDK\nCompare size: Fory is 0.31x size of JDK\n"})}),"\n",(0,s.jsx)(i.h3,{id:"pojo-benchmark",children:"Pojo Benchmark"}),"\n",(0,s.jsx)(i.h4,{id:"class-fields-1",children:"Class Fields"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{className:"language-java",children:"public class Foo implements Serializable {\n int f1;\n String f2;\n List<String> f3;\n Map<String, Long> f4;\n}\n"})}),"\n",(0,s.jsx)(i.h4,{id:"benchmark-results-1",children:"Benchmark Results"}),"\n",(0,s.jsx)(i.p,{children:"No compression:"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{children:"Benchmark repeat number: 400000\nObject type: class org.apache.fory.graalvm.Foo\nCompress number: false\nFory size: 541.0\nJDK size: 964.0\nFory serialization took mills: 1663\nJDK serialization took mills: 16266\nCompare speed: Fory is 12.19x speed of JDK\nCompare size: Fory is 0.56x size of JDK\n"})}),"\n",(0,s.jsx)(i.p,{children:"Compress number:"}),"\n",(0,s.jsx)(i.pre,{children:(0,s.jsx)(i.code,{children:"Benchmark repeat number: 400000\nObject type: class org.apache.fory.graalvm.Foo\nCompress number: true\nFory size: 459.0\nJDK size: 964.0\nFory serialization took mills: 1289\nJDK serialization took mills: 15069\nCompare speed: Fory is 12.11x speed of JDK\nCompare size: Fory is 0.48x size of JDK\n"})})]})}function h(e={}){let{wrapper:i}={...(0,a.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},28453(e,i,r){r.d(i,{R:()=>t,x:()=>l});var n=r(96540);let s={},a=n.createContext(s);function t(e){let i=n.useContext(a);return n.useMemo(function(){return"function"==typeof e?e(i):{...i,...e}},[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:t(e.components),n.createElement(a.Provider,{value:i},e.children)}}}]);