java Lombok岛传承:如何在超类中设置字段默认值而不重新声明它?

7kjnsjlb  于 2023-05-12  发布在  Java
关注(0)|答案(3)|浏览(295)

我正在使用Lombok,我需要一种方法来自动设置子类中超类字段的值而无需重新声明它
在使用构建器时,它自己工作得很好(@SuperBuiler@Builder.Default),但它在使用Spring-Data MongoDB时遇到了麻烦。

org.springframework.data.mapping.MappingException: Ambiguous field mapping detected! Both protected test.jackson.polymorphism.domain.enumeration.EvaluationType test.jackson.polymorphism.domain.models.EvaluationModel.type and private test.jackson.polymorphism.domain.enumeration.EvaluationType test.jackson.polymorphism.domain.models.QuantitativeEvaluationModel.type map to the same field name type! Disambiguate using @Field annotation!

    at org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity$AssertFieldNameUniquenessHandler.assertUniqueness(BasicMongoPersistentEntity.java:368)
    at org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity$AssertFieldNameUniquenessHandler.doWithPersistentProperty(BasicMongoPersistentEntity.java:354)
    at org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity$AssertFieldNameUniquenessHandler.doWithPersistentProperty(BasicMongoPersistentEntity.java:348)

这些是我的班级:

public enum EvaluationType{
    QUALITATIVE, QUANTITATIVE;
}
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public abstract class EvaluationModel {
    protected EvaluationType type;
    protected Integer evaluation;
}
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class QualitativeEvaluationModel extends EvaluationModel {
    /**
     * How to set the default value for this field
     * without redeclaring it?
     */
    @Builder.Default
    private EvaluationType type = EvaluationType.QUALITATIVE;
}
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class QuantitativeEvaluationModel extends EvaluationModel {
    /**
     * How to set the default value for this field
     * without redeclaring it?
     */
    @Builder.Default
    private EvaluationType type = EvaluationType.QUANTITATIVE;

    @Builder.Default
    private String currencyCode = Currency.getInstance("EUR").getCurrencyCode();

    private BigDecimal economicValue;
}

我如何使这些子类具有type字段的默认值(mayb final),但不重新声明该字段?这应该与施工者和建筑商一起工作。

rbpvctlc

rbpvctlc1#

从你的描述中,听起来有点像你不想要一个可设置的字段,而只是一个取决于子类示例的固定值。在这种情况下,不带任何字段的手动实现的getter方法是更好的选择。
但是,如果你真的希望用户能够设置一个不同于默认值的值,这是你的方法:

@SuperBuilder
public class QualitativeEvaluationModel extends EvaluationModel {
    
    public static abstract class QualitativeEvaluationModelBuilder<C extends QualitativeEvaluationModel, B extends QualitativeEvaluationModelBuilder<C, B>> extends EvaluationModel.EvaluationModelBuilder<C, B>
    {
        public QualitativeEvaluationModelBuilder() {
            type(EvaluationType.QUALITATIVE);
        }
    }
}

它定义构建器类,就像Lombok创建它一样(Lombok将添加您没有手动编写的任何内容)。因为它实际上充满了泛型,所以我使用delombok来使它正确。接下来,您必须为构建器示例定义一个默认值,只需在构建器的构造函数中为type调用构建器的setter方法。
通过这种方式,没有在构建器示例上调用type()方法的用户将获得默认值。如果您想要其他的东西作为type,只需在构建器示例上调用type()方法。
请注意,这只影响构建器。如果你还想通过(no-args)构造函数示例化,你必须手动实现构造函数并设置默认值。

ccgok5k5

ccgok5k52#

解决这个问题的一个方法(并不特定于Lombok)是在子类中使用一个初始化器块(https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html)。

@Data
@SuperBuilder
public class QualitativeEvaluationModel extends EvaluationModel {
    {
        super.type = EvaluationType.QUALITATIVE;
    }
}
ar7v8xwq

ar7v8xwq3#

您可以自己定义构建器方法并在那里进行初始化。默认的构建器方法名是builder(),甚至可以使用@SuperBuilder(builderMethodName = "myBuilderMethodName")进行自定义

@Getter
@SuperBuilder
@EqualsAndHashCode
public class HttpError {

  private final int status;
  private String type;
  private String title;
  private String detail;
  private String instance;

}

@SuperBuilder
@EqualsAndHashCode(callSuper = true)
public class BadRequestError extends HttpError {

  public static BadRequestError.BadRequestErrorBuilder<?, ?> builder(){
    return new BadRequestError.BadRequestErrorBuilderImpl()
        .title("Bad Request")
        .status(400);
  }

相关问题