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

When using lambda: "Must use a concretely typed RowMapper here" #1070

Closed
dhardtke opened this issue Apr 9, 2018 · 3 comments
Closed

When using lambda: "Must use a concretely typed RowMapper here" #1070

dhardtke opened this issue Apr 9, 2018 · 3 comments
Labels
Milestone

Comments

@dhardtke
Copy link
Contributor

dhardtke commented Apr 9, 2018

First of all: Thanks for this awesome library! We are slowly migrating from Hibernate to jdbi and are very satisfied with it so far ;)

Suppose I have the following code:

getHandle().createQuery("SELECT ...")
    .bind("id", id)
    .registerRowMapper((RowMapper<CatalogueJdbi>) (rs, ctx) -> {
        final CatalogueJdbi catalogue = FieldMapper.of(CatalogueJdbi.class, "c").map(rs, ctx);
        if (rs.getObject("mid") != null) {
            catalogue.setImage(FieldMapper.of(MediaFileJdbi.class, "m").map(rs, ctx));
        }

        return catalogue;
    })
    .mapTo(CatalogueJdbi.class)
    .collect(Collectors.toSet());

When registering the RowMapper as shown I get

java.lang.UnsupportedOperationException: Must use a concretely typed RowMapper here
	at org.jdbi.v3.core.mapper.InferredRowMapperFactory.lambda$new$0(InferredRowMapperFactory.java:38)
	at java.base/java.util.Optional.orElseThrow(Optional.java:385)
	at org.jdbi.v3.core.mapper.InferredRowMapperFactory.<init>(InferredRowMapperFactory.java:38)
	at org.jdbi.v3.core.mapper.RowMappers.register(RowMappers.java:63)
	at org.jdbi.v3.core.config.Configurable.lambda$registerRowMapper$16(Configurable.java:248)
	at org.jdbi.v3.core.config.Configurable.configure(Configurable.java:74)
	at org.jdbi.v3.core.config.Configurable.registerRowMapper(Configurable.java:248)
	at ...

but when using

.registerRowMapper(new RowMapper<CatalogueJdbi>() {
                    @Override
                    public CatalogueJdbi map(final ResultSet rs, final StatementContext ctx) throws SQLException {
                        final CatalogueJdbi catalogue = FieldMapper.of(CatalogueJdbi.class, "c").map(rs, ctx);
                        if (rs.getObject("mid") != null) {
                            catalogue.setImage(FieldMapper.of(MediaFileJdbi.class, "m").map(rs, ctx));
                        }

                        return catalogue;
                    }
                })

instead everything works fine.

I thought lambdas were only syntactic sugar and the compiler would expand the code anyway?

@qualidafial
Copy link
Member

Due to generic erasure, the <CatalogueJdbi> parameter is lost at runtime, so Jdbi doesn't know what type that mapper maps to.

There is an alternative method you can use, where you pass the type as a separate parameter:

.registerRowMapper(CatalogueJdbi.class, (rs, ctx) -> { ... })

One thing to note: registering a row mapper and then calling mapTo(type) is wasted effort if that mapper is not being reused anywhere else. You could just call the map(RowMapper<T>) method and pass the lambda directly to that:

.map((rs, ctx) -> { ... })

@qualidafial qualidafial added this to the JDBI 3.x milestone Apr 9, 2018
@dhardtke
Copy link
Contributor Author

dhardtke commented Apr 9, 2018

I knew I was doing something wrong :) Thanks a lot!

@dhardtke dhardtke closed this as completed Apr 9, 2018
@qualidafial
Copy link
Member

As a follow up: when you create an anonymous inner class, you are creating a concretely typed mapper.

What we mean by concretely typed is that Jdbi can get the mapper's class and reflectively discover the generic parameter T for RowMapper<T>. Whether you do this via a full-fledged class like class FooMapper implements RowMapper<Foo> { ... } or via an anonymous inner class e.g. new RowMapper<Foo>() { ... }, it looks the same to Jdbi.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants