扩展扩展另一个抽象 class 的抽象 class 时的构造函数问题

Constructor issue when extending an abstract class that extends another abstract class

无论出于何种原因,我在扩展抽象 class 时遇到问题,扩展了基础抽象 class,实现如下:

ContractBuilder.groovy:

package com.xxx.builders

import static com.kms.katalon.core.testdata.TestDataFactory.findTestData

import com.xxx.enums.Frequency
import com.xxx.enums.Signatory
import com.xxx.models.contract.ContractModel
import com.xxx.models.contract.details.BankDetailModel
import com.xxx.utils.SMDDateUtils

public class ContractBuilder extends BaseFinderBuilder<ContractModel> {

    public ContractBuilder() {
        super(findTestData('PracticeContractData'))
    }

    @Override
    public ContractModel createModelFromRow(List<Object> row) {
        return new ContractModel(
                Integer.parseInt(row[0]),
                SMDDateUtils.toDate(row[2]),
                SMDDateUtils.toDate(row[3]),
                Integer.parseInt(row[4]),
                row[6],
                Double.parseDouble(row[5]),
                Frequency.valueOfText(row[7]),
                Integer.parseInt(row[8]),
                Integer.parseInt(row[10]),
                (row[11] == 'Y'),
                Integer.parseInt(row[12]),
                row[13],
                Signatory.valueOfText(row[14]),
                this.createBankDetailModel(row),
                Double.valueOf(row[18]),
                )
    }

    public BankDetailModel createBankDetailModel(row) {
        return new BankDetailModel(Double.valueOf(row[15]), Double.valueOf(row[16]), Double.valueOf(row[17]));
    }
}

BaseFinderBuilder.groovy:

package com.xxx.builders

public abstract class BaseFinderBuilder<T> extends BaseModelBuilder<T>{

    protected int primaryKeyIdx = 1;

    public T createModelFromID(int id) {
        return this.createModelFromRowNum(this.findIndex(id));
    }

    protected int findIndex(int foreignKey) {
        for (int rowIdx = 0; rowIdx < this.testData.getRowNumbers(); rowIdx++) {
            if (Integer.parseInt(this.testData.getValue(this.primaryKeyIdx, rowIdx + 1)) == foreignKey) {
                return rowIdx
            }
        }

        return -1
    }
}

BaseModelBuilder.groovy:

package com.xxx.builders

import java.util.stream.Collectors

import com.kms.katalon.core.testdata.TestData

public abstract class BaseModelBuilder<T> {
    protected TestData testData;

    public BaseModelBuilder() {
        this.init();
    }

    public BaseModelBuilder(TestData testData) {
        this.testData = testData;
        this.init();
    }

    protected void init() {
        // implementation go here
    }

    public List<T> createModels() {
        return this.testData.getAllData()
                .stream()
                .filter { row ->
                    row.stream().anyMatch { String cell ->
                        cell != null && !cell.isEmpty()
                    }
                }
                .map { row -> this.createModelFromRow(row) }
                .collect(Collectors.toList())
    }

    public T createModelFromRowNum(int rowNum) {
        return this.createModelFromRow(this.testData.getAllData().get(rowNum))
    }

    public abstract T createModelFromRow(List<Object> row)
}

当我 运行 一个使用 ContractBuilder 的测试用例时,我面临以下问题:

groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.xxx.builders.BaseFinderBuilder(com.kms.katalon.core.testdata.reader.SheetPOI)
    at com.xxx.builders.ContractBuilder.<init>(ContractBuilder.groovy:14)
    at com.xxx.builders.PracticeBuilder.init(PracticeBuilder.groovy:26)
    at com.xxx.builders.BaseModelBuilder.<init>(BaseModelBuilder.groovy:16)
    at com.xxx.builders.PracticeBuilder.<init>(PracticeBuilder.groovy:20)
    at New Zoho - 02 Create Practice.run(New Zoho - 02 Create Practice:15)

您认为是什么原因造成的?

看起来在派生抽象 class 上没有显式构造函数是导致此问题的原因。

为什么构造函数不沿继承链一路继承?

这里的问题是这样的:Java还有Groovy没有 构造函数继承 - 它只意味着无参数的 subclasses,如果你没有在子class.

中定义一个c'tor

所以这失败了你看到的错误(简化版本 名称,使它更容易理解):


class SuperSuper {
    SuperSuper() {
        println "default"
    }
    SuperSuper(text) {
        println "hello, $text"
    }
}

class Super extends SuperSuper {}

class Clazz extends Super {
    Clazz() {
        super("World")
    }
}

new Clazz()
// → Caught: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: Super(String)

Super 仅“继承”来自 SuperSuper 的一个 c'tor 没有 争论。因此 Clazz 的 c'tor 中的 super() 将起作用(并打印 default).

这里的解决方法是让in-between-super-class继承all 来自超级 class 和 @InheritConstructors:

的构造函数
class SuperSuper {
    SuperSuper() {
        println "default"
    }
    SuperSuper(text) {
        println "hello, $text"
    }
}

@groovy.transform.InheritConstructors // XXX
class Super extends SuperSuper {}

class Clazz extends Super {
    Clazz() {
        super("World")
    }
}

new Clazz()

或者当然要走明确的路线,将 c'tors 写在 Super你真的想用。

附加信息:

  • Default constructors and inheritance in Java
  • Java Constructor Inheritance