A tool to generate an Android ContentProvider. It takes a set of entity (a.k.a "table") definitions as the input, and generates:
- a
ContentProviderclass - a
SQLiteOpenHelperclass - a
SQLiteOpenHelperCallbacksclass - one
Columnsclass per entity - one
Cursorclass per entity - one
ContentValuesclass per entity - one
Selectionclass per entity - one
Modelinterface per entity
This is where you declare a few parameters that will be used to generate the code.
These are self-explanatory so here is an example:
{
"syntaxVersion": 3,
"projectPackageId": "com.example.app",
"authority": "com.example.app.provider",
"providerJavaPackage": "com.example.app.provider",
"providerClassName": "ExampleProvider",
"sqliteOpenHelperClassName": "ExampleSQLiteOpenHelper",
"sqliteOpenHelperCallbacksClassName": "ExampleSQLiteOpenHelperCallbacks",
"databaseFileName": "example.db",
"databaseVersion": 1,
"enableForeignKeys": true,
"useAnnotations": true,
}Create one file per entity, naming it <entity_name>.json.
Inside each file, declare your fields (a.k.a "columns") with a name and a type.
You can also optionally declare a default value, an index flag, a documentation and a nullable flag.
Currently the type can be:
String(SQLite type:TEXT)Integer(INTEGER)Long(INTEGER)Float(REAL)Double(REAL)Boolean(INTEGER)Date(INTEGER)byte[](BLOB)enum(INTEGER).
You can also optionally declare table constraints.
Here is a person.json file as an example:
{
"documentation": "A human being which is part of a team.",
"fields": [
{
"documentation": "First name of this person. For instance, John.",
"name": "first_name",
"type": "String",
"defaultValue": "John",
},
{
"documentation": "Last name (a.k.a. Given name) of this person. For instance, Smith.",
"name": "last_name",
"type": "String",
"nullable": true,
"defaultValue": "Doe",
},
{
"name": "age",
"type": "Integer",
"index": true,
},
{
"name": "gender",
"type": "enum",
"enumName": "Gender",
"enumValues": [
"MALE",
"FEMALE",
{"OTHER": "Value to use when neither male nor female"},
],
"nullable": false,
},
],
"constraints": [
{
"name": "unique_name",
"definition": "UNIQUE (first_name, last_name) ON CONFLICT REPLACE"
},
]
}Notes:
- An
_idprimary key field is automatically (implicitly) declared for all entities. It must not be declared in the json file. nullableis optional (true by default).- if
documentationis present the value will be copied in Javadoc blocks in the generated code.
A more comprehensive sample is available in the etc/sample folder.
You can also have a look at the corresponding generated code in the etc/sample/app folder.
By convention, you should name your entities and fields in lower case with words separated by '_', like in the example above.
If a header.txt file is present, its contents will be inserted at the top of every generated file.
Download the jar from here: https://github.com/BoD/android-contentprovider-generator/releases/latest
java -jar android_contentprovider_generator-1.9.2-bundle.jar -i <input folder> -o <output folder>
- Input folder: where to find
_config.jsonand your entity json files - Output folder: where the resulting files will be generated
- When querying a table, use the corresponding
Selectionclass as shown in this example:
PersonSelection where = new PersonSelection();
where.firstName("John").or().age(42);
Cursor c = context.getContentResolver().query(PersonColumns.CONTENT_URI, projection,
where.sel(), where.args(), null);- When using the results of a query, wrap the resulting
Cursorin the corresponding wrapper class. You can then use the generated getters directly as shown in this example:
PersonCursor person = new PersonCursor(c);
String lastName = person.getLastName();
Long age = person.getAge();- You can also conveniently combine these two facilities by using the
query(ordelete) method:
PersonSelection where = new PersonSelection();
where.firstName("John").or().age(42);
PersonCursor person = where.query(getContentResolver());
person.moveToNext();
String lastName = person.getLastName();
Long age = person.getAge();- When updating or inserting into a table, use the corresponding
ContentValuesclass as shown in this example:
PersonContentValues values = new PersonContentValues();
values.putFirstName("John").putAge(42);
context.getContentResolver().update(personUri, values.values(), null, null);There is limited support for foreign keys and joins. Here is an example of the syntax:
{
"fields": [
{
"name": "main_team_id",
"type": "Long",
"nullable": false,
"foreignKey": {
"table": "team",
"onDelete": "CASCADE",
},
},
{
"name": "first_name",
"type": "String",
"nullable": false,
},
(...)
}In this example, the field main_team_id is a foreign key referencing the primary key of the team table.
- The appropriate
FOREIGN KEYSQL constraint is generated (ifenableForeignKeysis set totruein_config.json). - The
teamtable will be automatically joined when querying thepersontable (only if anyteamcolumns are included in the projection). - Getters for
teamcolumns are generated in thePersonCursorwrapper. - Of course if
teamhas foreign keys they will also be handled (and recursively).
- Foreign keys always reference the
_idcolumn (the implicit primary key of all tables) and thus must always be of typeLong- by design. - Only one foreign key to a particular table is allowed per table. In the example above only one column in
personcan point toteam. - Loops (i.e. A has a foreign key to B and B has a foreign key to A) aren't detected. The generator will infinitely loop if they exist.
- Cases such as "A has a FK to B, B has a FK to C, A has a FK to C" generate ambiguities in the queries, because C columns appear twice. In the sample app you can see an example of how to deal with this case, using prefixes and aliases (SQL's
ASkeyword).
A sample is available in the etc/sample folder.
You can have a look at the corresponding generated code in the etc/sample/app folder.
Here is the table shema of the sample:

You need maven to build this tool.
mvn package
This will produce android_contentprovider_generator-1.9.2-bundle.jar in the target folder.
Here is a list of other tools that try to tackle the same problem.
I did not have the chance to try them out.
- https://github.com/SimonVT/schematic
- https://github.com/TimotheeJeannin/ProviGen
- http://triple-t.github.io/simpleprovider/
- https://github.com/foxykeep/ContentProviderCodeGenerator
- https://code.google.com/p/mdsd-android-content-provider/
- https://github.com/hamsterksu/Android-AnnotatedSQL
- http://robotoworks.com/mechanoid/doc/db/api.html
- https://github.com/robUx4/android-contentprovider-generator (a fork of this project that generates more code)
- https://github.com/novoda/sqlite-analyzer (based on sql statements, not json)
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
Just to be absolutely clear, this license applies to this program itself, not to the source it will generate!