Struggling to create a GenericDao

427 views
Skip to first unread message

Bill Comer

unread,
Jun 12, 2017, 10:33:17 AM6/12/17
to jDBI
In my real example I have insert, delete & findById but have kleft them out as they all fail with the same issue as update

In the code below:
    findAll() works fine
However
    update() fails with the following error.


java.lang.NoSuchMethodError: java.lang.Object.update(Ljava/lang/Object;)J

at org.skife.jdbi.v2.sqlobject.CloseInternalDoNotUseThisClass$$EnhancerByCGLIB$$fa49eec0.update(<generated>)
at com.lgc.daos.GenericDaoImpl.update(GenericDaoImpl.java:38)
at com.lgc.daos.SchemeDaoImpl.update(SchemeDaoImpl.java:12)

Line 38 is 
  return getDao().update(t);

Any ideas what I am doing wrong ?

When I look at the 'dao' in the debugger it all looks OK from my limited understanding of CGLIB.
I can see the update method squirrelled away in its depths.



public interface GenericDao<T> {
List<T> findAll();
long update(T t);
}

I have a GenericDaoImpl

public class GenericDaoImpl<T, S extends GenericDao<T>> implements GenericDao<T> {

Class<? extends S> type;
S dao;

public GenericDaoImpl() {
Type s = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) s;
type = (Class) pt.getActualTypeArguments()[1];
}

@Autowired
DBI dbi;


@Override
public long update(T t) {
return getDao().update(t);
}

@Override
public List<T> findAll() {
return getDao().findAll();
}

  public S getDao() {
if (dao == null) {
dao = dbi.onDemand(type);
}
return dao;
}
}

& I have the Dao & DaoImpl to access my Table


@RegisterMapperFactory(EntityMapperFactory.class)
public interface SchemeDao extends GenericDao<Scheme> {

@Override
@SqlQuery("Select * FROM PORTAL2.scheme")
List<Scheme> findAll();


@Override
@SqlUpdate("UPDATE PORTAL2.scheme SET ifs_id=:s.schemeId" +
", prefix=:s.prefix" +
" WHERE id=:s.id")
long update(@BindBean("s") Scheme scheme);
}

@Repository
public class SchemeDaoImpl extends GenericDaoImpl<Scheme, SchemeDao> implements SchemeDao {
}

Scheme is just a plain old POJO with '@Column' annotations


Thanks,
Bill

Steven Schlansker

unread,
Jun 14, 2017, 4:20:54 PM6/14/17
to jd...@googlegroups.com
Hi Bill,

I don't think the approach you are trying will fundamentally work due to limitations in Java's type system
combined with the age of the jdbi2 codebase.

When jdbi looks at GenericDao<T> at runtime, what it really sees is GenericDao (with no <T>) and all Ts
replaced with Object.

So your method update(T) is actually update(Object) as declared by the supertype.

It is possible to try to reify this under the hood in some cases. jdbi2 does not and probably
never will support this.

jdbi3 has started to make this possible, but until there are tests proving it works, I am not sure that
such a GenericDao is really feasible. Feature requests, bug reports and fixes against jdbi3 are more than welcome though :)
> --
> You received this message because you are subscribed to the Google Groups "jDBI" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+uns...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

signature.asc

Matthew Hall

unread,
Jun 14, 2017, 4:29:21 PM6/14/17
to jd...@googlegroups.com
We actually have one team at $EMPLOYER that is already doing this in jdbi3, so it is possible. That's actually where the bridge method fix a couple months ago came from.

> To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+unsubscribe@googlegroups.com.

> For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "jDBI" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+unsubscribe@googlegroups.com.

Steven Schlansker

unread,
Jun 14, 2017, 4:45:43 PM6/14/17
to jd...@googlegroups.com
Is the approach you take there concise and approachable enough to add as a documentation bit? Seems like it'd be worth sharing.
> > To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+uns...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups "jDBI" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+uns...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> You received this message because you are subscribed to the Google Groups "jDBI" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+uns...@googlegroups.com.
signature.asc

Matthew Hall

unread,
Jun 14, 2017, 8:16:10 PM6/14/17
to jd...@googlegroups.com
Here's a basic example:

package com.app;

