javagenerics

Java circular generic-type parameter issue


I have these interfaces and classes in a java (17) application:

public interface ISurvey<T extends ISurveyDetails<? extends ISurvey<T>>> {
    void setDetails(T details);
}
public interface ISurveyDetails<T extends ISurvey<? extends ISurveyDetails<T>>> {
    void setSurvey(T survey);
}
public class AppleSurvey implements ISurvey<AppleSurveyDetails> {
    @Override
    public void setDetails(AppleSurveyDetails details) {
    }
}
public class AppleSurveyDetails implements ISurveyDetails<AppleSurvey> {
    @Override
    public void setSurvey(AppleSurvey survey) {
    }
}
public class ComplexGenericUser {
    <T extends ISurveyDetails<ISurvey<T>>> void setDetail(ISurvey<T> survey, Supplier<T> detailMaker) {
        var detail = detailMaker.get();
        detail.setSurvey(survey);
        survey.setDetails(detail);
    }

    void useWithApple() {
        var appleSurvey = new AppleSurvey();
        setDetail(appleSurvey, AppleSurveyDetails::new);
    }
}

Whole system is ok except the call to setDetail() in useWithApple() method of ComplexGenericUser class. The compiler error states that no instance of type variable (T) exists so that AppleSurvey conforms to ISurvey<T>. How can I resolve this?


Solution

  • AppleSurveyDetails implements ISurveyDetails<AppleSurvey>. As written, your setDetail method expects AppleSurveyDetails to implement ISurveyDetails<ISurvey<AppleSurveyDetails>>, not ISurveyDetails<AppleSurvey>.

    I think correctly parameterizing setDetail requires two type parameters, one for the survey and one for the details:

    <D extends ISurveyDetails<S>, S extends ISurvey<D>>
    void setDetail(S survey, Supplier<D> detailMaker) {
        var detail = detailMaker.get();
        detail.setSurvey(survey);
        survey.setDetails(detail);
    }
    

    You'll also need to fix your setDetail call - the supplier should just be AppleSurveyDetails::new, not () -> AppleSurveyDetails::new.