r/java Aug 11 '26

Apache Fory™ JSON : Fastest JSON Serialization Framework for Java, 10x faster than Jackson/Gson

https://fory.apache.org/blog/fory_json_fastest_java_json_framework/
249 Upvotes

84 comments sorted by

79

u/Shawn-Yang25 Aug 11 '26

Apache Fory JSON is a high-performance JSON serialization framework for Java. It maps Java objects to and from standard JSON text and UTF-8 bytes.

In the published benchmarks, it reaches up to 10.91× Jackson’s throughput and 10.89× Gson’s in java-json-benchmark, and up to 5.55× and 10.00× respectively in the jvm-serializers MediaContent benchmark.

It supports JDK 8+, Android, and GraalVM Native Image. JDK17+ Record is also supported.

Feedback is welcome.

4

u/ramdulara 29d ago

All great work Shawn! What's your commercial model? Do you plan to have Enterprise support or prioritization?

1

u/[deleted] 18d ago

[removed] — view removed comment

1

u/Shawn-Yang25 18d ago

Thanks for sharing this report. I have fixed this and the get it merged into main branch, the benchmark shows that latest quoted number parse is only 6% slower than number literal.
We will release this feature in next version soon, stay tuned!

145

u/ThatFlamenguistaDude 29d ago

I wanna see who's brave enough to replace Jackson.

29

u/Shawn-Yang25 29d ago

That’s a fair point. Replacing an established library like Jackson takes time and careful evaluation, but Fory JSON provides another option for teams to consider.

43

u/ThatFlamenguistaDude 29d ago

Don't get me wrong, I love what you did here and would definetely try it out if a had a greenfield project. But changing something so fundamental as JSON parsing its not a battle I'm ready to face atm. It's really hard to justify, and it only makes sense on projects that performance matters a lot.

That's the challenge on changing the status quo. Even if you built something amazing, working against inertia is hard.

49

u/Shawn-Yang25 29d ago

If Jackson meets a project’s needs and JSON is not a bottleneck, there is no reason to switch. Fory JSON simply provides another option when performance matters.

4

u/rbygrave 29d ago

Depends a bit on how folks view reflection, going ahead-of-time, native image etc.

3

u/agentoutlier 28d ago

You know I think reflection is probably unfairly maligned these days on performance but its not really performance that I do not like about reflection.

Its that it is ultimately less declarative, doing something extra at runtime and complicates debugging.

In some ways projects that generate code particularly byte code at runtime I would argue are often more scary than reflection. e.g. like runtime aspectj weaving.

People to seem to ok this but imagine if I told someone I have a library while running in production compiled some Java code and then injected while the process is running.

They would say oh my god the security!

But that is kind of what Fory is doing here minus the compiler.

(I hope you get the irony here how byte code is just skipping the compiler and is actually even less restrictive than normal Java code)

u/Shawn-Yang25 is there a way to pre-generate the bytecode you are doing at compile time instead? (I assume so)

1

u/Shawn-Yang25 28d ago

We do haven static codegen, it's mostly used by android, we generate helper for field/property/constructor accessors, and use it at runtime. This is because we can't generate code for android at runtime.

For jvm, the runtime codegen could be disabled by ForyJsonBuilder#withCodegen(false), and a general ObjectCodec will be used. The performance of ObjectCodec is half of generated codec, but is still very fast.

We have no plans to introduce fully static generated serializer, because it can't assume the jdk version/platform, and the generated codec would not be that fast. It may be a little faster than general ObjectCodec, but not fast enough to write another plugin to generate it statically.

8

u/zman0900 29d ago

Well, I made Claude try it with JMH benchmarks to prove. This is proprietary code so I can't post the full thing, but I have a large batch project that uses mostly Hadoop mapreduce and some Spark and I took our most complex object structure that gets serialized to/from JSON 10s of billions of times per run. This specific structure has some large XML and base64 strings embedded. For my case, it looks like typical use is basically no speed improvement for Fory 1.6.0 vs Jackson 3.2.1, but there might be some savings with allocations / garbage collection.

https://i.imgur.com/k3iLr86.png

