Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
46e0e29
fix: init
mengnankkkk Feb 2, 2026
a610788
fix: remove
mengnankkkk Feb 3, 2026
7fc45b8
fix: add float16
mengnankkkk Feb 3, 2026
65f6ea3
fix: add float16serializer
mengnankkkk Feb 3, 2026
6e37abb
fix: add float16list
mengnankkkk Feb 3, 2026
f5ba942
fix: add native
mengnankkkk Feb 3, 2026
ad18586
Update native-image.properties
mengnankkkk Feb 3, 2026
5cfb49f
fix: add
mengnankkkk Feb 3, 2026
2772ff2
Update native-image.properties
mengnankkkk Feb 3, 2026
f6f38d3
Update native-image.properties
mengnankkkk Feb 3, 2026
578c05e
fix: ci
mengnankkkk Feb 3, 2026
0b98295
Update java/fory-core/src/main/java/org/apache/fory/type/Float16.java
mengnankkkk Feb 4, 2026
004663d
fix: remove something
mengnankkkk Feb 4, 2026
809ced1
Merge branch 'main' into hotfix/add_float16
mengnankkkk Feb 4, 2026
65f2667
fix: remove
mengnankkkk Feb 4, 2026
602aaed
fix: ci
mengnankkkk Feb 4, 2026
18f899c
fix
mengnankkkk Feb 13, 2026
77178dd
fix: fix codereview
mengnankkkk Feb 22, 2026
343a6ce
fix: from cr
mengnankkkk Feb 28, 2026
f5ee398
Merge branch 'main' into hotfix/add_float16
mengnankkkk Feb 28, 2026
b096c9b
Update Float16Serializer.java
mengnankkkk Mar 1, 2026
a692296
fix: ci
mengnankkkk Mar 1, 2026
ec14a50
Update Float16Serializer.java
mengnankkkk Mar 1, 2026
91e5bbd
Merge branch 'main' into hotfix/add_float16
mengnankkkk Mar 5, 2026
831009d
fix
mengnankkkk Mar 8, 2026
c33e97e
fix: ci
mengnankkkk Mar 8, 2026
aadee1b
fix(java): address float16 review issues
chaokunyang Mar 24, 2026
b9251c1
fix(compiler): use Float16List for repeated float16
chaokunyang Mar 24, 2026
e0d04f3
style(java): format ClassResolver for spotless
chaokunyang Mar 24, 2026
cfba1a6
style(compiler): format java generator with ruff
chaokunyang Mar 24, 2026
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
59 changes: 31 additions & 28 deletions compiler/fory_compiler/generators/java.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def generate_bytes_methods(self, class_name: str) -> List[str]:
PrimitiveKind.UINT64: "long",
PrimitiveKind.VAR_UINT64: "long",
PrimitiveKind.TAGGED_UINT64: "long",
PrimitiveKind.FLOAT16: "float",
PrimitiveKind.FLOAT16: "Float16",
PrimitiveKind.FLOAT32: "float",
PrimitiveKind.FLOAT64: "double",
PrimitiveKind.STRING: "String",
Expand Down Expand Up @@ -255,7 +255,7 @@ def generate_bytes_methods(self, class_name: str) -> List[str]:
PrimitiveKind.UINT64: "Long",
PrimitiveKind.VAR_UINT64: "Long",
PrimitiveKind.TAGGED_UINT64: "Long",
PrimitiveKind.FLOAT16: "Float",
PrimitiveKind.FLOAT16: "Float16",
PrimitiveKind.FLOAT32: "Float",
PrimitiveKind.FLOAT64: "Double",
PrimitiveKind.ANY: "Object",
Expand All @@ -278,12 +278,12 @@ def generate_bytes_methods(self, class_name: str) -> List[str]:
PrimitiveKind.UINT64: "long[]",
PrimitiveKind.VAR_UINT64: "long[]",
PrimitiveKind.TAGGED_UINT64: "long[]",
PrimitiveKind.FLOAT16: "float[]",
PrimitiveKind.FLOAT16: "Float16[]",
PrimitiveKind.FLOAT32: "float[]",
PrimitiveKind.FLOAT64: "double[]",
}

# Primitive list types for repeated integer fields (default mode)
# Primitive list types for repeated fields when Java should use compact specialized storage.
PRIMITIVE_LIST_MAP = {
PrimitiveKind.INT8: "Int8List",
PrimitiveKind.INT16: "Int16List",
Expand All @@ -299,6 +299,7 @@ def generate_bytes_methods(self, class_name: str) -> List[str]:
PrimitiveKind.UINT64: "Uint64List",
PrimitiveKind.VAR_UINT64: "Uint64List",
PrimitiveKind.TAGGED_UINT64: "Uint64List",
PrimitiveKind.FLOAT16: "Float16List",
}

