Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(java): Streamline ClassResolver responsibilities #1417

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 19 additions & 18 deletions java/fury-core/src/main/java/org/apache/fury/Fury.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.apache.fury.config.LongEncoding;
import org.apache.fury.memory.MemoryBuffer;
import org.apache.fury.memory.MemoryUtils;
import org.apache.fury.resolver.ClassIdAllocator.BuiltinClassId;
import org.apache.fury.resolver.ClassInfo;
import org.apache.fury.resolver.ClassInfoHolder;
import org.apache.fury.resolver.ClassResolver;
Expand Down Expand Up @@ -514,35 +515,35 @@ public <T> void xwriteNonRef(MemoryBuffer buffer, T obj, Serializer<T> serialize
/** Write not null data to buffer. */
private void writeData(MemoryBuffer buffer, ClassInfo classInfo, Object obj) {
switch (classInfo.getClassId()) {
case ClassResolver.BOOLEAN_CLASS_ID:
case BuiltinClassId.BOOLEAN_CLASS_ID:
buffer.writeBoolean((Boolean) obj);
break;
case ClassResolver.BYTE_CLASS_ID:
case BuiltinClassId.BYTE_CLASS_ID:
buffer.writeByte((Byte) obj);
break;
case ClassResolver.CHAR_CLASS_ID:
case BuiltinClassId.CHAR_CLASS_ID:
buffer.writeChar((Character) obj);
break;
case ClassResolver.SHORT_CLASS_ID:
case BuiltinClassId.SHORT_CLASS_ID:
buffer.writeShort((Short) obj);
break;
case ClassResolver.INTEGER_CLASS_ID:
case BuiltinClassId.INTEGER_CLASS_ID:
if (compressInt) {
buffer.writeVarInt((Integer) obj);
} else {
buffer.writeInt((Integer) obj);
}
break;
case ClassResolver.FLOAT_CLASS_ID:
case BuiltinClassId.FLOAT_CLASS_ID:
buffer.writeFloat((Float) obj);
break;
case ClassResolver.LONG_CLASS_ID:
case BuiltinClassId.LONG_CLASS_ID:
LongSerializer.writeLong(buffer, (Long) obj, longEncoding);
break;
case ClassResolver.DOUBLE_CLASS_ID:
case BuiltinClassId.DOUBLE_CLASS_ID:
buffer.writeDouble((Double) obj);
break;
case ClassResolver.STRING_CLASS_ID:
case BuiltinClassId.STRING_CLASS_ID:
stringSerializer.writeJavaString(buffer, (String) obj);
break;
// TODO(add fastpath for other types)
Expand Down Expand Up @@ -870,27 +871,27 @@ public Object readData(MemoryBuffer buffer, ClassInfo classInfo) {

private Object readDataInternal(MemoryBuffer buffer, ClassInfo classInfo) {
switch (classInfo.getClassId()) {
case ClassResolver.BOOLEAN_CLASS_ID:
case BuiltinClassId.BOOLEAN_CLASS_ID:
return buffer.readBoolean();
case ClassResolver.BYTE_CLASS_ID:
case BuiltinClassId.BYTE_CLASS_ID:
return buffer.readByte();
case ClassResolver.CHAR_CLASS_ID:
case BuiltinClassId.CHAR_CLASS_ID:
return buffer.readChar();
case ClassResolver.SHORT_CLASS_ID:
case BuiltinClassId.SHORT_CLASS_ID:
return buffer.readShort();
case ClassResolver.INTEGER_CLASS_ID:
case BuiltinClassId.INTEGER_CLASS_ID:
if (compressInt) {
return buffer.readVarInt();
} else {
return buffer.readInt();
}
case ClassResolver.FLOAT_CLASS_ID:
case BuiltinClassId.FLOAT_CLASS_ID:
return buffer.readFloat();
case ClassResolver.LONG_CLASS_ID:
case BuiltinClassId.LONG_CLASS_ID:
return LongSerializer.readLong(buffer, longEncoding);
case ClassResolver.DOUBLE_CLASS_ID:
case BuiltinClassId.DOUBLE_CLASS_ID:
return buffer.readDouble();
case ClassResolver.STRING_CLASS_ID:
case BuiltinClassId.STRING_CLASS_ID:
return stringSerializer.readJavaString(buffer);
// TODO(add fastpath for other types)
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@
import org.apache.fury.codegen.ExpressionOptimizer;
import org.apache.fury.codegen.ExpressionUtils;
import org.apache.fury.collection.Tuple2;
import org.apache.fury.resolver.ClassIdAllocator.BuiltinClassId;
import org.apache.fury.resolver.ClassInfo;
import org.apache.fury.resolver.ClassResolver;
import org.apache.fury.resolver.FieldResolver;
import org.apache.fury.resolver.FieldResolver.CollectionFieldInfo;
import org.apache.fury.resolver.FieldResolver.FieldInfo;
Expand Down Expand Up @@ -879,7 +879,7 @@ protected Expression getFinalClassInfo(Class<?> cls) {
protected Expression writeFinalClassInfo(Expression buffer, Class<?> cls) {
Preconditions.checkArgument(ReflectionUtils.isMonomorphic(cls));
ClassInfo classInfo = visitFury(f -> f.getClassResolver().getClassInfo(cls, false));
if (classInfo != null && classInfo.getClassId() != ClassResolver.NO_CLASS_ID) {
if (classInfo != null && classInfo.getClassId() != BuiltinClassId.NO_CLASS_ID) {
return fury.getClassResolver().writeClassExpr(buffer, classInfo.getClassId());
}
Expression classInfoExpr = getFinalClassInfo(cls);
Expand All @@ -889,7 +889,7 @@ protected Expression writeFinalClassInfo(Expression buffer, Class<?> cls) {
protected Expression skipFinalClassInfo(Class<?> cls, Expression buffer) {
Preconditions.checkArgument(ReflectionUtils.isMonomorphic(cls));
ClassInfo classInfo = visitFury(f -> f.getClassResolver().getClassInfo(cls, false));
if (classInfo != null && classInfo.getClassId() != ClassResolver.NO_CLASS_ID) {
if (classInfo != null && classInfo.getClassId() != BuiltinClassId.NO_CLASS_ID) {
return fury.getClassResolver().skipRegisteredClassExpr(buffer);
}
// read `ClassInfo` is not used, set `inlineReadClassInfo` false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fury.resolver;

import java.util.function.Function;
import org.apache.fury.util.Preconditions;

/** Responsible for allocating ClassId and maintaining built-in ClassId. */
public class ClassIdAllocator {
public static class BuiltinClassId {
// preserve 0 as flag for class id not set in ClassInfo`
public static final short NO_CLASS_ID = (short) 0;
public static final short LAMBDA_STUB_ID = 1;
public static final short JDK_PROXY_STUB_ID = 2;
public static final short REPLACE_STUB_ID = 3;
// Note: following pre-defined class id should be continuous, since they may be used based
// range.
public static final short PRIMITIVE_VOID_CLASS_ID = (short) (REPLACE_STUB_ID + 1);
public static final short PRIMITIVE_BOOLEAN_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 1);
public static final short PRIMITIVE_BYTE_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 2);
public static final short PRIMITIVE_CHAR_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 3);
public static final short PRIMITIVE_SHORT_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 4);
public static final short PRIMITIVE_INT_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 5);
public static final short PRIMITIVE_FLOAT_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 6);
public static final short PRIMITIVE_LONG_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 7);
public static final short PRIMITIVE_DOUBLE_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 8);
public static final short VOID_CLASS_ID = (short) (PRIMITIVE_DOUBLE_CLASS_ID + 1);
public static final short BOOLEAN_CLASS_ID = (short) (VOID_CLASS_ID + 1);
public static final short BYTE_CLASS_ID = (short) (VOID_CLASS_ID + 2);
public static final short CHAR_CLASS_ID = (short) (VOID_CLASS_ID + 3);
public static final short SHORT_CLASS_ID = (short) (VOID_CLASS_ID + 4);
public static final short INTEGER_CLASS_ID = (short) (VOID_CLASS_ID + 5);
public static final short FLOAT_CLASS_ID = (short) (VOID_CLASS_ID + 6);
public static final short LONG_CLASS_ID = (short) (VOID_CLASS_ID + 7);
public static final short DOUBLE_CLASS_ID = (short) (VOID_CLASS_ID + 8);
public static final short STRING_CLASS_ID = (short) (VOID_CLASS_ID + 9);
public static final short PRIMITIVE_BOOLEAN_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 1);
public static final short PRIMITIVE_BYTE_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 2);
public static final short PRIMITIVE_CHAR_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 3);
public static final short PRIMITIVE_SHORT_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 4);
public static final short PRIMITIVE_INT_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 5);
public static final short PRIMITIVE_FLOAT_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 6);
public static final short PRIMITIVE_LONG_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 7);
public static final short PRIMITIVE_DOUBLE_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 8);
public static final short STRING_ARRAY_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 1);
public static final short OBJECT_ARRAY_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 2);
public static final short ARRAYLIST_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 3);
public static final short HASHMAP_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 4);
public static final short HASHSET_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 5);
public static final short CLASS_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 6);
public static final short EMPTY_OBJECT_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 7);
}