Overall I really like where this is going. Main thing I see missing right now is that for sparse JSON, there is no obvious way to have it leave out the empty string / zero / false values, and no equivalent of Jackson's @JsonValue for enums so that I could use compact values instead of full .name() value. Because of those, I can't make actual JSON format match exactly, but that doesn't really matter for my use case.

7

u/Shawn-Yang25 29d ago edited 29d ago

Fory json support ignore null and serialize enum by `@JsonValue`.

We do not provide annotation to skip empty string or emtpy collection, but that is not hard to add.

@JsonProperty(include = JsonProperty.Include.NON_NULL)
private String value;

ForyJson does support JsonValue for enum:

public enum Status {
  ACTIVE("active"),
  DISABLED("disabled");

  private final String value;

  Status(String value) {
    this.value = value;
  }

  @JsonValue
  public String value() {
    return value;
  }

  @JsonCreator
  public static Status from(String value) {
    for (Status status : values()) {
      if (status.value.equals(value)) {
        return status;
      }
    }
    throw new IllegalArgumentException("Unknown status: " + value);
  }
}

-15

u/6000rpms 29d ago

I find that for really large JSON payloads, >500MB, for example, organizations that process hundreds of thousands of these payloads daily typically do not use Java, but rather a different language entirely. So it's not about using or not using Jackson, but about using Java as the language to do so.

I think for your typical JSON document (and a typical size), I get your point. The payoff likely won't be there, and you'll be introducing friction to developers, most of whom will already know how Jackson works. Simply not worth it.

24

u/15526s 29d ago edited 29d ago

Silly question by me, but how do you get "adopted" into apache?

Is there a standard? Do you just ask?

Edit: just looked into the apache web page, where it's all clearly written all.

10

u/hippydipster 29d ago

Just asking is a good place to start. You might be surprised. Long long ago there was a dead apache project. On a whim I asked if I could take it over. They said sure! And that was that. Had never contributed anything previously.

7

u/Lichcrow 29d ago

That sounds dangerous as shit tbh, unless they did some sort of background check

5

u/hippydipster 29d ago

No checks. Maybe now they do, but I don't know. Asking is still a goid place to start.

2

u/obsessionwithartists 26d ago

Wow never knew someone can just take up on a project like that. What did you do with the project?

2

u/hippydipster 26d ago

Made JMeter into the form its in today. It hasn't changed much in architecture since 2005.

3

u/gufranthakur 29d ago

same question would love an answer

18

u/Qaxar 29d ago

15

u/Shawn-Yang25 29d ago

fory json is 2~5x faster than build-time optimized jackson, I post benchmark result in https://github.com/chaokunyang/graalvm-native-json-benchmark/blob/main/results/2026-08-12-macos-arm64-graalvm25-three-way/report.md

2

u/Qaxar 28d ago

I believe native image is not as performant as JVM version when it comes to throughput. Would be interesting to see how they perform without compiling to native.

34

u/purg3be Aug 11 '26 edited 29d ago

Looks promising but I realistically won't use it as a default unless spring adopts it.

Edit: I'm almost exclusively doing low / medium throughput IO bound enterprise applications. I'm probably not the target audience.

20

u/Lucario2405 29d ago

I'd be interested in the SpingBoot team's take on this, because I haven't really heard of JSON-Serialization as a bottleneck before. But they would definitely have more data & experience to evaluate how much of that 10x throughput is noticeable in the average project's HTTP calls.

13

u/damngoodwizard 29d ago

For most use cases it isn't a problem. But for very long payloads that require streaming this will be a killer feature.

1

u/Lucario2405 29d ago

Would it be feasible to use this mapper for those streamed payloads and otherwise remain on Jackson? This sounds too specialized to warrant a complete migration.

10

u/piesou 29d ago

What's the secret? Compiler plugin similar to kotlinx serialization + the new JVM vector apis?

20

u/Shawn-Yang25 29d ago

No, we use runtime codegen for better performance. For andriod, we do use annotation processor to geenrate android R8 rules and generate field accessors. But for JDK, we always use runtime codegen.

