Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problematic use of generic types #238

Closed
ldcasillas-progreso opened this issue Oct 25, 2016 · 14 comments
Closed

Problematic use of generic types #238

ldcasillas-progreso opened this issue Oct 25, 2016 · 14 comments
Labels
stale type/breaking-api-change Public APIs are being changed
Milestone

Comments

@ldcasillas-progreso
Copy link

ldcasillas-progreso commented Oct 25, 2016

Using TestContainers 1.1.6, the following code produces a compile time error:

private static final PostgreSQLContainer postgres =
        new PostgreSQLContainer("postgres:9.5.4")
                .withDatabaseName("test")
                .withEnv("PGDATA", CONTAINER_PGDATA)
                .withFileSystemBind(HOST_PGDATA.toString(), CONTAINER_PGDATA, BindMode.READ_WRITE);

Compilation error:

/Users/my-user-name/my-project/my/path/to/IntegrationTest.java:71: error: incompatible types: GenericContainer cannot be converted to PostgreSQLContainer
                    .withFileSystemBind(HOST_PGDATA.toString(), CONTAINER_PGDATA, BindMode.READ_WRITE)

The problem stems from the fact that the PostgreSQLContainer class starts like this, with a recursive bound on its generic type parameter (à la class Enum<E extends Enum<E>>):

public class PostgreSQLContainer<SELF extends PostgreSQLContainer<SELF>> 
        extends JdbcDatabaseContainer<SELF>

So this is a generic class, but the documentation and example test case use it with no type parameter, as a raw type:

@Rule
public PostgreSQLContainer postgres = new PostgreSQLContainer();

And in this situation Java can't figure out that in my use of the withFileSytemBind() method, the SELF return type unifies with PostgreSQLContainer.

My workaround for this issue illustrates the fix:

// A dummy class whose sole purpose is to instantiate the `SELF`
// type parameter.
private static final class MyPostgreSQLContainer extends PostgreSQLContainer<MyPostgreSQLContainer> {
    public MyPostgreSQLContainer(String dockerImageName) {
        super(dockerImageName);
    }
}

private static final MyPostgreSQLContainer postgres =
        new MyPostgreSQLContainer("postgres:9.5.4")
                .withDatabaseName("test")
                .withEnv("PGDATA", CONTAINER_PGDATA)
                .withFileSystemBind(HOST_PGDATA.toString(), CONTAINER_PGDATA, BindMode.READ_WRITE);

This argues that the existing "end user facing" classes like PostgreSQLContainer in the library ought to be split into two classes:

public abstract class AbstractPostgreSQLContainer<SELF extends AbstractPostgreSQLContainer<SELF>> 
        extends JdbcDatabaseContainer<SELF> {
    ...
}

public class PostgreSQLContainer extends AbstractPostgreSQLContainer<PostgreSQLContainer> {
    ...
}

People who want to extend PostgreSQLContainer should be discouraged from doing so as well, and pointed to AbstractPostgreSQLContainer as the proper class for extension. (Making PostgreSQLContainer a final class is one alternative here, but with the downside that it's a backwards-incompatible change.)

@bsideup
Copy link
Member

bsideup commented Oct 26, 2016

@ldcasillas-progreso thanks for the report!

As a temporary workaround, I can suggest this:

private static final PostgreSQLContainer postgres =
   new PostgreSQLContainer<>("postgres:9.5.4")
    .withDatabaseName("test")
    .withEnv("PGDATA", CONTAINER_PGDATA)
    .withFileSystemBind(HOST_PGDATA.toString(), CONTAINER_PGDATA, BindMode.READ_WRITE);

(note the diamond operator)

@ldcasillas-progreso
Copy link
Author

@bsideup Ah, good one!

@rnorth
Copy link
Member

rnorth commented Nov 20, 2016

@ldcasillas-progreso yes, I can see how this would be annoying, and we're keen to come up with a more user-friendly model (which will probably be a breaking change and the focus of a future 2.0.0 release).

In the meantime @bsideup's workaround is the right way, and I'd like to think about your suggested fix too. It looks pretty sensible to me. It might be a good solution for users on the 1.x.x series and something we can integrate reasonably soon.

@rnorth rnorth modified the milestone: 2.0 Jan 14, 2017
@rnorth rnorth added the type/breaking-api-change Public APIs are being changed label Jan 14, 2017
@mpecan
Copy link

mpecan commented Jul 18, 2017

This issue also makes it very hard to use Testcontainers in Kotlin (and still exists in the current 1.2.1 version).

Is there any progress on this? Can I help out with a PR?

@bsideup
Copy link
Member

bsideup commented Jul 18, 2017

Hi @mpecan,

If you have an idea how to solve self-referencing without breaking current behavior it would be great!

You can also submit a bug to Kotlin... Well... Because it's a bug in Kotlin and a valid JVM bytecode :D

@martin-g
Copy link

The solution I've shared at #318 (comment) works without any issues for me.

@mpecan
Copy link

mpecan commented Jul 18, 2017

@martin-g Agreed. And I can see why.

@bsideup I will give it a stab in the next couple of days.

@stale
Copy link

stale bot commented Oct 28, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you believe this is a mistake, please reply to this comment to keep it open. If there isn't one already, a PR to fix or at least reproduce the problem in a test case will always help us get back on track to tackle this.

@stale stale bot added the stale label Oct 28, 2018
@stale
Copy link

stale bot commented Nov 11, 2018

This issue has been automatically closed due to inactivity. We apologise if this is still an active problem for you, and would ask you to re-open the issue if this is the case.

@martinandersson
Copy link

Reopen please. Should be an absolute top priority if you ask me.

@missingfaktor
Copy link

Could you please reopen this issue? I'm trying to use this library in Scala, and with the way generics are currently used here, it's really difficult. I'm happy to help out with PRs.

@mikelhamer
Copy link

Is this "2.0" I see mentioned in this issue and other related issues about generic types actually happening? Even though it seems like a minor thing, I can't stand the thought of using something where I had to tell the IDE to suppress warnings for constantly

@bsideup
Copy link
Member

bsideup commented Feb 20, 2022

We're experimenting with a new "container definitions API" that will be an experimental alternative API in 1.x and get promoted as the main one in 2.0 if the feedback is good.

You can preview it here:
#4465

Usage example:
https://gist.github.com/bsideup/8247229e8a8dd86ac8bcf490e2ce6acb

@mikelhamer
Copy link

Thank you I love you and I love this project. Keep up the good work everyone! Really awesome tool youve built here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale type/breaking-api-change Public APIs are being changed
Projects
None yet
Development

No branches or pull requests

8 participants