def generate(self) -> List[GeneratedFile]:
Expand Down Expand Up @@ -1139,19 +1140,16 @@ def generate_type(
return field_type.name

elif isinstance(field_type, ListType):
# Use primitive arrays for numeric types, or primitive lists by default for integers
# Use specialized primitive lists when available, otherwise primitive arrays.
if isinstance(field_type.element_type, PrimitiveType):
if (
field_type.element_type.kind in self.PRIMITIVE_ARRAY_MAP
and not element_optional
and not element_ref
):
if (
field_type.element_type.kind in self.PRIMITIVE_LIST_MAP
and not self.java_array(field)
):
return self.PRIMITIVE_LIST_MAP[field_type.element_type.kind]
return self.PRIMITIVE_ARRAY_MAP[field_type.element_type.kind]
kind = field_type.element_type.kind
if not element_optional and not element_ref:
if kind == PrimitiveKind.FLOAT16:
return self.PRIMITIVE_LIST_MAP[kind]
if kind in self.PRIMITIVE_LIST_MAP and not self.java_array(field):
return self.PRIMITIVE_LIST_MAP[kind]
if kind in self.PRIMITIVE_ARRAY_MAP:
return self.PRIMITIVE_ARRAY_MAP[kind]
element_type = self.generate_type(field_type.element_type, True)
if self.is_ref_target_type(field_type.element_type):
ref_annotation = "@Ref" if element_ref else "@Ref(enable=false)"
Expand Down Expand Up @@ -1184,24 +1182,29 @@ def collect_type_imports(
imports.add("java.time.LocalDate")
elif field_type.kind == PrimitiveKind.TIMESTAMP:
imports.add("java.time.Instant")
elif field_type.kind == PrimitiveKind.FLOAT16:
imports.add("org.apache.fory.type.Float16")

elif isinstance(field_type, ListType):
# Primitive arrays don't need List import
# Specialized primitive lists/arrays don't need java.util.List imports.
if isinstance(field_type.element_type, PrimitiveType):
if (
field_type.element_type.kind in self.PRIMITIVE_ARRAY_MAP
and not element_optional
and not element_ref
):
if (
field_type.element_type.kind in self.PRIMITIVE_LIST_MAP
and not self.java_array(field)
):
kind = field_type.element_type.kind
if not element_optional and not element_ref:
if kind == PrimitiveKind.FLOAT16:
imports.add(
"org.apache.fory.collection."
+ self.PRIMITIVE_LIST_MAP[kind]
)
return
if kind in self.PRIMITIVE_LIST_MAP and not self.java_array(field):
imports.add(
"org.apache.fory.collection."
+ self.PRIMITIVE_LIST_MAP[field_type.element_type.kind]
+ self.PRIMITIVE_LIST_MAP[kind]
)
return # No import needed for primitive arrays or primitive lists
return
if kind in self.PRIMITIVE_ARRAY_MAP:
self.collect_type_imports(field_type.element_type, imports)
return
imports.add("java.util.List")
if self.is_ref_target_type(field_type.element_type):
imports.add("org.apache.fory.annotation.Ref")
Expand Down
36 changes: 36 additions & 0 deletions compiler/fory_compiler/tests/test_generated_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,42 @@ def test_generated_code_tree_ref_options_equivalent():
assert "SharedWeak<TreeNode>" in cpp_output


def test_java_float16_equals_hash_contract_generation():
schema = parse_fdl(
dedent(
"""
package gen;

message Float16Contract {
float16 f16 = 1;
optional float16 opt_f16 = 2;
}
"""
)
)
java_output = render_files(generate_files(schema, JavaGenerator))
assert "Objects.equals(f16, that.f16)" in java_output
assert "Objects.equals(optF16, that.optF16)" in java_output
assert "return Objects.hash(f16, optF16);" in java_output


def test_java_repeated_float16_generation_uses_float16_list():
schema = parse_fdl(
dedent(
"""
package gen;

message RepeatedFloat16 {
list<float16> vals = 1;
}
"""
)
)
java_output = render_files(generate_files(schema, JavaGenerator))
assert "import org.apache.fory.collection.Float16List;" in java_output
assert "private Float16List vals;" in java_output


def test_go_bfloat16_generation():
idl = dedent(
"""
Expand Down
4 changes: 2 additions & 2 deletions docs/specification/xlang_type_mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ When reading type IDs:
| var_uint64 | 14 | long/Long | int/pyfory.uint64 | Type.varUInt64() | uint64_t | uint64 | u64 |
| tagged_uint64 | 15 | long/Long | int/pyfory.tagged_uint64 | Type.taggedUInt64() | uint64_t | uint64 | u64 |
| float8 | 16 | / | / | / | / | / | / |
| float16 | 17 | float/Float | float/pyfory.float16 | Type.float16() | fory::float16_t | fory.float16 | fory::f16 |
| float16 | 17 | Float16 | float/pyfory.float16 | Type.float16() | fory::float16_t | fory.float16 | fory::f16 |
| bfloat16 | 18 | / | / | / | / | / | / |
| float32 | 19 | float/Float | float/pyfory.float32 | Type.float32() | float | float32 | f32 |
| float64 | 20 | double/Double | float/pyfory.float64 | Type.float64() | double | float64 | f64 |
Expand Down Expand Up @@ -100,7 +100,7 @@ When reading type IDs:
| uint32_array | 50 | long[] | ndarray(uint32) | / | `uint32_t[n]/vector<T>` | `[n]uint32/[]T` | `Vec<u32>` |
| uint64_array | 51 | long[] | ndarray(uint64) | / | `uint64_t[n]/vector<T>` | `[n]uint64/[]T` | `Vec<u64>` |
| float8_array | 52 | / | / | / | / | / | / |
| float16_array | 53 | float[] | ndarray(float16) | / | `fory::float16_t[n]/vector<T>` | `[n]float16/[]T` | `Vec<fory::f16>` |
| float16_array | 53 | Float16List | ndarray(float16) | / | `fory::float16_t[n]/vector<T>` | `[n]float16/[]T` | `Vec<fory::f16>` |
| bfloat16_array | 54 | / | / | / | / | / | / |
| float32_array | 55 | float[] | ndarray(float32) | / | `float[n]/vector<T>` | `[n]float32/[]T` | `Vec<f32>` |
| float64_array | 56 | double[] | ndarray(float64) | / | `double[n]/vector<T>` | `[n]float64/[]T` | `Vec<f64>` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
import org.apache.fory.codegen.Expression.Literal;
import org.apache.fory.codegen.Expression.Reference;
import org.apache.fory.codegen.Expression.Return;
import org.apache.fory.codegen.Expression.StaticInvoke;
import org.apache.fory.codegen.Expression.Variable;
import org.apache.fory.codegen.Expression.While;
import org.apache.fory.codegen.ExpressionUtils;
Expand Down Expand Up @@ -137,6 +138,7 @@
import org.apache.fory.serializer.collection.MapLikeSerializer;
import org.apache.fory.type.Descriptor;
import org.apache.fory.type.DispatchId;
import org.apache.fory.type.Float16;
import org.apache.fory.type.GenericType;
import org.apache.fory.type.TypeUtils;
import org.apache.fory.type.Types;
Expand Down Expand Up @@ -451,7 +453,7 @@ private Expression serializeForNotNullForField(
Expression inputObject, Expression buffer, Descriptor descriptor, Expression serializer) {
TypeRef<?> typeRef = descriptor.getTypeRef();
Class<?> clz = getRawType(typeRef);
if (isPrimitive(clz) || isBoxed(clz)) {
if (isPrimitiveLikeDescriptor(descriptor, clz)) {
return serializePrimitiveField(inputObject, buffer, descriptor);
} else {
if (clz == String.class) {
Expand Down Expand Up @@ -505,6 +507,8 @@ private Expression serializePrimitiveField(
return new Invoke(buffer, "writeFloat32", inputObject);
case DispatchId.FLOAT64:
return new Invoke(buffer, "writeFloat64", inputObject);
case DispatchId.FLOAT16:
return new Invoke(buffer, "writeInt16", new Invoke(inputObject, "toBits", SHORT_TYPE));
default:
throw new IllegalStateException("Unsupported dispatchId: " + dispatchId);
}
Expand Down Expand Up @@ -662,9 +666,19 @@ protected boolean useMapSerialization(Class<?> type) {
}

protected int getNumericDescriptorDispatchId(Descriptor descriptor) {
int dispatchId =
descriptorDispatchId.computeIfAbsent(descriptor, d -> DispatchId.getDispatchId(fory, d));
Class<?> rawType = descriptor.getRawType();
Preconditions.checkArgument(TypeUtils.unwrap(rawType).isPrimitive());
return descriptorDispatchId.computeIfAbsent(descriptor, d -> DispatchId.getDispatchId(fory, d));
Preconditions.checkArgument(
TypeUtils.unwrap(rawType).isPrimitive() || dispatchId == DispatchId.FLOAT16);
return dispatchId;
}

private boolean isPrimitiveLikeDescriptor(Descriptor descriptor, Class<?> rawType) {
if (isPrimitive(rawType) || isBoxed(rawType)) {
return true;
}
return rawType == Float16.class;
}

/**
Expand Down Expand Up @@ -1989,7 +2003,7 @@ private Expression deserializeForNotNullForField(
Expression buffer, Descriptor descriptor, Expression serializer) {
TypeRef<?> typeRef = descriptor.getTypeRef();
Class<?> cls = getRawType(typeRef);
if (isPrimitive(cls) || isBoxed(cls)) {
if (isPrimitiveLikeDescriptor(descriptor, cls)) {
return deserializePrimitiveField(buffer, descriptor);
} else {
if (cls == String.class) {
Expand Down Expand Up @@ -2062,6 +2076,9 @@ private Expression deserializePrimitiveField(Expression buffer, Descriptor descr
return isPrimitive
? readFloat64(buffer)
: new Invoke(buffer, readFloat64Func(), DOUBLE_TYPE);
case DispatchId.FLOAT16:
return new StaticInvoke(
Float16.class, "fromBits", TypeRef.of(Float16.class), readInt16(buffer));
default:
throw new IllegalStateException("Unsupported dispatchId: " + dispatchId);
}
Expand Down
Loading
Loading