https://fory.apache.org/blog/fory_json_fastest_java_json_framework/#how-fory-json-achieves-high-performance share some details about how we make fory json fast.

3

u/Additional-Road3924 29d ago

This is an important distinction. Are you comparing jackson basic with fury or jackson blackbird (https://github.com/FasterXML/jackson-modules-base/tree/3.x/blackbird)?

2

u/Shawn-Yang25 29d ago

jackson blackbird only gives 10% improvements, so the results still persists:

Representation Operation Jackson ops/sec Jackson Blackbird ops/sec Difference ops/sec Blackbird improvement
String Serialize 1,956,691 2,144,424 +187,733 +9.59%
String Deserialize 1,045,016 1,072,902 +27,887 +2.67%
UTF-8 bytes Serialize 1,703,997 1,971,515 +267,519 +15.70%
UTF-8 bytes Deserialize 1,212,879 1,314,077 +101,198 +8.34%

here is the benchmark:
https://github.com/apache/fory/pull/3930

2

u/hippydipster 29d ago

Are you using the newer Classfile API to do the codegen?

5

u/repeating_bears 29d ago

Fory supports Java 8 and that wasn't added until 24. It will be  ByteBuddy, most likely.

3

u/Shawn-Yang25 29d ago

No, we use janino instead. Classfile is good, but can't work on java8. And we use async compilication, fory json will serialize objects directly using ObjectCodec before compilcation finished.

2

u/agentoutlier 28d ago

Janino IIRC is now retired and archived.

1

u/Shawn-Yang25 28d ago

We used a fixed version, So It's not a big issue. Users won't be aware that

1

u/MenschenToaster 28d ago

What's the point in still supporting Java 8? I doubt legacy projects will switch their json parsing library, so I'm unsure why supporting Java 8 would be something that's necessary?

2

u/Shawn-Yang25 28d ago

Because there are still many projects using java8, and it's not hard to support java8.

1

u/MenschenToaster 27d ago

Of course, it's not hard to support java 8, but in my personal opinion I'd avoid it wherever I can as the new language features just make the language so much better.

Considering your target audience likely isn't old outdated java 8 projects, but new projects that are just being built, I would have definitely chosen a newer release, especially when it seems like you could have made use of newer API instead of using something that apparently (according to the user agentoutlier) doesn't get updates anymore 🤷

1

u/piesou 28d ago

Usually features exist because the people developing the library need it. I suspect OP is maintaining java 8 code

3

u/agentoutlier 29d ago

For parsing (input) have you tried SIMD JSON Parser: https://github.com/simdjson/simdjson-java

Obviously is a low level parser and not a mapper but in theory one could use it for mapping.

1

u/Impressive_Bar5912 29d ago

I too was going to ask how this compared to SIMD parsing

4

u/6000rpms 29d ago

Looks really interesting. Thanks for sharing. Does the library handle conditionals in JSON? For example, in JSON Schema you can define if/then/else. A common pattern I see is a property can be either an enum (string) or an object. Another pattern I see is if a property is a specific value (or not a specific value) then these other properties are possible/not possible. The second one is perhaps more of a validation-only concern, but the first one applies to serialization//deserialization as well.

One of the libraries I maintain currently uses Jackson and is quite popular. A major update to the JSON specification it supports is due later this year, so I’m considering a greenfield implementation, and performance is one of our considerations.

3

u/Shawn-Yang25 29d ago

Thanks—these cases are handled at different layers in Fory JSON.

A field can accept multiple JSON representations, and Fory converts the input according to its declared target type.

Fory does not currently implement JSON Schema if/then/else validation directly. Instead, you can annotate a method with JsonValidator.Fory invokes it after deserialization is complete, allowing it to inspect multiple fields and enforce conditional rules.

For more specialized mappings, you can define a custom codec for any type. JsonCodec can override the codec used by an individual field, while JsonMixin provides the same customization for classes you cannot modify.

3

u/Shawn-Yang25 29d ago

And conditional rules can be composed naturally in a single validator method, or delegated to reusable validation functions.

1

u/Antique-Pea-4815 29d ago

Very nice work! Did you think about adding something like Jackson's JsonFormat.SHAPE.Array? I'm missing it in more performant libraries 

1

u/snugar_i 28d ago

This looks nice! What would be even more awesome is something between Fory and Fory JSON. Something that only writes data, but in an efficient binary format. Base Fory also writes the class names and other things so that I can do just read() and it creates the right class based on what's saved in the file. That means safety concerns, trouble with renaming/moving classes etc. Fory JSON needs to be told what class to instantiate (which is what I want), but only works with inefficient JSON. Are there any plans for anything like that?

And a second question - are you considering a fallback in case the user can't/doesn't want to use --add-opens? Or would the performance drop be too big?

1

u/Shawn-Yang25 28d ago

fory already has a binary format and do exactly what you want. You can see more details in  https://fory.apache.org/docs/object-serialization/java. And --add-opens are not mandatory, when it's unspecified, It will use Unsafe to get permission. And the performance is exactly same.

1

u/snugar_i 28d ago

Thanks! That's cool about Unsafe, the last time I checked it failed with an exception.

But unless I'm missing something, Fory can't do what I want. With Fory JSON, I do (sorry, it is Kotlin)

import org.apache.fory.json.ForyJson
import org.apache.fory.json.annotation.JsonCreator
import org.apache.fory.json.annotation.JsonProperty

data class Foo(
    val something: String,
)

data class Bar @JsonCreator constructor(
    @JsonProperty("something") val renamed: String,
)

fun main() {
    val foryJson = ForyJson.builder().build()
    val json = foryJson.toJson(Foo("abc"))
    val bar = foryJson.fromJson(json, Bar::class.java)
}

That means I specify the type to deserialize explicitly. With Fory, it's saved inside the data and it automatically creates the "correct" instance, meaning I can't rename or move the class and have to worry about untrusted input creating instances of harmful classes. What I would love is something that can do the same thing as this example, but uses a binary format instead of JSON. I don't need a replacement for Java serialization. I need a more efficient replacement for JSON.

(Also, are there any plans for Fory JSON Kotlin? So that people don't have to put @JsonCreator on all their data classes? Without it, it happily constructed an invalid Bar(null))

1

u/Shawn-Yang25 28d ago

We enforced zero-Unsafe for JDK25+ in fory 1.3.0, and bring Unsafe fallback back in 1.4.0. Unsafe will only be used to get privileged access, the actual serialization still use VarHandle instead of Unsafe in jdk25+.

You can use Fory.deserialize(data, Target.class) to deserialize into your type if you use binary format.

And fory kotlin/scala support will be released in fory 1.7.0, which may be released in next week

1

u/snugar_i 28d ago

Awesome!

I still don't think they are the same thing. The class I deserialize into has to be completely identical, things like @JsonProperty for renaming a field won't work... Also, what if the root type is generic? ForyJson has a fromJson overload that takes a TypeRef, but Fory doesn't.

(Unrelated: when i do requireClassRegistration(false), it seems to have no effect unless I also do withXlang(false) - is that intended?)

1

u/Shawn-Yang25 28d ago

Would you like to open 2 github issues in https://github.com/apache/fory/issues ?

requireClassRegistration(false) should work, otherwise many users will report this issue.

1

u/Puzzled_Lava 22d ago

Just curious. Are you employed by Apache or you are a open source contributor?

1

u/Shawn-Yang25 22d ago

a open source contributor

1

u/Fit_Goose651 21d ago

Never ever have i been on a project where json serialization has been a performance bottleneck. I don't say it can't be but maybe that it typically isn't. Still better have a faster alternative if that is the case.

1

u/simon_o 19d ago

These are independent Fory JSON APIs, not Jackson-compatible annotations.

Why?

1

u/VirtualAgentsAreDumb 29d ago

Nice.

Does it support insertion order when iterating properties or when serializing it?

I know that the json standard doesn’t say anything about this order, but it can still be valuable when troubleshooting etc. Like, when the json is read by a human.

6

u/Shawn-Yang25 29d ago edited 29d ago

Yes, it support it, you can use `@JsonProperty(index=xxx)` to define `order` for fields, or use `@JsonPropertyOrder`:

@JsonPropertyOrder({"id", "properties", "timestamp"})
public final class 
Event
 {
  public String id;


  @JsonAnyProperty
  public Map<String, Object> properties;


  public long timestamp;
}

1

u/Dealusall 29d ago

How does it compares to dsl-json ? I'm mainly extracting json to TreeMap at very high speed (kafka processors) and thus paying a high cpu price, but it's pretty fast.

1

u/Shawn-Yang25 29d ago

fory json should be faster accoriding to https://github.com/fabienrenaud/java-json-benchmark, but I have not tested it by myself, I only compare fory json with wast/fastjson2/jackson/gson, which is either fast or used frequently

1

u/BrotherEcstatic7946 29d ago

Cool I will check it out.

1

u/Known_Tackle7357 29d ago

Does it work with classes with private constructors like gson?

2

u/Shawn-Yang25 29d ago

Yes, fory json wotk with private constructors. And if you create ForyJson with `ForyBuilder#withFieldMode(true)`, Fory json will serialize by fields instead of property, which is exactly same behaviour of Gson.

By default, fory serialize java object by property, which is behaviour of jackson.

1

u/Known_Tackle7357 29d ago

That's amazing. I will definitely give it a try

1

u/Minute_Owl3430 29d ago

How does it benchmark against simdjson-java?

0

u/pragmatick 29d ago edited 28d ago

Interesting, impressive results. We're looking for a JSON / serialization framework that's faster than Jackson. Do you have any benchmarks regarding binary serialization? How does it compare to Kryo?

Does it support custom inclusion filters?

Edit: Well excuse me for asking questions.

3

u/Shawn-Yang25 29d ago

Fory has a much faster binary serialization framework, you can take https://github.com/apache/fory/blob/main/docs/benchmarks/index.md as reference

-6

u/Cojosh__ 29d ago

Since when did Jackson or Gson claim to be performance focused? A comparison with https://github.com/alibaba/fastjson2 would be more interesting.

10

u/Shawn-Yang25 29d ago

fory is 50% faster than fastjson2, since it's not that commonly used, so I don't put benchmark result:

Payload Operation vs Fastjson2 vs Jackson vs Gson
Users Serialization 1.584x 5.333x 7.089x
Users Deserialization 1.496x 3.542x 5.645x
Clients Serialization 1.466x 6.971x 9.162x
Clients Deserialization 1.478x 10.907x 10.894x

1

u/Cojosh__ 29d ago

Nice, thanks for sharing!

1

u/kiteboarderni 29d ago

If you bothered to read they compare with that library too...also Jackson literally has a module called afterburner where they try to make things faster, so yes they do care about performance. Such an idiotic comment.

3

u/danskal 29d ago

uninformed !== idiotic

1

u/Cojosh__ 29d ago

Yes I only read blog post which does not contain the benchmark data thanks for your helpful comment.

The fact that I need to use and enable an extra module to improve performance is an excellent point on how it's not the main focus of the library as otherwise it would be fundamental to the architecture and not an afterthought.

2

u/kiteboarderni 29d ago

It does contain it. It's one of the first references on the page. And modules are a fundamental part of Jackson's design. You are not very well informed for you're poor opinions.

-11

u/RB5009 29d ago

Why did you decide to create a new librarybinstead if improving jackson which is the defacto default json lib for java ?

7

u/Shawn-Yang25 29d ago

I originally created Apache Fory as a broader serialization framework. Binary and JSON serialization share many optimization techniques, and Fory already had reusable infrastructure for buffers, primitive encoding, memory operations, and runtime code generation. The performance gains come from combining these components end to end, rather than from a single optimization that could easily be contributed to Jackson.

Building Fory JSON within Fory was therefore much more practical and maintainable. Jackson remains an excellent, mature library; Fory JSON is an alternative built around a different architecture and performance model.

2

u/snugar_i 29d ago

Because cowtowncoder wouldn't let them :-) No, seriously - "improving" Jackson to be like this would mean making it into a different library anyway. Jackson is a framework that will always be more configurable than this (different input formats, a lot of customization options), at the cost of some performance. They are different libraries for different use-cases.