projectlombok / lombok

Very spicy additions to the Java programming language.
https://projectlombok.org/
Other
12.84k stars 2.38k forks source link

[FEATURE] Default Value Support in Lombok #3664

Open lyf2nb opened 4 months ago

lyf2nb commented 4 months ago

Feature Request: Default Value Support in Lombok

Describe the feature A clear and concise description of the feature request is to add support for setting default values in Lombok-generated getters. The goal of this feature request is to allow developers to specify default values for fields, ensuring that getters return these default values when the field is null.

Java Snippets:

import lombok.Getter;

public class MyClass {
    @Getter(defaultValue = BigDecimal.ZERO)
    private BigDecimal value; // Desired feature: Ability to specify default value, e.g., default = BigDecimal.ZERO
}
public class MyClass {
    private BigDecimal value;

    public BigDecimal getValue() {
        return value== null ? BigDecimal.ZERO : value;
    }
}

Describe the target audience This feature proposal would benefit developers who use Lombok to reduce boilerplate code in their Java projects. It would particularly help those who need to ensure that getters return default values when the field is null.

Additional context Adding support for default values in Lombok-generated getters would enhance the flexibility and convenience of using Lombok annotations, making it easier for developers to handle default values without manually writing getter methods. This feature would streamline the development process and improve code readability in projects utilizing Lombok.

Can I Implement This Feature Myself? Certainly, you can implement this feature yourself by creating custom getter methods in your classes to handle default values. This approach provides flexibility in setting default values based on your specific needs and allows you to tailor the implementation to suit your requirements.

sixcorners commented 4 months ago

Why not use a field initializer?

lyf2nb commented 4 months ago

Why not use a field initializer?

Because you can set it to null, and if you query the database, it will return null

EvertJanDeBruin commented 3 months ago

I have looked a bit into this because I can imagine the added value of such a getter. The example given, however, is not valid Java code:

@Getter(defaultValue = BigDecimal.ZERO)

This is because the arguments for an annotation cannot be just any Java Object (like BigDecimal.ZERO), but only a primitive, String, Class, enum or array. See also the Java specifications for annotations.

1st alternative

One route would be for the defaultValue to be some kind of enum listing default value types, for example:

@Getter(defaultValue = DefaultValues.BIGDECIMAL_ZERO)

Obviously this is not the prettiest of solutions, but I was able to make this work in a quick-and-dirty proof-of-concept version. The enum would have to contain a lot of default values for different types of classes (BigDecimal, BigInteger, etc). Major setback is that it would only work for a limited amount of values in a limited amount of classes, basically only zero in standard Java classes.

2nd alternative

Another alternative is to provide a tiny Class that implements an interface to provide the default value. This is basically a workaround for the fact that the interface parameters cannot refer to objects, but can refer to classes.

import lombok.Getter;
import lombok.GetterDefaultValue;

class BigDecimalDefaultZero implements GetterDefaultValue {
    @Override
    public BigDecimal getDefaultValue() {
        return BigDecimal.ZERO;        
    }
}

public class MyClass {
    @Getter(defaultValueClass = BigDecimalDefaultZero.class)
    private BigDecimal value;
}

The de-lombok-ed class would end up looking something like this:

class BigDecimalDefaultZero implements GetterDefaultValue {
    @Override
    public BigDecimal getDefaultValue() {
        return BigDecimal.ZERO;        
    }
}

class MyClass {
    private BigDecimal value;
    private static BigDecimal DEFAULTVALUE_value = (new BigDecimalDefault()).getDefaultValue();

    public BigDecimal getValue() {
        return value == null ? DEFAULTVALUE_value : value;
    }
}

Does this route seem acceptable, or too much work for a relatively simple default value in a getter?

lyf2nb commented 3 months ago

我对此进行了一些研究,因为我可以想象这种getter的附加值。但是,给出示例不是有效的Java代码:

@Getter(defaultValue = BigDecimal.ZERO)

这是因为注释的参数不能只是任何 Java 对象(如 BigDecimal.ZERO),而只能是原始类型、字符串、类、或数组。另请参阅注释的 Java 规范

第一种选择

方法是将默认值设置为网址默认值,例如:

@Getter(defaultValue = DefaultValues.BIGDECIMAL_ZERO)

显然这不是一个完美的解决方案,但我能够快速而简单地在验证版本中的概念时实现这一点。枚举必须包含大量类似的类(BigDecimal、BigInteger 等)的默认值。最大的缺点是它只能在有限大小的类中对有限大小的服务,在标准 Java 类中基本上只有零个。

更好的选择

另一种选择是提供实现接口的类库。这是为了解决接口不能被_类_引用这一问题。

import lombok.Getter;
import lombok.GetterDefaultValue;

class BigDecimalDefaultZero implements GetterDefaultValue {
    @Override
    public BigDecimal getDefaultValue() {
        return BigDecimal.ZERO;        
    }
}

public class MyClass {
    @Getter(defaultValueClass = BigDecimalDefaultZero.class)
    private BigDecimal value;
}

去龙目岛 后续最终的外观看起来

class BigDecimalDefaultZero implements GetterDefaultValue {
    @Override
    public BigDecimal getDefaultValue() {
        return BigDecimal.ZERO;        
    }
}

class MyClass {
    private BigDecimal value;
    private static BigDecimal DEFAULTVALUE_value = (new BigDecimalDefault()).getDefaultValue();

    public BigDecimal getValue() {
        return value == null ? DEFAULTVALUE_value : value;
    }
}

看起来市场上接受的这个路线图,或者对于 getter 中相对简单的默认值来说工作量太大了?

I have looked a bit into this because I can imagine the added value of such a getter. The example given, however, is not valid Java code:

@Getter(defaultValue = BigDecimal.ZERO)

This is because the arguments for an annotation cannot be just any Java Object (like BigDecimal.ZERO), but only a primitive, String, Class, enum or array. See also the Java specifications for annotations.

1st alternative

One route would be for the defaultValue to be some kind of enum listing default value types, for example:

@Getter(defaultValue = DefaultValues.BIGDECIMAL_ZERO)

Obviously this is not the prettiest of solutions, but I was able to make this work in a quick-and-dirty proof-of-concept version. The enum would have to contain a lot of default values for different types of classes (BigDecimal, BigInteger, etc). Major setback is that it would only work for a limited amount of values in a limited amount of classes, basically only zero in standard Java classes.

2nd alternative

Another alternative is to provide a tiny Class that implements an interface to provide the default value. This is basically a workaround for the fact that the interface parameters cannot refer to objects, but can refer to classes.

import lombok.Getter;
import lombok.GetterDefaultValue;

class BigDecimalDefaultZero implements GetterDefaultValue {
    @Override
    public BigDecimal getDefaultValue() {
        return BigDecimal.ZERO;        
    }
}

public class MyClass {
    @Getter(defaultValueClass = BigDecimalDefaultZero.class)
    private BigDecimal value;
}

The de-lombok-ed class would end up looking something like this:

class BigDecimalDefaultZero implements GetterDefaultValue {
    @Override
    public BigDecimal getDefaultValue() {
        return BigDecimal.ZERO;        
    }
}

class MyClass {
    private BigDecimal value;
    private static BigDecimal DEFAULTVALUE_value = (new BigDecimalDefault()).getDefaultValue();

    public BigDecimal getValue() {
        return value == null ? DEFAULTVALUE_value : value;
    }
}

Does this route seem acceptable, or too much work for a relatively simple default value in a getter?

Yes, that's what I mean. This way, it can avoid a lot of get methods