Skip to content

Compact constructor in Java record loses field initialization in ObjC translation #2633

@AliakseiRak

Description

@AliakseiRak

Description:
When using a compact constructor in a Java record, j2ObjC fails to initialize the record fields in the generated Objective-C code.

Steps to reproduce:
1. Create a record in Java:

public record PersonTest(String name, int age, String email) {
    public PersonTest {
        if (age < 0) {
            throw new IllegalArgumentException("Age cannot be negative");
        }
        if (name == null || name.isEmpty()) {
            throw new IllegalArgumentException("Name cannot be empty");
        }
    }
}
  1. Translate it with j2ObjC version 3.1.

Expected behavior:
The generated Objective-C init function should both:
• perform the validation checks, and
• initialize the record fields (self->name_ = name; self->age_ = age; self->email_ = email;).

Actual behavior:
The generated Objective-C init function contains only the validation checks, but does not assign values to fields:

void PersonTest_initPackagePrivateWithNSString_withInt_withNSString_(PersonTest *self, NSString *name, int32_t age, NSString *email) {
  JavaLangRecord_init(self);
  if (age < 0) {
    @throw new_JavaLangIllegalArgumentException_initWithNSString_(@"Age cannot be negative");
  }
  if (name == nil || [name isEmpty]) {
    @throw new_JavaLangIllegalArgumentException_initWithNSString_(@"Name cannot be empty");
  }
  // missing self->name_ = name; self->age_ = age; self->email_ = email;
}

Workarounds:
• Use a canonical constructor instead of a compact constructor.
• Manually assign fields inside the compact constructor (but this duplicates boilerplate).
• Avoid compact constructors in records translated with j2ObjC.

Impact:
This can lead to uninitialized fields in ObjC, causing crashes or incorrect behavior in apps translated from Java records with compact constructors.

Environment:
• j2ObjC version: 3.1

Additional context / suggestion:
It would be ideal if j2ObjC could automatically assign record fields in the generated ObjC init function after performing any validation logic in compact constructors, similar to how canonical constructors are handled.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions