Library / SDK
odnoklassniki/one-nio avatar
odnoklassniki/one-nio

one-nio and the case for going around the JDK's I/O layer

Unconventional I/O library for Java

729 stars120 forksJavaApache-2.0

At a glance

What is it?
one-nio is a Java library that reaches past the standard library into OS primitives and selected JDK internals, giving high-load servers native sockets, off-heap memory, a compact serialization format and an RPC stack. The cost is a hard dependency on JDK internals, and since version 2.2.0 that dependency has two generation modes, one of which is required on JDK 24 and later.
Who is it for?
one-nio suits a team running a high-load Java service where socket and serialization overhead is measurable and the team is willing to own a library that depends on JDK internals, because the off-heap memory API, the native epoll and sendfile wrappers and the schema-evolving serializer are not available anywhere else in the standard library.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A library that deliberately steps outside the JDK

one-nio is described as an unconventional I/O library for Java, and the README is direct about what it is: a library for building high-performance Java servers that exposes OS capabilities and selected JDK internal APIs to help high-load applications get the most out of the underlying system.

That framing explains the whole project. Every feature in it exists because the standard library either cannot do the job or does it through layers the author considered too slow for a server under load. The native socket API has its own native library and wraps Linux-specific primitives such as epoll_wait() and sendfile(). The off-heap APIs manage gigabytes of RAM beyond the Java heap through DirectMemory, MappedFile and off-heap hash tables. The serialization layer is described as significantly faster and more compact than standard Java serialization, with schema evolution and dynamic serializer generation built in.

There is also an RPC stack, described as an order of magnitude faster than Java RMI, plus a simple high-performance HTTP server, a general-purpose TCP server, and utilities for asynchronous execution, resource pooling and JMX management.

The audience is server developers with a performance problem they have already measured. It is not a general-purpose toolkit, and it is not appropriate for a script, a CLI tool or an application where the standard library is good enough.

What the serialization format gives up

The serialization section is the most detailed part of the documentation, and it reads like a contract because the format has real constraints.

Support for Serializable and Externalizable is there. readObject and writeObject are invoked when present, but they may only call defaultReadObject or defaultWriteObject on the data stream, so custom serialization logic is heavily restricted. Externalizable readExternal and writeExternal are fully supported.

Constructors are not invoked during deserialization. That is a meaningful difference from standard Java serialization, where constructors are bypassed anyway but where a class with no no-arg constructor can still be an obstacle in some flows. Here it is stated as a rule, with the single exception of collections and maps, which are serialized by contents and fall back to sensible defaults such as ArrayList or HashMap chosen by implemented interface.

serialVersionUID is ignored and is safe to omit, because the identity used to derive the format comes from instance field names, types and field order. That is the root of the schema evolution story: adding, removing or reordering fields stays compatible, renames are handled explicitly through the @Renamed annotation, and a set of type changes is auto-converted, covering primitive to primitive, wrapper to primitive, Number to Number, up and downcasts within a hierarchy, and conversions via valueOf() or instance methods when present. If no rule applies, the field falls back to a default of 0 or null.

Enumerations, wrappers and the JDK types that will bite you

A few details decide whether the format works for your data model.

Enums get a compact 2-byte encoding. Wrapper types cost roughly one byte more than their primitive counterparts, which is a reasonable trade for a field that may legitimately be null.

The JDK type caveat is the sharpest edge. java.sql.Date and java.sql.Time have only transient fields, so the documentation tells you to use java.util.Date or java.sql.Timestamp instead. A schema that was written against java.sql.Date will silently lose its data under this format, and nothing in the type names will warn you.

Anonymous and local classes are another trap. The engine warns with the message Trying to serialize anonymous class, which tells you the failure is detected at runtime rather than at compile time. Generated serializers cannot reason about a class that has no stable shape, so the object graph has to be built from named types.

Practically, this means the format is best suited to a deliberate, versioned wire model rather than to whatever happens to be in your domain objects today. The compatibility rules are generous for field additions and reorderings, but they do not rescue a model that was never designed to be serialized.

Serializing an object in ten lines

The API surface is small. A class implements Serializable, and two static calls do the work:

java
import one.nio.serial.Serializer;
import java.io.Serializable;
public class Example {
    static class User implements Serializable {
        String name;
        int age;
        transient String password; // will not be serialized
        User(String name, int age, String password) {
            this.name = name;
            this.age = age;
            this.password = password;
        }
    }
    public static void main(String[] args) throws Exception {
        User alice = new User("Alice", 30, "secret");
        byte[] data = Serializer.serialize(alice);
        User copy = (User) Serializer.deserialize(data);
        System.out.println(copy);
    }
}

