简体   繁体   中英

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

For whatever reason, I face issue when extending an abstract class, that extend a base abstract class, with implementation like this :

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)
}

When I run a test case that is using the ContractBuilder , I face the following issue:

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)

What do you think is causing it?

It looks like not having explicit constructors on the derived abstract class is causing this.

How's come the constructors don't inherit all the way down the inheritance chain?

The problem here is like this: Java and also Groovy does not have constructor inheritance - it only implies argument-less ones for subclasses, if you have not defined a c'tor in a sub-class.

So this fails with the error you have seen (simplified version with names, that make it easier to follow):


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 only "inherits" the one c'tor from SuperSuper without arguments. So super() in the c'tor of Clazz will work (and print default ).

The solution here is to make the in-between-super-class to inherit all constructors from their super class with @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()

Or of course go the route of being explicit and write the c'tors out in Super you actually want to use.

Additional infos:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM