| <!doctype html><html lang=en-US dir=ltr class="docs-wrapper plugin-docs plugin-id-default docs-version-0.13 docs-doc-page docs-doc-id-specification/java_serialization_spec" data-has-hydrated=false><head><meta charset=UTF-8><meta name=generator content="Docusaurus v3.10.1"><title data-rh=true>Java Serialization Format | Apache Fory™</title><meta data-rh=true name=viewport content="width=device-width, initial-scale=1.0"/><meta data-rh=true property=og:url content=https://fory.apache.org/docs/0.13/specification/java_serialization_spec /><meta data-rh=true property=og:locale content=en_US /><meta data-rh=true property=og:locale:alternate content=zh_CN /><meta data-rh=true name=docusaurus_locale content=en-US /><meta data-rh=true name=docsearch:language content=en-US /><meta data-rh=true http-equiv=Content-Security-Policy content="frame-src 'self' https://ghbtns.com/;"/><meta data-rh=true property=og:image content=https://fory.apache.org/img/logo.png /><meta data-rh=true property=og:image:width content=1500 /><meta data-rh=true property=og:image:height content=1500 /><meta data-rh=true name=twitter:card content=summary_large_image /><meta data-rh=true name=twitter:image content=https://fory.apache.org/img/logo.png /><meta data-rh=true name=docusaurus_version content=0.13 /><meta data-rh=true name=docusaurus_tag content=docs-default-0.13 /><meta data-rh=true name=docsearch:version content=0.13 /><meta data-rh=true name=docsearch:docusaurus_tag content=docs-default-0.13 /><meta data-rh=true property=og:title content="Java Serialization Format | Apache Fory™"/><meta data-rh=true name=description content="Spec overview"/><meta data-rh=true property=og:description content="Spec overview"/><link data-rh=true rel=icon href=/img/favicon.ico /><link data-rh=true rel=canonical href=https://fory.apache.org/docs/0.13/specification/java_serialization_spec /><link data-rh=true rel=alternate href=https://fory.apache.org/docs/0.13/specification/java_serialization_spec hreflang=en-US /><link data-rh=true rel=alternate href=https://fory.apache.org/zh-CN/docs/0.13/specification/java_serialization_spec hreflang=zh-CN /><link data-rh=true rel=alternate href=https://fory.apache.org/docs/0.13/specification/java_serialization_spec hreflang=x-default /><script data-rh=true type=application/ld+json>{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","item":"https://fory.apache.org/docs/0.13/specification/java_serialization_spec","name":"Java Serialization Format","position":1}]}</script><link rel=alternate type=application/rss+xml href=/blog/rss.xml title="Apache Fory™ RSS Feed"><link rel=alternate type=application/atom+xml href=/blog/atom.xml title="Apache Fory™ Atom Feed"><script type=text/javascript>"fury.apache.org"===window.location.host&&(window.location.href="https://fory.apache.org"),function(){for(var o=window.location.pathname,a=["guide","introduction","start"],n=0;n<a.length;n++){var t=a[n],i=RegExp("^((?:/[a-z]{2}-[A-Z]{2})?/docs(?:/(?:next|[0-9]+.[0-9]+))?)/docs/"+t+"(/.*)?$"),c=o.match(i);if(c){var r=c[1]+"/"+t+(c[2]||"");window.location.replace(r+window.location.search+window.location.hash);return}}}()</script><link rel=stylesheet href=/assets/css/styles.3a1edaa1.css /><script src=/assets/js/runtime~main.605b11b1.js defer></script><script src=/assets/js/main.283fea4b.js defer></script></head><body><svg style="display: none;"><defs> |
| <symbol id=theme-svg-external-link viewBox="0 0 24 24"><path fill=currentColor d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"/></symbol> |
| </defs></svg> |
| <script>!function(){var t=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.localStorage.getItem("theme")}catch(t){}}();document.documentElement.setAttribute("data-theme",t||"light"),document.documentElement.setAttribute("data-theme-choice",t||"light")}(),function(){try{for(var[t,e]of new URLSearchParams(window.location.search).entries())if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id=__docusaurus><div role=region aria-label="Skip to main content"><a class=skipToContent_fXgn href=#__docusaurus_skipToContent_fallback>Skip to main content</a></div><nav aria-label=Main class="theme-layout-navbar navbar navbar--fixed-top"><div class=navbar__inner><div class="theme-layout-navbar-left navbar__items"><button aria-label="Toggle navigation bar" aria-expanded=false class="navbar__toggle clean-btn" type=button><svg width=30 height=30 viewBox="0 0 30 30" aria-hidden=true><path stroke=currentColor stroke-linecap=round stroke-miterlimit=10 stroke-width=2 d="M4 7h22M4 15h22M4 23h22"/></svg></button><a class=navbar__brand href=/><div class=navbar__logo><img src=/img/fory-logo-light.png alt="Apache Fory™ Logo" class="themedComponent_mlkZ themedComponent--light_NVdE"/><img src=/img/fory-logo-dark.png alt="Apache Fory™ Logo" class="themedComponent_mlkZ themedComponent--dark_xIcU"/></div><b class="navbar__title text--truncate"></b></a><a class="navbar__item navbar__link" href=/docs/0.13/introduction/overview>Docs</a><a aria-current=page class="navbar__item navbar__link navbar__link--active" href=/docs/0.13/specification/xlang_serialization_spec>Specification</a><a class="navbar__item navbar__link" href=/docs/0.13/community/>Community</a><a class="navbar__item navbar__link" href=/user>Users</a><a class="navbar__item navbar__link" href=/download>Download</a><a class="navbar__item navbar__link" href=/blog>Blog</a></div><div class="theme-layout-navbar-right navbar__items navbar__items--right"><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a href=# aria-haspopup=true aria-expanded=false role=button class=navbar__link>ASF</a><ul class=dropdown__menu><li><a href=https://www.apache.org/ target=_blank rel="noopener noreferrer" class=dropdown__link>Foundation</a><li><a href=https://www.apache.org/licenses/ target=_blank rel="noopener noreferrer" class=dropdown__link>License</a><li><a href=https://www.apache.org/events/current-event.html target=_blank rel="noopener noreferrer" class=dropdown__link>Events</a><li><a href=https://privacy.apache.org/policies/privacy-policy-public.html target=_blank rel="noopener noreferrer" class=dropdown__link>Privacy</a><li><a href=https://www.apache.org/security/ target=_blank rel="noopener noreferrer" class=dropdown__link>Security</a><li><a href=https://www.apache.org/foundation/sponsorship.html target=_blank rel="noopener noreferrer" class=dropdown__link>Sponsorship</a><li><a href=https://www.apache.org/foundation/thanks.html target=_blank rel="noopener noreferrer" class=dropdown__link>Thanks</a><li><a href=https://www.apache.org/foundation/policies/conduct.html target=_blank rel="noopener noreferrer" class=dropdown__link>Code of Conduct</a></ul></div><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a class=navbar__link aria-haspopup=true aria-expanded=false role=button href=/docs/0.13/specification/java_serialization_spec>0.13</a><ul class=dropdown__menu><li><a class=dropdown__link href=/docs/next/specification/java_serialization_spec>dev</a><li><a class=dropdown__link href=/docs/specification/java_serialization_spec>1.3.0</a><li><a class=dropdown__link href=/docs/1.2.0/specification/java_serialization_spec>1.2.0</a><li><a class=dropdown__link href=/docs/1.1.0/specification/java_serialization_spec>1.1.0</a><li><a class=dropdown__link href=/docs/1.0.0/specification/java_serialization_spec>1.0.0</a><li><a class=dropdown__link href=/docs/0.17/specification/java_serialization_spec>0.17</a><li><a class=dropdown__link href=/docs/0.16/specification/java_serialization_spec>0.16</a><li><a class=dropdown__link href=/docs/0.15/specification/java_serialization_spec>0.15</a><li><a class=dropdown__link href=/docs/0.14/specification/java_serialization_spec>0.14</a><li><a aria-current=page class="dropdown__link dropdown__link--active" href=/docs/0.13/specification/java_serialization_spec>0.13</a><li><a class=dropdown__link href=/docs/0.12/specification/java_serialization_spec>0.12</a><li><a class=dropdown__link href=/docs/0.11/specification/java_serialization_spec>0.11</a><li><a class=dropdown__link href=/docs/0.10/specification/java_serialization_spec>0.10</a></ul></div><a href=https://github.com/apache/fory target=_blank rel="noopener noreferrer" class="navbar__item navbar__link header-github-link" aria-label="GitHub repository"></a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a href=# aria-haspopup=true aria-expanded=false role=button class=navbar__link><svg viewBox="0 0 24 24" width=20 height=20 aria-hidden=true class=iconLanguage_nlXk><path fill=currentColor d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"/></svg>English</a><ul class=dropdown__menu><li><a href=/docs/0.13/specification/java_serialization_spec target=_self rel="noopener noreferrer" class="dropdown__link dropdown__link--active" lang=en-US>English</a><li><a href=/zh-CN/docs/0.13/specification/java_serialization_spec target=_self rel="noopener noreferrer" class=dropdown__link lang=zh-CN>简体中文</a></ul></div><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type=button disabled title="system mode" aria-label="Switch between dark and light mode (currently system mode)"><svg viewBox="0 0 24 24" width=24 height=24 aria-hidden=true class="toggleIcon_g3eP lightToggleIcon_pyhR"><path fill=currentColor d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"/></svg><svg viewBox="0 0 24 24" width=24 height=24 aria-hidden=true class="toggleIcon_g3eP darkToggleIcon_wfgR"><path fill=currentColor d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"/></svg><svg viewBox="0 0 24 24" width=24 height=24 aria-hidden=true class="toggleIcon_g3eP systemToggleIcon_QzmC"><path fill=currentColor d="m12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9zm4.95-13.95c1.313 1.313 2.05 3.093 2.05 4.95s-0.738 3.637-2.05 4.95c-1.313 1.313-3.093 2.05-4.95 2.05v-14c1.857 0 3.637 0.737 4.95 2.05z"/></svg></button></div><div class=navbarSearchContainer_Bca1><div class=navbar__search><span aria-label="expand searchbar" role=button class=search-icon tabindex=0></span><input id=search_input_react type=search placeholder=Loading... aria-label=Search class="navbar__search-input search-bar" disabled/></div></div></div></div><div role=presentation class=navbar-sidebar__backdrop></div></nav><div id=__docusaurus_skipToContent_fallback class="theme-layout-main main-wrapper mainWrapper_z2l0"><div class=docsWrapper_hBAB><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type=button></button><div class=docRoot_UBD9><aside class="theme-doc-sidebar-container docSidebarContainer_YfHR"><div class=sidebarViewport_aRkj><div class=sidebar_njMd><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class=menu__link href=/docs/0.13/specification/xlang_serialization_spec><span title="Xlang Serialization Format" class=linkLabel_WmDU>Xlang Serialization Format</span></a><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link menu__link--active" aria-current=page href=/docs/0.13/specification/java_serialization_spec><span title="Java Serialization Format" class=linkLabel_WmDU>Java Serialization Format</span></a><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class=menu__link href=/docs/0.13/specification/row_format_spec><span title="Row Format" class=linkLabel_WmDU>Row Format</span></a><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class=menu__link href=/docs/0.13/specification/xlang_type_mapping><span title="Xlang Type Mapping" class=linkLabel_WmDU>Xlang Type Mapping</span></a></ul></nav></div></div></aside><main class=docMainContainer_TBSr><div class="container padding-top--md padding-bottom--lg"><div class=row><div class="col docItemCol_VOVn"><div class="theme-doc-version-banner alert alert--warning margin-bottom--md" role=alert><div>This is documentation for <!-- -->Apache Fory™<!-- --> <b>0.13</b>, which is no longer actively maintained.</div><div class=margin-top--md>For up-to-date documentation, see the <b><a href=/docs/specification/java_serialization_spec>latest version</a></b> (<!-- -->1.3.0<!-- -->).</div></div><div class=docItemContainer_Djhp><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_Z_bl" aria-label=Breadcrumbs><ul class=breadcrumbs><li class=breadcrumbs__item><a aria-label="Home page" class=breadcrumbs__link href=/><svg viewBox="0 0 24 24" class=breadcrumbHomeIcon_YNFT><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill=currentColor /></svg></a><li class="breadcrumbs__item breadcrumbs__item--active"><span class=breadcrumbs__link>Java Serialization Format</span></ul></nav><span class="theme-doc-version-badge badge badge--secondary">Version: 0.13</span><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type=button class="clean-btn tocCollapsibleButton_TO0P">On this page</button></div><div class="theme-doc-markdown markdown"><header><h1>Java Serialization Format</h1></header><h2 class="anchor anchorTargetStickyNavbar_Vzrq" id=spec-overview>Spec overview<a href=#spec-overview class=hash-link aria-label="Direct link to Spec overview" title="Direct link to Spec overview" translate=no></a></h2> |
| <p>Apache Fory™ Java Serialization is an automatic object serialization framework that supports reference and polymorphism. Apache Fory™ |
| will |
| convert an object from/to fory java serialization binary format. Apache Fory™ has two core concepts for java serialization:</p> |
| <ul> |
| <li class=""><strong>Apache Fory™ Java Binary format</strong></li> |
| <li class=""><strong>Framework to convert object to/from Apache Fory™ Java Binary format</strong></li> |
| </ul> |
| <p>The serialization format is a dynamic binary format. The dynamics and reference/polymorphism support make Apache Fory™ flexible, |
| much more easy to use, but |
| also introduce more complexities compared to static serialization frameworks. So the format will be more complex.</p> |
| <p>Here is the overall format:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| fory header | object ref meta | object class meta | object value data |</span><br/></div></code></pre></div></div> |
| <p>The data are serialized using little endian byte order overall. If bytes swap is costly for some object, |
| Fory will write the byte order for that object into the data instead of converting it to little endian.</p> |
| <h2 class="anchor anchorTargetStickyNavbar_Vzrq" id=fory-header>Fory header<a href=#fory-header class=hash-link aria-label="Direct link to Fory header" title="Direct link to Fory header" translate=no></a></h2> |
| <p>Fory header consists starts one byte:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| 4 bits | 1 bit | 1 bit | 1 bit | 1 bit | optional 4 bytes |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+---------------+-------+-------+--------+-------+------------------------------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| reserved bits | oob | xlang | endian | null | unsigned int for meta start offset |</span><br/></div></code></pre></div></div> |
| <ul> |
| <li class="">null flag: 1 when object is null, 0 otherwise. If an object is null, other bits won't be set.</li> |
| <li class="">endian flag: 1 when data is encoded by little endian, 0 for big endian.</li> |
| <li class="">xlang flag: 1 when serialization uses xlang format, 0 when serialization uses Fory java format.</li> |
| <li class="">oob flag: 1 when passed <code>BufferCallback</code> is not null, 0 otherwise.</li> |
| </ul> |
| <p>If meta share mode is enabled, an uncompressed unsigned int is appended to indicate the start offset of metadata.</p> |
| <h2 class="anchor anchorTargetStickyNavbar_Vzrq" id=reference-meta>Reference Meta<a href=#reference-meta class=hash-link aria-label="Direct link to Reference Meta" title="Direct link to Reference Meta" translate=no></a></h2> |
| <p>Reference tracking handles whether the object is null, and whether to track reference for the object by writing |
| corresponding flags and maintaining internal state.</p> |
| <p>Reference flags:</p> |
| <table><thead><tr><th>Flag<th>Byte Value<th>Description<tbody><tr><td>NULL FLAG<td><code>-3</code><td>This flag indicates the object is a null value. We don't use another byte to indicate REF, so that we can save one byte.<tr><td>REF FLAG<td><code>-2</code><td>This flag indicates the object is already serialized previously, and fory will write a ref id with unsigned varint format instead of serialize it again<tr><td>NOT_NULL VALUE FLAG<td><code>-1</code><td>This flag indicates the object is a non-null value and fory doesn't track ref for this type of object.<tr><td>REF VALUE FLAG<td><code>0</code><td>This flag indicates the object is referencable and the first time to serialize.</table> |
| <p>When reference tracking is disabled globally or for specific types, or for certain types within a particular |
| context(e.g., a field of a class), only the <code>NULL</code> and <code>NOT_NULL VALUE</code> flags will be used for reference meta.</p> |
| <h2 class="anchor anchorTargetStickyNavbar_Vzrq" id=class-meta>Class Meta<a href=#class-meta class=hash-link aria-label="Direct link to Class Meta" title="Direct link to Class Meta" translate=no></a></h2> |
| <p>Fory supports to register class by an optional id, the registration can be used for security check and class |
| identification. |
| If a class is registered, it will have a user-provided or an auto-growing unsigned int i.e. <code>class_id</code>.</p> |
| <p>Depending on whether meta share mode and registration is enabled for current class, Fory will write class meta |
| differently.</p> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=schema-consistent>Schema consistent<a href=#schema-consistent class=hash-link aria-label="Direct link to Schema consistent" title="Direct link to Schema consistent" translate=no></a></h3> |
| <p>If schema consistent mode is enabled globally or enabled for current class, class meta will be written as follows:</p> |
| <ul> |
| <li class="">If class is registered, it will be written as a fory unsigned varint: <code>class_id << 1</code>.</li> |
| <li class="">If class is not registered:<!-- --> |
| <ul> |
| <li class="">If class is not an array, fory will write one byte <code>0bxxxxxxx1</code> first, then write class name.<!-- --> |
| <ul> |
| <li class="">The first little bit is <code>1</code>, which is different from first bit <code>0</code> of |
| encoded class id. Fory can use this information to determine whether to read class by class id for |
| deserialization.</li> |
| </ul> |
| </li> |
| <li class="">If class is not registered and class is an array, fory will write one byte <code>dimensions << 1 | 1</code> first, then write |
| component |
| class subsequently. This can reduce array class name cost if component class is or will be serialized.</li> |
| <li class="">Class will be written as two enumerated fory unsigned by default: <code>package name</code> and <code>class name</code>. If meta share |
| mode is |
| enabled, |
| class will be written as an unsigned varint which points to index in <code>MetaContext</code>.</li> |
| </ul> |
| </li> |
| </ul> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=schema-evolution>Schema evolution<a href=#schema-evolution class=hash-link aria-label="Direct link to Schema evolution" title="Direct link to Schema evolution" translate=no></a></h3> |
| <p>If schema evolution mode is enabled globally or enabled for current class, class meta will be written as follows:</p> |
| <ul> |
| <li class="">If meta share mode is not enabled, class meta will be written as schema consistent mode. Additionally, field meta such |
| as field type |
| and name will be written with the field value using a key-value like layout.</li> |
| <li class="">If meta share mode is enabled, class meta will be written as a meta-share encoded binary if class hasn't been written |
| before, otherwise an unsigned varint id which references to previous written class meta will be written.</li> |
| </ul> |
| <h2 class="anchor anchorTargetStickyNavbar_Vzrq" id=meta-share>Meta share<a href=#meta-share class=hash-link aria-label="Direct link to Meta share" title="Direct link to Meta share" translate=no></a></h2> |
| <blockquote> |
| <p>This mode will forbid streaming writing since it needs to look back for update the start offset after the whole object |
| graph |
| writing and meta collecting is finished. Only in this way we can ensure deserialization failure doesn't lost shared |
| meta. |
| Meta streamline will be supported in the future for enclosed meta sharing which doesn't cross multiple serializations |
| of different objects.</p> |
| </blockquote> |
| <p>For Schema consistent mode, class will be encoded as an enumerated string by full class name. Here we mainly describe |
| the meta layout for schema evolution mode:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| 8 bytes global meta header | 1~2 bytes | variable bytes | variable bytes | variable bytes |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-------------------------------+-------------|--------------------+-------------------+----------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| 50 bits hash + 14 bits header | type header | current class meta | parent class meta | ... |</span><br/></div></code></pre></div></div> |
| <p>Class meta are encoded from parent class to leaf class, only class with serializable fields will be encoded.</p> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=global-meta-header>Global meta header<a href=#global-meta-header class=hash-link aria-label="Direct link to Global meta header" title="Direct link to Global meta header" translate=no></a></h3> |
| <p>Meta header is a 64 bits number value encoded in little endian order.</p> |
| <ul> |
| <li class="">lower 12 bits are used to encode meta size. If meta size <code>>= 0b1111_1111_1111</code>, then write |
| <code>meta_ size - 0b1111_1111_1111</code> next.</li> |
| <li class="">13rd bit is used to indicate whether to write fields meta. When this class is schema-consistent or use registered |
| serializer, fields meta will be skipped. Class Meta will be used for share namespace + type name only.</li> |
| <li class="">14rd bit is used to indicate whether meta is compressed.</li> |
| <li class="">Other 50 bits is used to store the unique hash of <code>flags + all layers class meta</code>.</li> |
| </ul> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=type-header>Type header<a href=#type-header class=hash-link aria-label="Direct link to Type header" title="Direct link to Type header" translate=no></a></h3> |
| <ul> |
| <li class="">Lowest 4 digits <code>0b0000~0b1110</code> are used to record num classes. <code>0b1111</code> is preserved to indicate that Fory need to |
| read more bytes for length using Fory unsigned int encoding. If current class doesn't has parent class, or parent |
| class doesn't have fields to serialize, or we're in a context which serialize fields of current class |
| only(<code>ObjectStreamSerializer#SlotInfo</code> is an example), num classes will be 1.</li> |
| <li class="">Other 4 bits are preserved to future extensions.</li> |
| <li class="">If num classes are greater than or equal to <code>0b1111</code>, write <code>num_classes - 0b1111</code> as varuint next.</li> |
| </ul> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=single-layer-class-meta>Single layer class meta<a href=#single-layer-class-meta class=hash-link aria-label="Direct link to Single layer class meta" title="Direct link to Single layer class meta" translate=no></a></h3> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| unsigned varint | meta string | meta string | field info: variable bytes | variable bytes | ... |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+----------------------------+-----------------------+---------------------+-------------------------------+-----------------+-----+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| num fields + register flag | header + package name | header + class name | header + type id + field name | next field info | ... |</span><br/></div></code></pre></div></div> |
| <ul> |
| <li class="">num fields: encode <code>num fields << 1 | register flag(1 when class registered)</code> as unsigned varint.<!-- --> |
| <ul> |
| <li class="">If class is registered, then an unsigned varint class id will be written next, package and class name will be |
| omitted.</li> |
| <li class="">If current class is schema consistent, then num field will be <code>0</code> to flag it.</li> |
| <li class="">If current class isn't schema consistent, then num field will be the number of compatible fields. For example, |
| users |
| can use tag id to mark some field as compatible field in schema consistent context. In such cases, schema |
| consistent |
| fields will be serialized first, then compatible fields will be serialized next. At deserialization, Fory will use |
| fields info of those fields which aren't annotated by tag id for deserializing schema consistent fields, then use |
| fields info in meta for deserializing compatible fields.</li> |
| </ul> |
| </li> |
| <li class="">Package name encoding(omitted when class is registered):<!-- --> |
| <ul> |
| <li class="">encoding algorithm: <code>UTF8/ALL_TO_LOWER_SPECIAL/LOWER_UPPER_DIGIT_SPECIAL</code></li> |
| <li class="">Header: <code>6 bits size | 2 bits encoding flags</code>. The <code>6 bits size: 0~63</code> will be used to indicate size <code>0~63</code>, |
| the value <code>63</code> the size need more byte to read, the encoding will encode <code>size - 63</code> as a varint next.</li> |
| </ul> |
| </li> |
| <li class="">Class name encoding(omitted when class is registered):<!-- --> |
| <ul> |
| <li class="">encoding algorithm: <code>UTF8/LOWER_UPPER_DIGIT_SPECIAL/FIRST_TO_LOWER_SPECIAL/ALL_TO_LOWER_SPECIAL</code></li> |
| <li class="">header: <code>6 bits size | 2 bits encoding flags</code>. The <code>6 bits size: 0~63</code> will be used to indicate size <code>0~63</code>, |
| the value <code>63</code> the size need more byte to read, the encoding will encode <code>size - 63</code> as a varint next.</li> |
| </ul> |
| </li> |
| <li class="">Field info:<!-- --> |
| <ul> |
| <li class="">header(8 |
| bits): <code>3 bits size + 2 bits field name encoding + polymorphism flag + nullability flag + ref tracking flag</code>. |
| Users can use annotation to provide those info.<!-- --> |
| <ul> |
| <li class="">2 bits field name encoding:<!-- --> |
| <ul> |
| <li class="">encoding: <code>UTF8/ALL_TO_LOWER_SPECIAL/LOWER_UPPER_DIGIT_SPECIAL/TAG_ID</code></li> |
| <li class="">If tag id is used, i.e. field name is written by an unsigned varint tag id. 2 bits encoding will be <code>11</code>.</li> |
| </ul> |
| </li> |
| <li class="">size of field name:<!-- --> |
| <ul> |
| <li class="">The <code>3 bits size: 0~7</code> will be used to indicate length <code>1~7</code>, the value <code>6</code> the size read more bytes, |
| the encoding will encode <code>size - 7</code> as a varint next.</li> |
| <li class="">If encoding is <code>TAG_ID</code>, then num_bytes of field name will be used to store tag id.</li> |
| </ul> |
| </li> |
| <li class="">ref tracking: when set to 1, ref tracking will be enabled for this field.</li> |
| <li class="">nullability: when set to 1, this field can be null.</li> |
| <li class="">polymorphism: when set to 1, the actual type of field will be the declared field type even the type if |
| not <code>final</code>.</li> |
| </ul> |
| </li> |
| <li class="">type id:<!-- --> |
| <ul> |
| <li class="">For registered type-consistent classes, it will be the registered class id.</li> |
| <li class="">Otherwise it will be encoded as <code>OBJECT_ID</code> if it isn't <code>final</code> and <code>FINAL_OBJECT_ID</code> if it's <code>final</code>. The |
| meta for such types is written separately instead of inlining here is to reduce meta space cost if object of |
| this type is serialized in current object graph multiple times, and the field value may be null too.</li> |
| </ul> |
| </li> |
| <li class="">Field name: If type id is set, type id will be used instead. Otherwise meta string encoding length and data will |
| be written instead.</li> |
| </ul> |
| </li> |
| </ul> |
| <p>Field order are left as implementation details, which is not exposed to specification, the deserialization need to |
| resort fields based on Fory field comparator. In this way, fory can compute statistics for field names or types and |
| using a more compact encoding.</p> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=other-layers-class-meta>Other layers class meta<a href=#other-layers-class-meta class=hash-link aria-label="Direct link to Other layers class meta" title="Direct link to Other layers class meta" translate=no></a></h3> |
| <p>Same encoding algorithm as the previous layer except:</p> |
| <ul> |
| <li class="">header + package name:<!-- --> |
| <ul> |
| <li class="">Header:<!-- --> |
| <ul> |
| <li class="">If package name has been written before: <code>varint index + sharing flag(set)</code> will be written</li> |
| <li class="">If package name hasn't been written before:<!-- --> |
| <ul> |
| <li class="">If meta string encoding is <code>LOWER_SPECIAL</code> and the length of encoded string <code><=</code> 64, then header will be |
| <code>6 bits size + encoding flag(set) + sharing flag(unset)</code>.</li> |
| <li class="">Otherwise, header will |
| be <code>3 bits unset + 3 bits encoding flags + encoding flag(unset) + sharing flag(unset)</code></li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| <h2 class="anchor anchorTargetStickyNavbar_Vzrq" id=meta-string>Meta String<a href=#meta-string class=hash-link aria-label="Direct link to Meta String" title="Direct link to Meta String" translate=no></a></h2> |
| <p>Meta string is mainly used to encode meta strings such as class name and field names.</p> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=encoding-algorithms>Encoding Algorithms<a href=#encoding-algorithms class=hash-link aria-label="Direct link to Encoding Algorithms" title="Direct link to Encoding Algorithms" translate=no></a></h3> |
| <p>String binary encoding algorithm:</p> |
| <table><thead><tr><th>Algorithm<th>Pattern<th>Description<tbody><tr><td>LOWER_SPECIAL<td><code>a-z._$|</code><td>every char is written using 5 bits, <code>a-z</code>: <code>0b00000~0b11001</code>, <code>._$|</code>: <code>0b11010~0b11101</code>, prepend one bit at the start to indicate whether strip last char since last byte may have 7 redundant bits(1 indicates strip last char)<tr><td>LOWER_UPPER_DIGIT_SPECIAL<td><code>a-zA-Z0~9._</code><td>every char is written using 6 bits, <code>a-z</code>: <code>0b00000~0b11001</code>, <code>A-Z</code>: <code>0b11010~0b110011</code>, <code>0~9</code>: <code>0b110100~0b111101</code>, <code>._</code>: <code>0b111110~0b111111</code>, prepend one bit at the start to indicate whether strip last char since last byte may have 7 redundant bits(1 indicates strip last char)<tr><td>UTF-8<td>any chars<td>UTF-8 encoding</table> |
| <p>Encoding flags:</p> |
| <table><thead><tr><th>Encoding Flag<th>Pattern<th>Encoding Algorithm<tbody><tr><td>LOWER_SPECIAL<td>every char is in <code>a-z._$|</code><td><code>LOWER_SPECIAL</code><tr><td>FIRST_TO_LOWER_SPECIAL<td>every char is in <code>a-z[c1,c2]</code> except first char is upper case<td>replace first upper case char to lower case, then use <code>LOWER_SPECIAL</code><tr><td>ALL_TO_LOWER_SPECIAL<td>every char is in <code>a-zA-Z[c1,c2]</code><td>replace every upper case char by <code>|</code> + <code>lower case</code>, then use <code>LOWER_SPECIAL</code>, use this encoding if it's smaller than Encoding <code>LOWER_UPPER_DIGIT_SPECIAL</code><tr><td>LOWER_UPPER_DIGIT_SPECIAL<td>every char is in <code>a-zA-Z[c1,c2]</code><td>use <code>LOWER_UPPER_DIGIT_SPECIAL</code> encoding if it's smaller than Encoding <code>FIRST_TO_LOWER_SPECIAL</code><tr><td>UTF8<td>any utf-8 char<td>use <code>UTF-8</code> encoding<tr><td>Compression<td>any utf-8 char<td>lossless compression</table> |
| <p>Notes:</p> |
| <ul> |
| <li class="">For package name encoding, <code>c1,c2</code> should be <code>._</code>; For field/type name encoding, <code>c1,c2</code> should be <code>_$</code>;</li> |
| <li class="">Depending on cases, one can choose encoding <code>flags + data</code> jointly, uses 3 bits of first byte for flags and other |
| bytes |
| for data.</li> |
| </ul> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=shared-meta-string>Shared meta string<a href=#shared-meta-string class=hash-link aria-label="Direct link to Shared meta string" title="Direct link to Shared meta string" translate=no></a></h3> |
| <p>The shared meta string format consists of header and encoded string binary. Header of encoded string binary will be |
| inlined |
| in shared meta header.</p> |
| <p>Header is written using little endian order, Fory can read this flag first to determine how to deserialize the data.</p> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=write-by-data>Write by data<a href=#write-by-data class=hash-link aria-label="Direct link to Write by data" title="Direct link to Write by data" translate=no></a></h4> |
| <p>If string hasn't been written before, the data will be written as follows:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| unsigned varint: string binary size + 1 bit: not written before | 56 bits: unique hash | 3 bits encoding flags + string binary |</span><br/></div></code></pre></div></div> |
| <p>If string binary size is less than <code>16</code> bytes, the hash will be omitted to save spaces. Unique hash can be omitted too |
| if caller pass a flag to disable it. In such cases, the format will be:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| unsigned varint: string binary size + 1 bit: not written before | 3 bits encoding flags + string binary |</span><br/></div></code></pre></div></div> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=write-by-ref>Write by ref<a href=#write-by-ref class=hash-link aria-label="Direct link to Write by ref" title="Direct link to Write by ref" translate=no></a></h4> |
| <p>If string has been written before, the data will be written as follows:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| unsigned varint: written string id + 1 bit: written before |</span><br/></div></code></pre></div></div> |
| <h2 class="anchor anchorTargetStickyNavbar_Vzrq" id=value-format>Value Format<a href=#value-format class=hash-link aria-label="Direct link to Value Format" title="Direct link to Value Format" translate=no></a></h2> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=basic-types>Basic types<a href=#basic-types class=hash-link aria-label="Direct link to Basic types" title="Direct link to Basic types" translate=no></a></h3> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=bool>Bool<a href=#bool class=hash-link aria-label="Direct link to Bool" title="Direct link to Bool" translate=no></a></h4> |
| <ul> |
| <li class="">size: 1 byte</li> |
| <li class="">format: 0 for <code>false</code>, 1 for <code>true</code></li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=byte>Byte<a href=#byte class=hash-link aria-label="Direct link to Byte" title="Direct link to Byte" translate=no></a></h4> |
| <ul> |
| <li class="">size: 1 byte</li> |
| <li class="">format: write as pure byte.</li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=short>Short<a href=#short class=hash-link aria-label="Direct link to Short" title="Direct link to Short" translate=no></a></h4> |
| <ul> |
| <li class="">size: 2 byte</li> |
| <li class="">byte order: little endian order</li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=char>Char<a href=#char class=hash-link aria-label="Direct link to Char" title="Direct link to Char" translate=no></a></h4> |
| <ul> |
| <li class="">size: 2 byte</li> |
| <li class="">byte order: little endian order</li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=unsigned-int>Unsigned int<a href=#unsigned-int class=hash-link aria-label="Direct link to Unsigned int" title="Direct link to Unsigned int" translate=no></a></h4> |
| <ul> |
| <li class="">size: 1~5 byte</li> |
| <li class="">Format: The most significant bit (MSB) in every byte indicates whether to have the next byte. If first bit is set |
| i.e. <code>b & 0x80 == 0x80</code>, then |
| the next byte should be read until the first bit of the next byte is unset.</li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=signed-int>Signed int<a href=#signed-int class=hash-link aria-label="Direct link to Signed int" title="Direct link to Signed int" translate=no></a></h4> |
| <ul> |
| <li class="">size: 1~5 byte</li> |
| <li class="">Format: First convert the number into positive unsigned int by <code>(v << 1) ^ (v >> 31)</code> ZigZag algorithm, then encoding |
| it as an unsigned int.</li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=unsigned-long>Unsigned long<a href=#unsigned-long class=hash-link aria-label="Direct link to Unsigned long" title="Direct link to Unsigned long" translate=no></a></h4> |
| <ul> |
| <li class="">size: 1~9 byte</li> |
| <li class="">Fory PVL(Progressive Variable-length Long) Encoding:<!-- --> |
| <ul> |
| <li class="">positive long format: first bit in every byte indicates whether to have the next byte. If first bit is set |
| i.e. <code>b & 0x80 == 0x80</code>, then the next byte should be read until the first bit is unset.</li> |
| </ul> |
| </li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=signed-long>Signed long<a href=#signed-long class=hash-link aria-label="Direct link to Signed long" title="Direct link to Signed long" translate=no></a></h4> |
| <ul> |
| <li class="">size: 1~9 byte</li> |
| <li class="">Fory SLI(Small long as int) Encoding:<!-- --> |
| <ul> |
| <li class="">If long is in [-1073741824, 1073741823], encode as 4 bytes int: <code>| little-endian: ((int) value) << 1 |</code></li> |
| <li class="">Otherwise write as 9 bytes: <code>| 0b1 | little-endian 8 bytes long |</code></li> |
| </ul> |
| </li> |
| <li class="">Fory PVL(Progressive Variable-length Long) Encoding:<!-- --> |
| <ul> |
| <li class="">First convert the number into positive unsigned long by <code>(v << 1) ^ (v >> 63)</code> ZigZag algorithm to reduce cost of |
| small negative numbers, then encoding it as an unsigned long.</li> |
| </ul> |
| </li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=float>Float<a href=#float class=hash-link aria-label="Direct link to Float" title="Direct link to Float" translate=no></a></h4> |
| <ul> |
| <li class="">size: 4 byte</li> |
| <li class="">format: convert float to 4 bytes int by <code>Float.floatToRawIntBits</code>, then write as binary by little endian order.</li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=double>Double<a href=#double class=hash-link aria-label="Direct link to Double" title="Direct link to Double" translate=no></a></h4> |
| <ul> |
| <li class="">size: 8 byte</li> |
| <li class="">format: convert double to 8 bytes int by <code>Double.doubleToRawLongBits</code>, then write as binary by little endian order.</li> |
| </ul> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=string>String<a href=#string class=hash-link aria-label="Direct link to String" title="Direct link to String" translate=no></a></h3> |
| <p>Format:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| header: size << 2 | 2 bits encoding flags | binary data |</span><br/></div></code></pre></div></div> |
| <ul> |
| <li class=""><code>size + encoding</code> will be concat as a long and encoded as an unsigned var long. The little 2 bits is used for |
| encoding: |
| 0 for <code>latin</code>, 1 for <code>utf-16</code>, 2 for <code>utf-8</code>.</li> |
| <li class="">encoded string binary data based on encoding: <code>latin/utf-16/utf-8</code>.</li> |
| </ul> |
| <p>Which encoding to choose:</p> |
| <ul> |
| <li class="">For JDK8: fory detect <code>latin</code> at runtime, if string is <code>latin</code> string, then use <code>latin</code> encoding, otherwise |
| use <code>utf-16</code>.</li> |
| <li class="">For JDK9+: fory use <code>coder</code> in <code>String</code> object for encoding, <code>latin</code>/<code>utf-16</code> will be used for encoding.</li> |
| <li class="">If the string is encoded by <code>utf-8</code>, then fory will use <code>utf-8</code> to decode the data. But currently fory doesn't enable |
| utf-8 encoding by default for java. Cross-language string serialization of fory uses <code>utf-8</code> by default.</li> |
| </ul> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=collection>Collection<a href=#collection class=hash-link aria-label="Direct link to Collection" title="Direct link to Collection" translate=no></a></h3> |
| <blockquote> |
| <p>All collection serializers must extend <code>CollectionLikeSerializer</code>.</p> |
| </blockquote> |
| <p>Format:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">length(unsigned varint) | collection header | elements header | elements data</span><br/></div></code></pre></div></div> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=collection-header>Collection header<a href=#collection-header class=hash-link aria-label="Direct link to Collection header" title="Direct link to Collection header" translate=no></a></h4> |
| <ul> |
| <li class="">For <code>ArrayList/LinkedArrayList/HashSet/LinkedHashSet</code>, this will be empty.</li> |
| <li class="">For <code>TreeSet</code>, this will be <code>Comparator</code></li> |
| <li class="">For subclass of <code>ArrayList</code>, this may be extra object field info.</li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=elements-header>Elements header<a href=#elements-header class=hash-link aria-label="Direct link to Elements header" title="Direct link to Elements header" translate=no></a></h4> |
| <p>In most cases, all collection elements are same type and not null, elements header will encode those homogeneous |
| information to avoid the cost of writing it for every element. Specifically, there are four kinds of information |
| which will be encoded by elements header, each use one bit:</p> |
| <ul> |
| <li class="">If track elements ref, use the first bit <code>0b1</code> of the header to flag it.</li> |
| <li class="">If the collection has null, use the second bit <code>0b10</code> of the header to flag it. If ref tracking is enabled for this |
| element type, this flag is invalid.</li> |
| <li class="">If the collection element types are the declared type, use the 3rd bit <code>0b100</code> of the header to flag it.</li> |
| <li class="">If the collection element types are same, use the 4th bit <code>0b1000</code> header to flag it.</li> |
| </ul> |
| <p>By default, all bits are unset, which means all elements won't track ref, all elements are same type, not null and |
| the actual element is the declared type in the custom class field.</p> |
| <p>The implementation can generate different deserialization code based read header, and look up the generated code from a |
| linear map/list.</p> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=elements-data>Elements data<a href=#elements-data class=hash-link aria-label="Direct link to Elements data" title="Direct link to Elements data" translate=no></a></h4> |
| <p>Based on the elements header, the serialization of elements data may skip <code>ref flag</code>/<code>null flag</code>/<code>element class info</code>.</p> |
| <p><code>CollectionSerializer#write/read</code> can be taken as an example.</p> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=array>Array<a href=#array class=hash-link aria-label="Direct link to Array" title="Direct link to Array" translate=no></a></h3> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=primitive-array>Primitive array<a href=#primitive-array class=hash-link aria-label="Direct link to Primitive array" title="Direct link to Primitive array" translate=no></a></h4> |
| <p>Primitive array are taken as a binary buffer, serialization will just write the length of array size as an unsigned int, |
| then copy the whole buffer into the stream.</p> |
| <p>Such serialization won't compress the array. If users want to compress primitive array, users need to register custom |
| serializers for such types.</p> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=object-array>Object array<a href=#object-array class=hash-link aria-label="Direct link to Object array" title="Direct link to Object array" translate=no></a></h4> |
| <p>Object array is serialized using the collection format. Object component type will be taken as collection element |
| generic |
| type.</p> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=map>Map<a href=#map class=hash-link aria-label="Direct link to Map" title="Direct link to Map" translate=no></a></h3> |
| <blockquote> |
| <p>All Map serializers must extend <code>MapLikeSerializer</code>.</p> |
| </blockquote> |
| <p>Format:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| length(unsigned varint) | map header | key value pairs data |</span><br/></div></code></pre></div></div> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=map-header>Map header<a href=#map-header class=hash-link aria-label="Direct link to Map header" title="Direct link to Map header" translate=no></a></h4> |
| <ul> |
| <li class="">For <code>HashMap/LinkedHashMap</code>, this will be empty.</li> |
| <li class="">For <code>TreeMap</code>, this will be <code>Comparator</code></li> |
| <li class="">For other <code>Map</code>, this may be extra object field info.</li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=map-key-value-data>Map Key-Value data<a href=#map-key-value-data class=hash-link aria-label="Direct link to Map Key-Value data" title="Direct link to Map Key-Value data" translate=no></a></h4> |
| <p>Map iteration is too expensive, Fory won't compute the header like for collection before since it introduce |
| <a href=https://github.com/apache/fory/issues/925 target=_blank rel="noopener noreferrer" class="">considerable overhead</a>. |
| Users can use <code>MapFieldInfo</code> annotation to provide header in advance. Otherwise Fory will use first key-value pair to |
| predict header optimistically, and update the chunk header if the prediction failed at some pair.</p> |
| <p>Fory will serialize map chunk by chunk, every chunk has 127 pairs at most.</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| 1 byte | 1 byte | variable bytes |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+----------------+----------------+-----------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| KV header | chunk size: N | N*2 objects |</span><br/></div></code></pre></div></div> |
| <p>KV header:</p> |
| <ul> |
| <li class="">If track key ref, use the first bit <code>0b1</code> of the header to flag it.</li> |
| <li class="">If the key has null, use the second bit <code>0b10</code> of the header to flag it. If ref tracking is enabled for this |
| key type, this flag is invalid.</li> |
| <li class="">If the actual key type of map is the declared key type, use the 3rd bit <code>0b100</code> of the header to flag it.</li> |
| <li class="">If track value ref, use the 4th bit <code>0b1000</code> of the header to flag it.</li> |
| <li class="">If the value has null, use the 5th bit <code>0b10000</code> of the header to flag it. If ref tracking is enabled for this |
| value type, this flag is invalid.</li> |
| <li class="">If the value type of map is the declared value type, use the 6rd bit <code>0b100000</code> of the header to flag it.</li> |
| <li class="">If key or value is null, that key and value will be written as a separate chunk, and chunk size writing will be |
| skipped too.</li> |
| </ul> |
| <p>If streaming write is enabled, which means Fory can't update written <code>chunk size</code>. In such cases, map key-value data |
| format will be:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">| 1 byte | variable bytes |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+----------------+-----------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| KV header | N*2 objects |</span><br/></div></code></pre></div></div> |
| <p><code>KV header</code> will be a header marked by <code>MapFieldInfo</code> in java. The implementation can generate different deserialization |
| code based read header, and look up the generated code from a linear map/list.</p> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=enum>Enum<a href=#enum class=hash-link aria-label="Direct link to Enum" title="Direct link to Enum" translate=no></a></h3> |
| <p>Enums are serialized as an unsigned var int. If the order of enum values change, the deserialized enum value may not be |
| the value users expect. In such cases, users must register enum serializer by make it write enum value as an enumerated |
| string with unique hash disabled.</p> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=object>Object<a href=#object class=hash-link aria-label="Direct link to Object" title="Direct link to Object" translate=no></a></h3> |
| <p>Object means object of <code>pojo/struct/bean/record</code> type. |
| Object will be serialized by writing its fields data in fory order.</p> |
| <p>Depending on schema compatibility, objects will have different formats.</p> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=field-order>Field order<a href=#field-order class=hash-link aria-label="Direct link to Field order" title="Direct link to Field order" translate=no></a></h4> |
| <p>Field will be ordered as following, every group of fields will have its own order:</p> |
| <ul> |
| <li class="">primitive fields: larger size type first, smaller later, variable size type last.</li> |
| <li class="">boxed primitive fields: same order as primitive fields</li> |
| <li class="">final fields: same type together, then sorted by field name lexicographically.</li> |
| <li class="">collection fields: same order as final fields</li> |
| <li class="">map fields: same order as final fields</li> |
| <li class="">other fields: same order as final fields</li> |
| </ul> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=schema-consistent-1>Schema consistent<a href=#schema-consistent-1 class=hash-link aria-label="Direct link to Schema consistent" title="Direct link to Schema consistent" translate=no></a></h4> |
| <p>Object fields will be serialized one by one using following format:</p> |
| <div class="language-text codeBlockContainer_Ckt0 theme-code-block" style=--prism-color:#393A34;--prism-background-color:#f6f8fa><div class=codeBlockContent_QJqH><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style=color:#393A34;background-color:#f6f8fa><code class=codeBlockLines_e6Vv><div class=token-line style=color:#393A34><span class="token plain">Primitive field value:</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| var bytes |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+----------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| value data |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+----------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">Boxed field value:</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| one byte | var bytes |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+---------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| null flag | field value |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+---------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">field value of final type with ref tracking:</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| var bytes | var objects |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+-------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| ref meta | value data |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+-------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">field value of final type without ref tracking:</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| one byte | var objects |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+-------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| null flag | field value |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+-------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">field value of non-final type with ref tracking:</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| one byte | var bytes | var objects |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+-------------+-------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| ref meta | class meta | value data |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+-------------+-------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">field value of non-final type without ref tracking:</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| one byte | var bytes | var objects |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+------------+------------+</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">| null flag | class meta | value data |</span><br/></div><div class=token-line style=color:#393A34><span class="token plain">+-----------+------------+------------+</span><br/></div></code></pre></div></div> |
| <h4 class="anchor anchorTargetStickyNavbar_Vzrq" id=schema-evolution-1>Schema evolution<a href=#schema-evolution-1 class=hash-link aria-label="Direct link to Schema evolution" title="Direct link to Schema evolution" translate=no></a></h4> |
| <p>Schema evolution have similar format as schema consistent mode for object except:</p> |
| <ul> |
| <li class="">For this object type itself, <code>schema consistent</code> mode will write class by id/name, but <code>schema evolution</code> mode will |
| write class field names, types and other meta too, see <a href=#class-meta class="">Class meta</a>.</li> |
| <li class="">Class meta of <code>final custom type</code> needs to be written too, because peers may not have this class defined.</li> |
| </ul> |
| <h3 class="anchor anchorTargetStickyNavbar_Vzrq" id=class>Class<a href=#class class=hash-link aria-label="Direct link to Class" title="Direct link to Class" translate=no></a></h3> |
| <p>Class will be serialized using class meta format.</p> |
| <h2 class="anchor anchorTargetStickyNavbar_Vzrq" id=implementation-guidelines>Implementation guidelines<a href=#implementation-guidelines class=hash-link aria-label="Direct link to Implementation guidelines" title="Direct link to Implementation guidelines" translate=no></a></h2> |
| <ul> |
| <li class="">Try to merge multiple bytes into an int/long write before writing to reduce memory IO and bound check cost.</li> |
| <li class="">Read multiple bytes as an int/long, then split into multiple bytes to reduce memory IO and bound check cost.</li> |
| <li class="">Try to use one varint/long to write flags and length together to save one byte cost and reduce memory io.</li> |
| <li class="">Condition branches are less expensive compared to memory IO cost unless there are too many branches.</li> |
| </ul></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="row margin-top--sm theme-doc-footer-edit-meta-row"><div class="col noPrint_WFHX"><a href=https://github.com/apache/fory-site/tree/main/docs/specification/java_serialization_spec.md target=_blank rel="noopener noreferrer" class=theme-edit-this-page><svg fill=currentColor height=20 width=20 viewBox="0 0 40 40" class=iconEdit_Z9Sw aria-hidden=true><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"/></g></svg>Edit this page</a></div><div class="col lastUpdated_JAkA"></div></div></footer></article><nav class="docusaurus-mt-lg pagination-nav" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href=/docs/0.13/specification/xlang_serialization_spec><div class=pagination-nav__sublabel>Previous</div><div class=pagination-nav__label>Xlang Serialization Format</div></a><a class="pagination-nav__link pagination-nav__link--next" href=/docs/0.13/specification/row_format_spec><div class=pagination-nav__sublabel>Next</div><div class=pagination-nav__label>Row Format</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href=#spec-overview class="table-of-contents__link toc-highlight">Spec overview</a><li><a href=#fory-header class="table-of-contents__link toc-highlight">Fory header</a><li><a href=#reference-meta class="table-of-contents__link toc-highlight">Reference Meta</a><li><a href=#class-meta class="table-of-contents__link toc-highlight">Class Meta</a><ul><li><a href=#schema-consistent class="table-of-contents__link toc-highlight">Schema consistent</a><li><a href=#schema-evolution class="table-of-contents__link toc-highlight">Schema evolution</a></ul><li><a href=#meta-share class="table-of-contents__link toc-highlight">Meta share</a><ul><li><a href=#global-meta-header class="table-of-contents__link toc-highlight">Global meta header</a><li><a href=#type-header class="table-of-contents__link toc-highlight">Type header</a><li><a href=#single-layer-class-meta class="table-of-contents__link toc-highlight">Single layer class meta</a><li><a href=#other-layers-class-meta class="table-of-contents__link toc-highlight">Other layers class meta</a></ul><li><a href=#meta-string class="table-of-contents__link toc-highlight">Meta String</a><ul><li><a href=#encoding-algorithms class="table-of-contents__link toc-highlight">Encoding Algorithms</a><li><a href=#shared-meta-string class="table-of-contents__link toc-highlight">Shared meta string</a></ul><li><a href=#value-format class="table-of-contents__link toc-highlight">Value Format</a><ul><li><a href=#basic-types class="table-of-contents__link toc-highlight">Basic types</a><li><a href=#string class="table-of-contents__link toc-highlight">String</a><li><a href=#collection class="table-of-contents__link toc-highlight">Collection</a><li><a href=#array class="table-of-contents__link toc-highlight">Array</a><li><a href=#map class="table-of-contents__link toc-highlight">Map</a><li><a href=#enum class="table-of-contents__link toc-highlight">Enum</a><li><a href=#object class="table-of-contents__link toc-highlight">Object</a><li><a href=#class class="table-of-contents__link toc-highlight">Class</a></ul><li><a href=#implementation-guidelines class="table-of-contents__link toc-highlight">Implementation guidelines</a></ul></div></div></div></div></main></div></div></div><footer class="theme-layout-footer footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="theme-layout-footer-column col footer__col"><div class=footer__title>Community</div><ul class="footer__items clean-list"><li class=footer__item><a href=https://lists.apache.org/list.html?dev@fory.apache.org target=_blank rel="noopener noreferrer" class=footer__link-item>Mailing list<svg width=13.5 height=13.5 aria-label="(opens in new tab)" class=iconExternalLink_nPIU><use href=#theme-svg-external-link /></svg></a><li class=footer__item><a href=https://join.slack.com/t/fory-project/shared_invite/zt-1u8soj4qc-ieYEu7ciHOqA2mo47llS8A target=_blank rel="noopener noreferrer" class=footer__link-item>Slack<svg width=13.5 height=13.5 aria-label="(opens in new tab)" class=iconExternalLink_nPIU><use href=#theme-svg-external-link /></svg></a><li class=footer__item><a href=https://twitter.com/ApacheFory target=_blank rel="noopener noreferrer" class=footer__link-item>Twitter<svg width=13.5 height=13.5 aria-label="(opens in new tab)" class=iconExternalLink_nPIU><use href=#theme-svg-external-link /></svg></a></ul></div><div class="theme-layout-footer-column col footer__col"><div class=footer__title>Docs</div><ul class="footer__items clean-list"><li class=footer__item><a class=footer__link-item href=/docs/start/install>Install</a><li class=footer__item><a class=footer__link-item href=/docs/start/usage>Usage</a><li class=footer__item><a class=footer__link-item href=/docs/introduction/benchmark>Benchmark</a></ul></div><div class="theme-layout-footer-column col footer__col"><div class=footer__title>Repositories</div><ul class="footer__items clean-list"><li class=footer__item><a href=https://github.com/apache/fory target=_blank rel="noopener noreferrer" class=footer__link-item>Apache Fory™<svg width=13.5 height=13.5 aria-label="(opens in new tab)" class=iconExternalLink_nPIU><use href=#theme-svg-external-link /></svg></a><li class=footer__item><a href=https://github.com/apache/fory-site target=_blank rel="noopener noreferrer" class=footer__link-item>Website<svg width=13.5 height=13.5 aria-label="(opens in new tab)" class=iconExternalLink_nPIU><use href=#theme-svg-external-link /></svg></a></ul></div></div><div class="footer__bottom text--center"><div class=margin-bottom--sm><a href=https://apache.org/ rel="noopener noreferrer" class=footerLogoLink_BH7S><img src=/img/asf_logo.svg alt="ASF Logo" class="footer__logo themedComponent_mlkZ themedComponent--light_NVdE" width=200 /><img src=/img/asf_logo.svg alt="ASF Logo" class="footer__logo themedComponent_mlkZ themedComponent--dark_xIcU" width=200 /></a></div><div class=footer__copyright><div> |
| <p> |
| Copyright © 2026 The Apache Software Foundation, Licensed under the Apache License, Version 2.0. <br/> |
| Apache Fory, Fory, Apache, the Apache Logo and the Apache Fory logo are either registered trademarks or trademarks of the Apache Software Foundation in the United States and/or other countries. |
| </p> |
| </div></div></div></div></footer></div></body> |