public interface CrudDao<T, ID> {
    @SqlUpdate
    @UseClasspathSqlLocator
    void insert(T entity);

    @SqlQuery
    @UseClasspathSqlLocator
    T getById(ID id);

    @SqlQuery
    @UseClasspathSqlLocator
    List<T> list();

    @SqlUpdate
    @UseClasspathSqlLocator
    void update(T entity);

    @SqlUpdate
    @UseClasspathSqlLocator
    void delete(ID id);
}

@RegisterBeanMapper(Contact.class)
public interface ContactDao extends CrudDao<Contact, Long> {}

@RegisterBeanMapper(Account.class)
public interface AccountDao extends CrudDao<Account, UUID> {}

In this example, SQL is loaded from files on the classpath, depending on the method called and which DAO subclass is used.
  • com/app/Contact/insert.sql
  • com/app/Contact/getById.sql
  • com/app/Contact/list.sql
  • com/app/Contact/update.sql
  • com/app/Contact/delete.sql
  • com/app/Account/insert.sql
  • com/app/Account/getById.sql
  • com/app/Account/list.sql
  • com/app/Account/update.sql
  • com/app/Account/delete.sql
Note that @UseClasspathSqlLocator is repeated on every method. This is because right now, we only look for annotations on the SQL object type itself (not supertypes). If a DAO subtype overrides a method from a supertype, we only look at the annotations present in the subtype.

In the future we may change this to look for annotations in the supertype, but it's not currently a priority.

-Matt

> > To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+unsubscribe@googlegroups.com.

> > For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups "jDBI" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+unsubscribe@googlegroups.com.

> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> You received this message because you are subscribed to the Google Groups "jDBI" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+unsubscribe@googlegroups.com.

> For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "jDBI" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+unsubscribe@googlegroups.com.

Matthew Hall

unread,
Jun 14, 2017, 8:18:03 PM6/14/17
to jd...@googlegroups.com
Oops: The file paths should have read ContactDao and AccountDao, instead of Contact and Account, to match the DAO interface names.

I do my best proofreading right after submission.

-Matt

Bill Comer

unread,
Jun 15, 2017, 3:43:03 AM6/15/17
to jDBI
Thanks Mathew,

Daft question - where do we log feature requests ?

The solution you have shown above is not quite what I am after.

My desire would be to remove the need for writing any SQL for basic CRUD
As for JDBI-v2 I came across this project that I will have a play with https://github.com/cemo/jdbi-extra

Regards,
Bill


Matthew Hall

unread,
Jun 15, 2017, 10:37:18 AM6/15/17
to jd...@googlegroups.com
You can open issues and submit pull requests at https://github.com/jdbi/jdbi

However, if you don't want to write your own SQL.. Jdbi might not be for you.

The philosophy of this project is that Jdbi should just be a conduit between you and the database with a better interface than JDBC. You, the user, tell the library what SQL statements you want to execute, and Jdbi simply carries it out. Writing your own SQL is an integral part of that philosophy. That's why they're named "SQL objects."

It might be possible to generate SQL using default methods in your base class, by inspecting the runtime generic type parameters of your DAO. But that's something you'd have to implement yourself, and we'll probably never support that use case directly in the library.

Regards,

-Matt


Steven Schlansker

unread,
Jun 15, 2017, 1:14:32 PM6/15/17
to jd...@googlegroups.com

> On Jun 15, 2017, at 12:43 AM, Bill Comer <bill....@gmail.com> wrote:
>
> Thanks Mathew,
>
> Daft question - where do we log feature requests ?

http://github.com/jdbi/jdbi

>
> The solution you have shown above is not quite what I am after.
>
> My desire would be to remove the need for writing any SQL for basic CRUD
> As for JDBI-v2 I came across this project that I will have a play with https://github.com/cemo/jdbi-extra
>

jdbi does not do SQL generation, and is not likely to gain that anytime soon.
You might look into other libraries like jooq that do this.

signature.asc

Bill Comer

unread,
Jun 16, 2017, 12:50:25 AM6/16/17
to jDBI
Thanks again.

I am quite happy writing SQL.

I am just trying to save having to write the CRUD all the time.
I'll set myself a task of attempting to achieve this, & look at JOOQ too.

Bill
 

Reply all
Reply to author
Forward
0 new messages