Randgalt / record-builder

Record builder generator for Java records
Apache License 2.0
723 stars 51 forks source link

Deconstructors/Tuple generator #175

Open Randgalt opened 5 months ago

Randgalt commented 5 months ago

This is a speculative PR. Open for discussion.

This is a variation of @RecordInterface that generates a general purpose tuple from any class. The impetus for this is to take advantage of Java 21's record patterns with non-record objects. In the future, Java will generally support deconstructors, but it doesn't today. Only real records are supported for record patterns. With the addition here of @RecordDeconstructor and object can be use for record pattern matching.

Example:

Given a legacy or non-record class like this:

public class BasicDeconstruct {
    private final String name;
    private final int qty;

    public BasicDeconstruct(String name, int qty) {
        this.name = name;
        this.qty = qty;
    }

    public String getName() {
        return name;
    }

    public int getQty() {
        return qty;
    }
}

We can now create a tuple-like record from this class by adding annotations:

@RecordDeconstructor
public class BasicDeconstruct {
    private final String name;
    private final int qty;

    public BasicDeconstruct(String name, int qty) {
        this.name = name;
        this.qty = qty;
    }

    @RecordDeconstructor.Component
    public String getName() {
        return name;
    }

    @RecordDeconstructor.Component
    public int getQty() {
        return qty;
    }
}

This generates the following record:

public record BasicDeconstructTuple(String name, int qty) {
    public static BasicDeconstructTuple from(BasicDeconstruct from) {
        return new BasicDeconstructTuple(from.getName(), from.getQty());
    }
}

Which can be used for pattern matching:

public void foo(BasicDeconstruct instance) {
    switch (BasicDeconstructTuple.from(instance)) {
        case BasicDeconstructTuple(var name, var qty) when name.equals("something") -> ....
    }
}
koppor commented 2 months ago

Can I also put the annotation "externally" to an existing class? I think, this is useful when using an external library, where the source should not be modified. -- If I can modify the source, I could use IntelliJ's refactoring "convert to record". OK, that would introduce API incompatibility. Then, the presented approach is good. However, I currently think, for self-maintained code this approach feels to require too much maintenance effort in comparison to the gain. 😅