The transient keyword keeps its standard Java meaning, and the password field is the reason the example exists.

There is a tooling story around this, which matters when a version conflict shows up in production. The documentation lists JMX statistics and a bytecode dump option as practical tooling for diagnosing version conflicts, and the wiki carries a Serialization FAQ with additional details.

The pattern to note is that the engine does not only encode values. It generates code for the class, and that generated code is where compatibility is decided.

Two serializer generation modes and the JDK 24 problem

one-nio generates serializer bytecode at runtime, and since version 2.2.0 that generation can proceed in one of two modes.

The magic_accessor mode is the legacy default on JDK 23 and earlier. It relies on the old MagicAccessor-based approach that depended on JDK internals. The method_handles mode is the newer experimental one, supported on JDK 9 and later, and it uses MethodHandles and VarHandles instead of the legacy internal APIs.

The important detail is the requirement: method_handles is required for JDK 24 and later. That is not a preference, it is a hard constraint, because the internal APIs the legacy mode depends on are no longer usable there.

The mode is chosen with the one.nio.serial.gen.mode system property, whose two documented values are magic_accessor and method_handles, so the setting is passed as a JVM flag on the command line.

So a deployment decision is baked into your startup flags and into how you build and package your service. If you run a mixed estate, some JVMs on JDK 21 and some on JDK 25, you are running two different serialization backends, and the behaviour differences between them are not something the README enumerates. The experimental label on method_handles is worth taking seriously if that is your only supported path.

Licence, build and release cadence

The licence is Apache-2.0, and the artifact is published to Maven Central under the group id ru.odnoklassniki with the artifact name one-nio, with javadocs available through javadoc.io. Apache-2.0 is permissive enough for commercial use with no copyleft obligation on your application code, and no legal advice is offered here beyond noting the identifier.

The build is Gradle, with build.gradle.kts and settings.gradle.kts at the root plus a gradle wrapper, and the project ships a CHANGELOG.md, CONTRIBUTORS and a copyright header script with both a shell and a batch variant, which is the shape of a project that cares about contribution hygiene.

The repository is not archived and the last push was on 2026-10-14. Release activity is high: 2.5.0 on 2026-10-13, 2.4.0 on 2026-10-01 and 2.3.0 on 2026-07-20. Two releases in the same month as the last commit suggests a responsive maintainer, but it also means the library moves quickly and your upgrade decisions have to keep pace.

The upgrade cost is mostly in the two places the README highlights: JDK version changes, which can force the generation mode, and schema changes in your own models, which the compatibility rules will mostly absorb but not always.

Editorial conclusion

one-nio suits a team running a high-load Java service where socket and serialization overhead is measurable and the team is willing to own a library that depends on JDK internals, because the off-heap memory API, the native epoll and sendfile wrappers and the schema-evolving serializer are not available anywhere else in the standard library. It does not suit a team that needs long-term upgrade safety, an application that must run on a JDK you do not control, or a codebase where standard Java serialization is good enough. Before adopting, confirm that the one.nio.serial.gen.mode setting matches your JDK version, since JDK 24 and later require method_handles, read the Serialization FAQ for the type-change rules your models rely on, and verify that the JMX statistics and bytecode dump tooling are enough to diagnose a version conflict in production.

Frequently asked questions

What is one-nio and who is it for?

one-nio is a library for building high-performance Java servers that exposes OS capabilities and selected JDK internal APIs. It is aimed at high-load applications that need native sockets, off-heap memory and fast serialization beyond what the standard library provides.

How do I choose the serializer generation mode in one-nio?

Set the one.nio.serial.gen.mode system property to either magic_accessor or method_handles. The magic_accessor mode is the default on JDK 23 and earlier, while method_handles is required for JDK 24 and later.

How does one-nio handle schema evolution?

Adding, removing or reordering fields is compatible, safe renames work through the @Renamed annotation, and certain type changes are auto-converted, including primitive to primitive, wrapper to primitive, Number to Number and casts within a hierarchy. If no rule applies, the field falls back to 0 or null.

Are there Java types that one-nio cannot serialize correctly?

java.sql.Date and java.sql.Time have only transient fields, so the documentation recommends java.util.Date or java.sql.Timestamp instead. Anonymous and local classes are also flagged, with the engine warning that it is trying to serialize an anonymous class.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. odnoklassniki/one-nio on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/odnoklassniki-one-nio.svg)](https://hysenlabs.com/projects/odnoklassniki-one-nio)

Was this useful?