// class id of last default registered class.
private short innerEndClassId;
// Here we set it to 1 because `NO_CLASS_ID` is 0 to avoid calculating it again in
// `register(Class<?> cls)`.
private short classIdGenerator = 1;

private final Function<Class<?>, Boolean> classRegisteredFactory;

private final Function<Short, Boolean> classIdRegisteredFactory;

public ClassIdAllocator(
Function<Class<?>, Boolean> classRegisteredFactory,
Function<Short, Boolean> classIdRegisteredFactory) {
Preconditions.checkNotNull(classRegisteredFactory);
Preconditions.checkNotNull(classIdRegisteredFactory);
this.classRegisteredFactory = classRegisteredFactory;
this.classIdRegisteredFactory = classIdRegisteredFactory;
}

public short allocateClassId(Class<?> cls) {
if (!classRegisteredFactory.apply(cls)) {
while (classIdRegisteredFactory.apply(classIdGenerator)) {
classIdGenerator++;
}
}
return classIdGenerator;
}

public void notifyRegistrationEnd() {
classIdGenerator++;
}

public void markInternalRegistrationEnd() {
innerEndClassId = classIdGenerator;
}

public boolean isInnerClass(Short classId) {
return classId != null && classId != BuiltinClassId.NO_CLASS_ID && classId < innerEndClassId;
}

