Skip to content

Commit

Permalink
feat(java): support nonexistent class deserialization in meta share m…
Browse files Browse the repository at this point in the history
…ode (#1646)

## What does this PR do?

support nonexistent class deserialization in meta share mode

## Related issues

<!--
Is there any related issue? Please attach here.

- #xxxx0
- #xxxx1
- #xxxx2
-->


## Does this PR introduce any user-facing change?

<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/incubator-fury/issues/new/choose)
describing the need to do so and update the document if necessary.
-->

- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?


## Benchmark

<!--
When the PR has an impact on performance (if you don't know whether the
PR will have an impact on performance, you can submit the PR first, and
if it will have impact on performance, the code reviewer will explain
it), be sure to attach a benchmark data here.
-->
  • Loading branch information
chaokunyang authored May 27, 2024
1 parent 03dba11 commit 3a0e410
Show file tree
Hide file tree
Showing 14 changed files with 496 additions and 242 deletions.
6 changes: 3 additions & 3 deletions docs/guide/java_serialization_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public class Example {
| `requireClassRegistration` | Disabling may allow unknown classes to be deserialized, potentially causing security risks. | `true` |
| `suppressClassRegistrationWarnings` | Whether to suppress class registration warnings. The warnings can be used for security audit, but may be annoying, this suppression will be enabled by default. | `true` |
| `shareMetaContext` | Enables or disables meta share mode. | `false` |
| `deserializeUnexistedClass` | Enables or disables deserialization/skipping of data for non-existent classes. | `true` if `CompatibleMode.Compatible` is set, otherwise false. |
| `deserializeNonexistentClass` | Enables or disables deserialization/skipping of data for non-existent classes. | `true` if `CompatibleMode.Compatible` is set, otherwise false. |
| `codeGenEnabled` | Disabling may result in faster initial serialization but slower subsequent serializations. | `true` |
| `asyncCompilationEnabled` | If enabled, serialization uses interpreter mode first and switches to JIT serialization after async serializer JIT for a class is finished. | `false` |
| `scalaOptimizationEnabled` | Enables or disables Scala-specific serialization optimization. | `false` |
Expand Down Expand Up @@ -363,13 +363,13 @@ MetaContext context=xxx;
### Deserialize non-existent classes

Fury support deserializing non-existent classes, this feature can be enabled
by `FuryBuilder#deserializeUnexistedClass(true)`. When enabled, and metadata sharing enabled, Fury will store
by `FuryBuilder#deserializeNonexistentClass(true)`. When enabled, and metadata sharing enabled, Fury will store
the deserialized data of this type in a lazy subclass of Map. By using the lazy map implemented by Fury, the rebalance
cost of filling map during deserialization can be avoided, which further improves performance. If this data is sent to
another process and the class exists in this process, the data will be deserialized into the object of this type without
losing any information.

If metadata sharing is not enabled, the new class data will be skipped and an `UnexistedSkipClass` stub object will be
If metadata sharing is not enabled, the new class data will be skipped and an `NonexistentSkipClass` stub object will be
returned.

## Migration
Expand Down
14 changes: 7 additions & 7 deletions java/fury-core/src/main/java/org/apache/fury/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public class Config implements Serializable {
private final boolean registerGuavaTypes;
private final boolean shareMetaContext;
private final boolean asyncCompilationEnabled;
private final boolean deserializeUnexistedClass;
private final boolean deserializeNonexistentClass;
private final boolean scalaOptimizationEnabled;
private transient int configHash;
private final boolean deserializeNonexistentEnumValueAsNull;
Expand All @@ -75,8 +75,8 @@ public Config(FuryBuilder builder) {
checkJdkClassSerializable = builder.checkJdkClassSerializable;
defaultJDKStreamSerializerType = builder.defaultJDKStreamSerializerType;
shareMetaContext = builder.shareMetaContext;
deserializeUnexistedClass = builder.deserializeUnexistedClass;
if (deserializeUnexistedClass) {
deserializeNonexistentClass = builder.deserializeNonexistentClass;
if (deserializeNonexistentClass) {
// Only in meta share mode or compatibleMode, fury knows how to deserialize
// unexisted class by type info in data.
Preconditions.checkArgument(shareMetaContext || compatibleMode == CompatibleMode.COMPATIBLE);
Expand Down Expand Up @@ -186,8 +186,8 @@ public boolean shareMetaContext() {
* Whether deserialize/skip data of un-existed class. If not enabled, an exception will be thrown
* if class not exist.
*/
public boolean deserializeUnexistedClass() {
return deserializeUnexistedClass;
public boolean deserializeNonexistentClass() {
return deserializeNonexistentClass;
}

/**
Expand Down Expand Up @@ -237,7 +237,7 @@ public boolean equals(Object o) {
&& registerGuavaTypes == config.registerGuavaTypes
&& shareMetaContext == config.shareMetaContext
&& asyncCompilationEnabled == config.asyncCompilationEnabled
&& deserializeUnexistedClass == config.deserializeUnexistedClass
&& deserializeNonexistentClass == config.deserializeNonexistentClass
&& scalaOptimizationEnabled == config.scalaOptimizationEnabled
&& language == config.language
&& compatibleMode == config.compatibleMode
Expand Down Expand Up @@ -267,7 +267,7 @@ public int hashCode() {
registerGuavaTypes,
shareMetaContext,
asyncCompilationEnabled,
deserializeUnexistedClass,
deserializeNonexistentClass,
scalaOptimizationEnabled);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public final class FuryBuilder {
boolean requireClassRegistration = true;
boolean shareMetaContext = false;
boolean codeGenEnabled = true;
Boolean deserializeUnexistedClass;
Boolean deserializeNonexistentClass;
boolean asyncCompilationEnabled = false;
boolean registerGuavaTypes = true;
boolean scalaOptimizationEnabled = false;
Expand Down Expand Up @@ -241,10 +241,10 @@ public FuryBuilder withMetaContextShare(boolean shareMetaContext) {
/**
* Whether deserialize/skip data of un-existed class.
*
* @see Config#deserializeUnexistedClass()
* @see Config#deserializeNonexistentClass()
*/
public FuryBuilder withDeserializeUnexistedClass(boolean deserializeUnexistedClass) {
this.deserializeUnexistedClass = deserializeUnexistedClass;
public FuryBuilder withDeserializeNonexistentClass(boolean deserializeNonexistentClass) {
this.deserializeNonexistentClass = deserializeNonexistentClass;
return this;
}

Expand Down Expand Up @@ -301,12 +301,12 @@ private void finish() {
}
if (compatibleMode == CompatibleMode.COMPATIBLE) {
checkClassVersion = false;
if (deserializeUnexistedClass == null) {
deserializeUnexistedClass = true;
if (deserializeNonexistentClass == null) {
deserializeNonexistentClass = true;
}
} else {
if (deserializeUnexistedClass == null) {
deserializeUnexistedClass = false;
if (deserializeNonexistentClass == null) {
deserializeNonexistentClass = false;
}
}
if (!requireClassRegistration) {
Expand Down
Loading

0 comments on commit 3a0e410

Please sign in to comment.