Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions java/fory-core/src/main/java/org/apache/fory/Fory.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.apache.fory;

import com.google.common.base.Objects;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
Expand Down Expand Up @@ -127,11 +128,13 @@ public final class Fory implements BaseFory {
private int copyDepth;
private final boolean copyRefTracking;
private final IdentityMap<Object, Object> originToCopyMap;
private int configHash;

public Fory(ForyBuilder builder, ClassLoader classLoader) {
// Avoid set classLoader in `ForyBuilder`, which won't be clear when
// `org.apache.fory.ThreadSafeFory.clearClassLoader` is called.
config = new Config(builder);
this.configHash = config.hashCode();
crossLanguage = config.getLanguage() != Language.JAVA;
this.refTracking = config.trackingRef();
this.copyRefTracking = config.copyRef();
Expand Down Expand Up @@ -226,18 +229,24 @@ public void register(String className, String namespace, String typeName) {
@Override
public <T> void registerSerializer(Class<T> type, Class<? extends Serializer> serializerClass) {
_getTypeResolver().registerSerializer(type, serializerClass);
this.configHash = Objects.hashCode(configHash, type, serializerClass);
}

@Override
public void registerSerializer(Class<?> type, Serializer<?> serializer) {
_getTypeResolver().registerSerializer(type, serializer);
this.configHash = Objects.hashCode(configHash, type, serializer.getClass());
}

@Override
public void registerSerializer(Class<?> type, Function<Fory, Serializer<?>> serializerCreator) {
_getTypeResolver().registerSerializer(type, serializerCreator.apply(this));
}

public int getConfigHash() {
return configHash;
}

@Override
public <T> void registerSerializerAndType(
Class<T> type, Class<? extends Serializer> serializerClass) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ public String codecClassName(Class<?> beanClass) {
nameBuilder.append("Codec").append(codecSuffix());
Map<String, Integer> subGenerator =
idGenerator.computeIfAbsent(nameBuilder.toString(), k -> new ConcurrentHashMap<>());
String key = fory.getConfig().getConfigHash() + "_" + CodeGenerator.getClassUniqueId(beanClass);
String key = fory.getConfigHash() + "_" + CodeGenerator.getClassUniqueId(beanClass);
Integer id = subGenerator.get(key);
if (id == null) {
synchronized (subGenerator) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private static CodeGenerator getCodeGenerator(

private static <T> Class<? extends Serializer<T>> loadSerializer(
String name, Class<?> cls, Fory fory, Callable<Class<? extends Serializer<T>>> func) {
int configHash = fory.getConfig().getConfigHash();
int configHash = fory.getConfigHash();
if (GraalvmSupport.IN_GRAALVM_NATIVE_IMAGE) {
Tuple3<String, Class<?>, Integer> key = Tuple3.of(name, cls, configHash);
Class serializerClass = graalvmSerializers.get(key);
Expand Down
16 changes: 0 additions & 16 deletions java/fory-core/src/main/java/org/apache/fory/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@

import java.io.Serializable;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.fory.Fory;
import org.apache.fory.meta.MetaCompressor;
import org.apache.fory.serializer.Serializer;
Expand Down Expand Up @@ -60,7 +57,6 @@ public class Config implements Serializable {
private final boolean asyncCompilationEnabled;
private final boolean deserializeNonexistentClass;
private final boolean scalaOptimizationEnabled;
private transient int configHash;
private final UnknownEnumValueStrategy unknownEnumValueStrategy;
private final boolean serializeEnumByName;
private final int bufferSizeLimitBytes;
Expand Down Expand Up @@ -364,18 +360,6 @@ public int hashCode() {
scalaOptimizationEnabled);
}

private static final AtomicInteger counter = new AtomicInteger(0);
// Different config instance with equality will be hold only one instance, no memory
// leak will happen.
private static final ConcurrentMap<Config, Integer> configIdMap = new ConcurrentHashMap<>();

public int getConfigHash() {
if (configHash == 0) {
configHash = configIdMap.computeIfAbsent(this, k -> counter.incrementAndGet());
}
return configHash;
}

/** Returns max depth for deserialization, when depth exceeds, an exception will be thrown. */
public int maxDepth() {
return maxDepth;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public ClassResolver(Fory fory) {
classInfoCache = NIL_CLASS_INFO;
extRegistry.classIdGenerator = NONEXISTENT_META_SHARED_ID + 1;
shimDispatcher = new ShimDispatcher(fory);
_addGraalvmClassRegistry(fory.getConfig().getConfigHash(), this);
_addGraalvmClassRegistry(fory.getConfigHash(), this);
}

@Override
Expand Down Expand Up @@ -468,7 +468,7 @@ public void register(Class<?> cls, String namespace, String name) {
compositeNameBytes2ClassInfo.put(
new TypeNameBytes(nsBytes.hashCode, nameBytes.hashCode), classInfo);
extRegistry.registeredClasses.put(fullname, cls);
GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
GraalvmSupport.registerClass(cls, fory.getConfigHash());
}

/**
Expand Down Expand Up @@ -547,7 +547,7 @@ private void registerInternalImpl(Class<?> cls, int classId) {
// serializer will be set lazily in `addSerializer` method if it's null.
putInternalTypeInfo(id, classInfo);
extRegistry.registeredClasses.put(cls.getName(), cls);
GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
GraalvmSupport.registerClass(cls, fory.getConfigHash());
}

private void registerUserImpl(Class<?> cls, int userId) {
Expand Down Expand Up @@ -1883,7 +1883,7 @@ public void ensureSerializersCompiled() {
}
classInfoMap.forEach(
(cls, classInfo) -> {
GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
GraalvmSupport.registerClass(cls, fory.getConfigHash());
if (classInfo.serializer == null) {
if (isSerializable(classInfo.cls)) {
createSerializer0(cls);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,7 @@ public static void _addGraalvmClassRegistry(int foryConfigHash, ClassResolver cl
}

final GraalvmSupport.GraalvmClassRegistry getGraalvmClassRegistry() {
return GraalvmSupport.getClassRegistry(fory.getConfig().getConfigHash());
return GraalvmSupport.getClassRegistry(fory.getConfigHash());
}

final Class<? extends Serializer> getGraalvmSerializerClass(Serializer serializer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public void register(Class<?> type, int userTypeId) {
ClassInfo classInfo = classInfoMap.get(type);
if (type.isArray()) {
buildClassInfo(type);
GraalvmSupport.registerClass(type, fory.getConfig().getConfigHash());
GraalvmSupport.registerClass(type, fory.getConfigHash());
return;
}
Serializer<?> serializer = null;
Expand Down Expand Up @@ -256,7 +256,7 @@ private void register(
String qualifiedName = qualifiedName(namespace, typeName);
qualifiedType2ClassInfo.put(qualifiedName, classInfo);
extRegistry.registeredClasses.put(qualifiedName, type);
GraalvmSupport.registerClass(type, fory.getConfig().getConfigHash());
GraalvmSupport.registerClass(type, fory.getConfigHash());
if (serializer == null) {
if (type.isEnum()) {
classInfo.serializer = new EnumSerializer(fory, (Class<Enum>) type);
Expand Down Expand Up @@ -1103,7 +1103,7 @@ private boolean isEnum(int internalTypeId) {
public void ensureSerializersCompiled() {
classInfoMap.forEach(
(cls, classInfo) -> {
GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
GraalvmSupport.registerClass(cls, fory.getConfigHash());
if (classInfo.serializer != null) {
// Trigger serializer initialization and resolution for deferred serializers
if (classInfo.serializer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,52 @@ public void testJava(boolean enableCodegen) {
EmptyWrapper newWrapper = (EmptyWrapper) fory2.deserialize(buffer2);
Assert.assertEquals(newWrapper, new EmptyWrapper());
}

@Test
public void testCodegenCacheIsolation() {
Fory foryA =
Fory.builder()
.withLanguage(Language.XLANG)
.withCompatibleMode(CompatibleMode.COMPATIBLE)
.withCodegen(true)
.build();
foryA.register(Color.class, 101);
foryA.register(MyStruct.class, 102);
foryA.register(MyExt.class, 103);
foryA.registerSerializer(MyExt.class, MyExtSerializer.class);
foryA.register(MyWrapper.class, 104);

MyWrapper wrapperA = new MyWrapper();
wrapperA.color = Color.Red;
wrapperA.my_struct = new MyStruct(10);
wrapperA.my_ext = new MyExt(20);

Fory foryB =
Fory.builder()
.withLanguage(Language.XLANG)
.withCompatibleMode(CompatibleMode.COMPATIBLE)
.withCodegen(true)
.build();
foryB.register(Color.class, 101);
foryB.register(MyStruct.class, 102);
foryB.register(MyExt.class, 103);
// NO MyExtSerializer registered
foryB.register(MyWrapper.class, 104);

MyWrapper wrapperB = new MyWrapper();
wrapperB.color = Color.Blue;
wrapperB.my_struct = new MyStruct(30);
wrapperB.my_ext = new MyExt(40);

try {
byte[] serializedByB = foryB.serialize(wrapperB);
MyWrapper deserializedB = (MyWrapper) foryB.deserialize(serializedByB);

Assert.assertNotNull(deserializedB);
Assert.assertEquals(deserializedB.my_ext.id, 40);

} catch (Exception e) {
Assert.fail("foryB tried to use foryA's codegen. Exception: " + e.getMessage());
}
}
}
Loading