public boolean isPrimitive(short classId) {
return classId >= BuiltinClassId.PRIMITIVE_VOID_CLASS_ID
&& classId <= BuiltinClassId.PRIMITIVE_DOUBLE_CLASS_ID;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public class ClassInfo {
this.typeTagBytes = typeTagBytes;
this.serializer = serializer;
this.classId = classId;
if (cls != null && classId == ClassResolver.NO_CLASS_ID) {
if (cls != null && classId == ClassIdAllocator.BuiltinClassId.NO_CLASS_ID) {
Preconditions.checkArgument(classNameBytes != null);
}
}
Expand All @@ -78,7 +78,8 @@ public class ClassInfo {
this.fullClassNameBytes = null;
}
if (cls != null
&& (classId == ClassResolver.NO_CLASS_ID || classId == ClassResolver.REPLACE_STUB_ID)) {
&& (classId == ClassIdAllocator.BuiltinClassId.NO_CLASS_ID
|| classId == ClassIdAllocator.BuiltinClassId.REPLACE_STUB_ID)) {
// REPLACE_STUB_ID for write replace class in `ClassSerializer`.
String packageName = ReflectionUtils.getPackage(cls);
this.packageNameBytes = enumStringResolver.getOrCreateEnumStringBytes(packageName);
Expand All @@ -100,10 +101,10 @@ public class ClassInfo {
boolean isProxy = ReflectionUtils.isJdkProxy(cls);
this.isDynamicGeneratedClass = isLambda || isProxy;
if (isLambda) {
this.classId = ClassResolver.LAMBDA_STUB_ID;
this.classId = ClassIdAllocator.BuiltinClassId.LAMBDA_STUB_ID;
}
if (isProxy) {
this.classId = ClassResolver.JDK_PROXY_STUB_ID;
this.classId = ClassIdAllocator.BuiltinClassId.JDK_PROXY_STUB_ID;
}
} else {
this.isDynamicGeneratedClass = false;
Expand Down