Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when trying to return a value with generics

Tags:

java

generics

I get this compile error "required T, found UseCaseTest" when I try to return INSTANCE at the method keepStateBetweenTests of the class UseCaseTest. I know I can easily fix it casting to T, but I want to do it right.

Plus, I don't know why the line

if (INSTANCE == null) INSTANCE = getInstance(activityTestRule);

can compile, given the previous error.

I supply two more classes to provide certain context.

UseCaseTest

public abstract class UseCaseTest {
    private static UseCaseTest INSTANCE;

    public abstract static class Builder<T extends UseCaseTest> {
        private final ActivityTestRule activityTestRule;

        protected Builder(ActivityTestRule activityTestRule) {
            this.activityTestRule = activityTestRule;
        }

        public T keepStateBetweenTests() {
            if (INSTANCE == null) INSTANCE = getInstance(activityTestRule); 
            return INSTANCE; //compile error: required T, found UseCaseTest
        }

        public T releaseStateBetweenTests() {
            return getInstance(activityTestRule);
        }

        protected abstract T getInstance(ActivityTestRule activityTestRule);
    }

    private final ActivityTestRule activityTestRule;

    public UseCaseTest(ActivityTestRule activityTestRule) {
        this.activityTestRule = activityTestRule;
    }
}

SessionUseCaseTest

public final class SessionUseCaseTest extends UseCaseTest {

    public static Builder<SessionUseCaseTest> with(ActivityTestRule activityTestRule) {
        return new Builder<SessionUseCaseTest> (activityTestRule) {
            @Override protected SessionUseCaseTest getInstance(ActivityTestRule activityTestRule) {
                return new SessionUseCaseTest(activityTestRule);
            }
        };
    }

    private SessionUseCaseTest(ActivityTestRule activityTestRule) {
        super(activityTestRule);
    }


    public void signUp() {}

    public void logout() {}
}

SessionTest

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SessionTest extends BaseTest {

    @Test public void _1_SingUp() {
        SessionUseCaseTest.with(mActivityRule)
                .keepStateBetweenTests()
                .signUp();
    }

    @Test public void _2_Logout() {
        SessionUseCaseTest.with(mActivityRule)
                .keepStateBetweenTests()
                .logout();
    }

}
like image 687
Víctor Albertos Avatar asked Jun 11 '26 12:06

Víctor Albertos


2 Answers

The topic of static method/fields in conjunction with generics is very well described in this post

Nevertheless, it would seem a simple casting makes the compiler happy while allowing to keep some level of generics in place:

public T keepStateBetweenTests() {
    if (INSTANCE == null)
        INSTANCE = getInstance(activityTestRule); 

    return (T)INSTANCE;
}

UPDATE

Part of your question was why this can compile although there is the error:

if (INSTANCE == null) INSTANCE = getInstance(activityTestRule);

To my understanding, the compiler knows the INSTANCE itself is actually UseCaseTest, which fulfills the restriction defined on the Builder class: <T extends UseCaseTest>

like image 166
Sva.Mu Avatar answered Jun 14 '26 10:06

Sva.Mu


You need to make your class aware of type T i.e.

public abstract class UseCaseTest <T> {

You can do like below:-

    class UseCaseTest<T> {
        final Class<T> useCaseTestType;

        public UseCaseTest(Class<T> useCaseTestType) {
            this.useCaseTestType = useCaseTestType;
        }

//Then write your methods which are generic
}
like image 34
Amit Bhati Avatar answered Jun 14 '26 08:06

Amit Bhati



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!