Retrobase — like Retrofit, but for database
Many Android developers use Retrofit library, that allows turn HTTP API into java-interface. It’s very convenient, because it reduces the amount of code and this is one of the easiest to use. You just need to create interface and add some annotations.
Recently I was engaged in the development of applications for Android, that was necessary to make queries to the database through the JDBC-driver. Thereat I decided to do something like Retrofit, but for database. So Retrobase appeared, that I’m going to tell you about now.
To turn interface and annotation into working code we need Annotation Processing, that gives us great opportunities in generating of similar code. Moreover, in conjunction with JavaPoet we can generate java-code easily and simply.
There are many articles about Annotation Processing in the Internet, so it’s not a problem to understand and deal with it. Plus, all things You need to know to work with JavaPoet is in it’s README.md.
The foundation of Retrobase is two annotaions — DBInterface
andDBQuery
together withDBAnnotationProcessor
that makes all code generation. WhileDBInterface
marks interface with methods-queries to database, DBQuery
is used to mark each method. Methods may have parameters, those will be used in SQL-query. For example:
All interesting things happen in DBAnnotationProcessor
, where implementation of interface is generated. Generated class have name *interface_name* + Impl
.
Then the connection to database is created.
Also DBAnnotationProcessor
creates PreparedStatement
for every query.
… and realization of method for this query.
In addition it takes into account return type of method. It can be void
if SQL-query is INSERT, DELETE or UPDATE and it doesn’t return anything. Or it can be ResultSet
if SQL-query is SELECT.
Farther DBAnnotationProcessor
checks whether method can throw Exception
. If it can, all exceptions will be throws from realization of method. Else they will be caught and printed to stderr
.
All parameters of annotated method are added to implementing method and DBAnnotationProcessor
will generate statement that transfers each parameter’s value to PreparedStatement
.
Of course, quantity and types of method’s parameters must correlate with parameters of SQL-query that was transmitted by DBQuery
annotation.
After generating of interface implementation, DBAnnotationProcessor
writes it using instruments of Annotation Processing.
Rx it!
Surely, it’s convenient to get ResultSet
, while defining only interface, but it can be improved by using popular RxJava. Also using RxJava we can easily make async queries.
To make Retrobase reactive DBMakeRxAnnotationProcessor
together with annotations DBInterfaceRx
and DBMakeRx
were created. You could see example of use of these annotation in example above. Class generated with DBMakeRxAnnotationProcessor
will have name *interfave_name* + Rx
and will have opened constructor that gets object of interface marked with DBInterfaceRx
. Generated class will transfer queries to this object, returning result in reactive style.
To use DBMakeRxAnnotationProcessor
You should add DBMakeRx
annotation to method-query. This annotation gets the name of model-class. Generated method-wrapper will return Observable<*model-class*>
. If You will not define model-class, generated method will return io.reactivex.Completable
that is well for INSERT, DELETE and UPDATE queries those don’t return result.
As you can see, model-class must have opened constructor that gets ResultSet
, because generated method-wrapper creates objects of model-class automatically.
Generated method-wrapper will have same quantity and types of parameters as method-query annotated withDBMakeRx
.
All exceptions those will be thrown by method-query will be caught and sent to Observer.
Of course, new SpendDBImpl();
or new SpendDBRx(mSpendDB);
may be replaced for testing using Dagger or any other DI library.
Source code of Retrobase with comments and working example are open. Feel free to modify them!
The aim of Retrobase is not only make queries to database easier, but show how powerful may be Annotation Processing. There are a lot of code that can be written automatically!