blob: d6ae9584be6b88fb0db4b02f4e65d0f6f7090bca [file]
<!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 &lt;&lt; 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 &lt;&lt; 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 &lt;&lt; 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>&lt;=</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 &lt;&lt; 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) &lt;&lt; 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 &lt;&lt; 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 &lt;&lt; 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>