@@ -33,6 +33,7 @@ type FieldInfo struct {
3333 Index int // Original field index in struct
3434 IsPrimitive bool // Whether it's a Fory primitive type
3535 IsPointer bool // Whether it's a pointer type
36+ Nullable bool // Whether the field can be null (pointer types)
3637 TypeID string // Fory TypeID for sorting
3738 PrimitiveSize int // Size for primitive type sorting
3839}
@@ -138,8 +139,33 @@ func getTypeID(t types.Type) string {
138139 t = ptr .Elem ()
139140 }
140141
141- // Check slice types
142- if _ , ok := t .(* types.Slice ); ok {
142+ // Check slice types - distinguish primitive arrays from generic lists
143+ if slice , ok := t .(* types.Slice ); ok {
144+ elemType := slice .Elem ()
145+ // For pointer to primitive, unwrap the pointer
146+ if ptr , ok := elemType .(* types.Pointer ); ok {
147+ elemType = ptr .Elem ()
148+ }
149+ // Check if element is a primitive type (primitive arrays use specific typeIDs)
150+ if basic , ok := elemType .Underlying ().(* types.Basic ); ok {
151+ switch basic .Kind () {
152+ case types .Bool :
153+ return "BOOL_ARRAY"
154+ case types .Int8 :
155+ return "INT8_ARRAY"
156+ case types .Int16 :
157+ return "INT16_ARRAY"
158+ case types .Int32 :
159+ return "INT32_ARRAY"
160+ case types .Int , types .Int64 :
161+ return "INT64_ARRAY"
162+ case types .Float32 :
163+ return "FLOAT32_ARRAY"
164+ case types .Float64 :
165+ return "FLOAT64_ARRAY"
166+ }
167+ }
168+ // Non-primitive slices use LIST
143169 return "LIST"
144170 }
145171
@@ -263,17 +289,36 @@ func getTypeIDValue(typeID string) int {
263289 case "FLOAT64" :
264290 return int (fory .FLOAT64 )
265291 case "STRING" :
266- return int (fory .STRING ) // 12
292+ return int (fory .STRING ) // 9
293+ case "BINARY" :
294+ return int (fory .BINARY ) // 10
295+ case "LIST" :
296+ return int (fory .LIST ) // 20
297+ case "SET" :
298+ return int (fory .SET ) // 21
299+ case "MAP" :
300+ return int (fory .MAP ) // 22
267301 case "TIMESTAMP" :
268302 return int (fory .TIMESTAMP ) // 25
269303 case "LOCAL_DATE" :
270304 return int (fory .LOCAL_DATE ) // 26
271305 case "NAMED_STRUCT" :
272306 return int (fory .NAMED_STRUCT ) // 17
273- case "LIST" :
274- return int (fory .LIST ) // 21
275- case "MAP" :
276- return int (fory .MAP ) // 23
307+ // Primitive array types
308+ case "BOOL_ARRAY" :
309+ return int (fory .BOOL_ARRAY ) // 39
310+ case "INT8_ARRAY" :
311+ return int (fory .INT8_ARRAY ) // 40
312+ case "INT16_ARRAY" :
313+ return int (fory .INT16_ARRAY ) // 41
314+ case "INT32_ARRAY" :
315+ return int (fory .INT32_ARRAY ) // 42
316+ case "INT64_ARRAY" :
317+ return int (fory .INT64_ARRAY ) // 43
318+ case "FLOAT32_ARRAY" :
319+ return int (fory .FLOAT32_ARRAY ) // 49
320+ case "FLOAT64_ARRAY" :
321+ return int (fory .FLOAT64_ARRAY ) // 50
277322 default :
278323 return 999 // Unknown types sort last
279324 }
@@ -329,14 +374,15 @@ func sortFields(fields []*FieldInfo) {
329374 return f1 .SnakeName < f2 .SnakeName
330375
331376 case groupOtherInternalType :
332- // Other internal type fields: sort by type id then snake case field name
377+ // Internal type fields (STRING, BINARY, LIST, SET, MAP): sort by type id then name only.
378+ // Java does NOT sort by nullable flag for these types.
333379 if f1 .TypeID != f2 .TypeID {
334380 return getTypeIDValue (f1 .TypeID ) < getTypeIDValue (f2 .TypeID )
335381 }
336382 return f1 .SnakeName < f2 .SnakeName
337383
338- case groupList , groupSet , groupMap , groupOther :
339- // List/Set/Map/Other fields: sort by snake case field name only
384+ case groupPrimitiveArray , groupOther :
385+ // Primitive arrays and other fields: sort by snake case field name only
340386 return f1 .SnakeName < f2 .SnakeName
341387
342388 default :
@@ -347,13 +393,13 @@ func sortFields(fields []*FieldInfo) {
347393}
348394
349395// Field group constants for sorting
396+ // This matches reflection's field ordering in field_info.go:
397+ // primitives → boxed → otherInternalType (STRING/BINARY/LIST/SET/MAP) → primitiveArray → other
350398const (
351399 groupPrimitive = 0 // primitive and nullable primitive fields
352- groupOtherInternalType = 1 // other internal type fields (string, timestamp, etc.)
353- groupList = 2 // list fields
354- groupSet = 3 // set fields
355- groupMap = 4 // map fields
356- groupOther = 5 // other fields
400+ groupOtherInternalType = 1 // STRING, BINARY, LIST, SET, MAP (sorted by typeId, name)
401+ groupPrimitiveArray = 2 // primitive arrays (BOOL_ARRAY, INT32_ARRAY, etc.) - sorted by name
402+ groupOther = 3 // structs, enums, and unknown types - sorted by name
357403)
358404
359405// getFieldGroup categorizes a field into its sorting group
@@ -366,38 +412,29 @@ func getFieldGroup(field *FieldInfo) int {
366412 return groupPrimitive
367413 }
368414
369- // List fields
370- if typeID == "LIST" {
371- return groupList
372- }
373-
374- // Set fields
375- if typeID == "SET" {
376- return groupSet
415+ // Primitive array fields - sorted by name only
416+ primitiveArrayTypes := map [string ]bool {
417+ "BOOL_ARRAY" : true ,
418+ "INT8_ARRAY" : true ,
419+ "INT16_ARRAY" : true ,
420+ "INT32_ARRAY" : true ,
421+ "INT64_ARRAY" : true ,
422+ "FLOAT32_ARRAY" : true ,
423+ "FLOAT64_ARRAY" : true ,
377424 }
378-
379- // Map fields
380- if typeID == "MAP" {
381- return groupMap
425+ if primitiveArrayTypes [typeID ] {
426+ return groupPrimitiveArray
382427 }
383428
384- // Other internal type fields
385- // These are fory internal types that are not primitives/lists/sets/maps
386- // Examples: STRING, TIMESTAMP, LOCAL_DATE, NAMED_STRUCT, etc.
429+ // Internal types (STRING, BINARY, LIST, SET, MAP) - sorted by typeId, nullable, name
430+ // These match reflection's category 1 in getFieldCategory
387431 internalTypes := map [string ]bool {
388- "STRING" : true ,
389- "TIMESTAMP" : true ,
390- "LOCAL_DATE" : true ,
391- "NAMED_STRUCT" : true ,
392- "STRUCT" : true ,
393- "BINARY" : true ,
394- "ENUM" : true ,
395- "NAMED_ENUM" : true ,
396- "EXT" : true ,
397- "NAMED_EXT" : true ,
398- "INTERFACE" : true , // for interface{} types
432+ "STRING" : true ,
433+ "BINARY" : true ,
434+ "LIST" : true ,
435+ "SET" : true ,
436+ "MAP" : true ,
399437 }
400-
401438 if internalTypes [typeID ] {
402439 return groupOtherInternalType
403440 }
@@ -448,6 +485,7 @@ func analyzeField(field *types.Var, index int) (*FieldInfo, error) {
448485 Index : index ,
449486 IsPrimitive : isPrimitive ,
450487 IsPointer : isPointer ,
488+ Nullable : isPointer , // Pointer types are nullable, slices/maps are non-nullable in xlang mode
451489 TypeID : typeID ,
452490 PrimitiveSize : primitiveSize ,
453491 }, nil
0 commit comments