A code generator to create Android ContentProvider

Overview

DatabaseCodeGenerator

This project is a code generator written in Java used to generate Android code. Given a database schema JSON definition file, it will generate all the code you need to add the corresponding ContentProvider in your project.

Architecture of the project

The java project found in the folder 'generator' contains the following folders :

  • src : The code used to generate your ContentProvider. Normally you shouldn't have to modify it.
  • res : This folder contains snippets of code used by the generator.
  • input : This folder contains your database schema JSON definition files. You can have multiple JSON files next to each other. An example and the JSON format are available in the example subfolder.
  • output : This is where the generated code will be written. Each generate code will be stored in a folder based on the corresponding JSON file name to separate them.

How to use ContentProviderCodeGenerator

In order to use it, here are the steps to follow :

  1. Download the current version of the project on your computer using git (git clone [email protected]:foxykeep/ContentProviderCodeGenerator.git).
  2. Import the project in the folder 'generator' in your Eclipse workspace.
  3. Write your JSON definition file. You can use the format file and the example file given in the folder input/example to help you.
  4. Run the project as a Java application.
  5. Your classes are available in the output folder

Building/Running from the CLI

    mkdir generator/bin
    mkdir generator/bin/input
    cd generator/bin
    ln -s ../res .
    javac $(find ../src -name *.java) -d .
    mkdir input
    cp ../example/sample.json ./input
    java com/foxykeep/cpcodegenerator/Main

Example

You can find in the 'sample' folder an example of an Android application which uses the generated ContentProvider

TODO

  • Add a sample project which uses a generated ContentProvider

Credits and License

Foxykeep (http://foxykeep.com)

Licensed under the Beerware License :

You can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return.

Comments
  • Override default notifyChanges behavior

    Override default notifyChanges behavior

    If there's the need to make different insert/update/replace queries, one would like to notify changes with notifyChanges only at the end of the whole process. As of now, changes are automatically notified at the end of each insert/update/delete. By overriding the generated ContentProvider one could be able to override the default implementation. Also, allowing the ContentProvider to be inherited from could let developers use some custom logic for join fake-Uris (which is something I'm doing) without having to manually edit the generated ContentProvider, by implementing that very logic in the inherited class.

    opened by frapontillo 16
  • Add table fail on onUpgrade

    Add table fail on onUpgrade

    Imagine we have a database with current database version 4. Let's add a table called "Tabs" on database version 5.

    {
                "table_name":"Tabs",
                "version":5,
                "fields":[
                    {
                        "name":"id",
                        "type":"long",
                        "is_primary_key":true,
                        "is_id":true
                            },
                    {
                        "name":"name",
                        "type":"text"
                    }
                ]
            }
    

    The code generated is the following :

    // Version 6 : Creation of the table
            public static void upgradeTable(SQLiteDatabase db, int oldVersion, int newVersion) {
    
                if (oldVersion < 1) {
                    Log.i(LOG_TAG, "Upgrading from version " + oldVersion + " to " + newVersion 
                            + ", data will be lost!");
    
                    db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME + ";");
                    createTable(db);
                    return;
                }
    
    
                if (oldVersion != newVersion) {
                    throw new IllegalStateException("Error upgrading the database to version " 
                            + newVersion);
                }
            }
    

    The SQLiteOpenHelper with its method getDatabaseLocked detects a new version and then launches "onUpgrade(db, version, mNewVersion);.

    Tabs.upgradeTable(db, oldVersion, newVersion); is called, oldVersion=4 and newVersion=5 so the first condition is false and the second is true and we throw an exception. Shouldn't we add a mechanism to force the table creation?

    Julien

    opened by JulienDev 8
  • autoincrement on long

    autoincrement on long

    I'm a newbie to SQLite. So please forgive. But I did receive this error:

    Exception in thread "main" java.lang.IllegalArgumentException: Field "eventId" | is_autoincrement can only be used on an integer type field at com.foxykeep.cpcodegenerator.model.FieldData.(FieldData.java:44) at com.foxykeep.cpcodegenerator.model.TableData.(TableData.java:40) at com.foxykeep.cpcodegenerator.model.TableData.getClassesData(TableData.java:66) at com.foxykeep.cpcodegenerator.Main.main(Main.java:100)

    I changed the code on line 44 to

    if (dbIsAutoincrement && !type.equals("integer") && !type.equals("long")) { throw new IllegalArgumentException("Field "" + name + "" | is_autoincrement can " + "only be used on an integer type field"); }

    My question is...is autoincrement valid only on int types? Is long OK?

    opened by jbarwick 6
  • Enumeration Types

    Enumeration Types

    I'd like the ability to add "enum" classes and refer to them in a field definition. And specify in the field definition to store a string or an int.

    Could create something like:

    "enums": [ { "enum_name": "ReadFlag", "enum_values": [ { "value": "UNREAD", "intvalue": "0", "string_value": "UNREAD" }, { "value": "READ", "intvalue": "1", "string_value": "READ" }, { "value": "UNSPECIFIED", "intvalue": "-1", "string_value": "UNSPECIFIED" }, ] },

    and then the resulting class would be:

    public enum ReadStatus {

    UNREAD, READ, UNKNOWN;
    
    /**
     * <p>
     * Returns the enumerated value for the specified integer. If the value is
     * out of range, UNKOWN is returned.
     * <ul>
     * <li>0 - {@code UNREAD}
     * <li>1 - {@code READ}
     * </ul>
     * 
     * @param in
     * @return the enumeration
     */
    public static ReadStatus forInt(int in) {
        switch (in) {
        case 0:
            return UNREAD;
        case 1:
            return READ;
        }
        return UNKNOWN;
    }
    
    /**
     * /**
     * <p>
     * Returns the enumerated value for the specified integer. If the value is
     * out of range, UNKOWN is returned.
     * <ul>
     * <li>"UNREAD" - {@code UNREAD}
     * <li>"READ" - {@code READ}
     * </ul>
     * 
     * @param in
     * @return the enumeration
     */
    public static ReadStatus forString(String in) {
        if ("READ".equalsIgnoreCase(in))
            return READ;
        if ("UNREAD".equalsIgnoreCase(in))
            return UNREAD;
        return UNKNOWN;
    }
    
    /**
     * Returns an integer representation of the enumeration
     * 
     * @return an integer representation of the enumeration
     */
    public int toInt() {
        switch (this) {
        case UNREAD:
            return 0;
        case READ:
            return 1;
        default:
            return -1;
        }
    }
    
    /**
     * Returns an string representation of the enumeration
     * 
     * @return an string representation of the enumeration
     */
    @Override
    public String toString() {
        switch (this) {
        case UNREAD:
            return "UNREAD";
        case READ:
            return "READ";
        default:
            return null;
        }
    }
    

    }

    Then a reference something like:

    "tables": [ { "table_name": "TheTable", "fields": [ { "name": "status", "type": "int", "enumeration": "ReadFlag" },

    The resulting table class would be:

    public class TheTable { private ReadFlag status; }

    With the appropriate SQL inserts doing a "toInt()" or "toString()" and the appropriate cursor reads doing the "Enumeration.forInt()" or "Enumeration.forString()" calls.

    What do you think? Sorry, I'm just really fond of enumerations.

    Was thinking of offering some code. But in the current Code Generator's construction, do you think this would be incredibly difficult or just a bit trivial?

    opened by jbarwick 1
  • Making a JOIN query over a content provider generated by this tool

    Making a JOIN query over a content provider generated by this tool

    Hi,

    First of all thank you so much for this, it has been great, I really like using this together with dataDroid.

    Now usually when you need to perform a query with a JOIN on your content provider you need to setup a new Uri on your URI matcher to "catch" the query correctly and route your code accordingly.

    As of right now I'm unable to find support for this on this tool, so how would you suggest to do this?, maybe supporting this on the tool itself or changing the generated code afterwards.

    opened by suarezjulian 1
  • Push create/update table start/end logging into respective methods

    Push create/update table start/end logging into respective methods

    Currently, the logging for table create/update is generated like so:

        if (ACTIVATE_ALL_LOGS) {
            Log.d(LOG_TAG, "MyTable | createTable start");
        }
        MyTable.createTable(db);
        if (ACTIVATE_ALL_LOGS) {
            Log.d(LOG_TAG, "MyTable | createTable end");
        }
    

    If one has a number of tables, this begins to look very cluttered in the source. It might be better to have this logging pushed into the beginning and end of the createTable method (and the updateTable methods as well).

    E.g.

    public static void createTable(SQLiteDatabase db) {
        if (ACTIVATE_ALL_LOGS) {
            Log.d(LOG_TAG, "MyTable | createTable start");
        }
        db.execSQL("CREATE TABLE " + TABLE_NAME + " (" +
                        Columns.ID.getName() + " " + Columns.ID.getType()+ ", " +
                        Columns.NAME.getName() + " " + Columns.NAME.getType() + ", " +
        ");");
        if (ACTIVATE_ALL_LOGS) {
            Log.d(LOG_TAG, "MyTable | createTable end");
        }
    }
    
    opened by peterschwarz 1
  • NotificationUri should be the one provided by the query

    NotificationUri should be the one provided by the query

    Hi,

    When we do a request, the notificationUri is not the given Uri but the authority Uri. It causes a cursor to be notified each time there is a change somewhere in the database. The notificationUri should be the queried Uri.

    Current source generated :

    Uri notificationUri = LeGorafiContent.CONTENT_URI; [...] if ((c != null) && !isTemporary()) { c.setNotificationUri(getContext().getContentResolver(), notificationUri); }

    Julien

    opened by JulienDev 1
  • Incorrect instruction in the README about run using CLI

    Incorrect instruction in the README about run using CLI

    When copy the sample.json to input using "cp ../input/example/sample.json ./input", it will copy the json as a file but not in input directory as there is no "input" folder. Fix it by create "input" directory explicitly before copying the json sample.

    opened by edwinkcw 1
  • Add AUTOINCREMENT option

    Add AUTOINCREMENT option

    Is there any chance you will add an autoincrement option for the primary key generation? It would be very useful when handling entities without a unique identificator, as it would generate it automatically.

    opened by frapontillo 1
  • Tables with AUTOINCREMENT IDs  have SQL syntax error in bulk insert statements

    Tables with AUTOINCREMENT IDs have SQL syntax error in bulk insert statements

            static String getBulkInsertString() {
                return new StringBuilder("INSERT INTO ")
                                         .append(TABLE_NAME).append(" ( ").append(",")
                                         .append(Columns.X.getName()).append(", ")
                                         .append(Columns.Y.getName())
                                         .append(" ) VALUES (, ?, ?)").toString();
            }
    

    which results in

    android.database.sqlite.SQLiteException: near ",": syntax error: , while compiling: INSERT INTO routePoint ( , lat, lon ) VALUES (, ?, ?)
    

    It should probably produce:

            static String getBulkInsertString() {
                return new StringBuilder("INSERT INTO ")
                                         .append(TABLE_NAME).append(" ( ")
                                         .append(Columns.X.getName()).append(", ")
                                         .append(Columns.Y.getName())
                                         .append(" ) VALUES (?, ?)").toString();
            }
    
    opened by peterschwarz 0
  • DB cache issues for non-parametrized ID queries

    DB cache issues for non-parametrized ID queries

    The generated provider has the whereWithId method that is used by single-entities queries such as query, update, delete. If a huge number of queries is executed on slow devices (I am using a Nexus One for testing purposes) a warning such as the following can be issued:

    Reached MAX size for compiled-sql statement cache for database <nameofdatabase>; i.e., 
    NO space for this sql statement in cache: 
    SELECT COLUMN_NAME FROM TABLE_NAME WHERE _ID = '1337'. 
    Please change your sql statements to use '?' for bindargs, instead of using actual values
    

    This can be solved by using the _ID column as a parameter. I have fixed this in my fork, I will make a pull request asap.

    opened by frapontillo 0
  • Add the option to define ContentProvider authority thorugh a string resource

    Add the option to define ContentProvider authority thorugh a string resource

    All that will be needed is to defer constant init until the content provider's creation, so we have a context to get the authority from a string resource

    This will be useful when you need to define a content provider for a debug or for a release build. or any build variant if you are using gradle

    opened by suarezjulian 1
  • Insert to replace

    Insert to replace

    First, I'd like to say great work.

    I have a suggestion:

    I think you should change the insert function from

    id = db.insert(uriType.getTableName(), "foo", values);

    to

    id = db.replace(uriType.getTableName(), "foo", values);

    This means, as a developer, you no longer need to query the table if the record exists or not to decide weather to do an update or an insert.

    This works great with DataDroid bulk operations

    Thanks

    opened by selfeky 0
  • null check for all DB type in bindValuesInBulkInsert

    null check for all DB type in bindValuesInBulkInsert

    Hi,

    First of all, thanks for this awesome tool ;) I think we should do a null check in bindValuesInBulkInsert for every DB type, not only String. Because as stated in the documentation for getAsLong for instance:

    Returns the Long value, or null if the value is missing or cannot be converted

    In my case, I do not set a value in every column when inserting new rows using a bulkInsert and it yield a NPE. I think there will be a special case for the _id column. If we haven't set a value for _id we shouldn't set a default one and instead let the system auto_increment this column. Something like:

    Long longValue = values.getAsLong(Columns.ID.getName());
    if(longValue != null)
        stmt.bindLong(i++, longValue);
    else
        i++;
    

    Or, more compact

    Long longValue = values.getAsLong(Columns.ID.getName());
    if(longValue != null)
        stmt.bindLong(i, longValue);
    i++;
    

    What do you think?

    opened by florianmski 1
Owner
Foxykeep
Foxykeep
Mirai-device-generator - Mirai Device Generator with kotlin

Mirai Device Generator Mirai DeviceInfo 生成器 作为插件运行时会提供 BotConfigurationAlterer 服

cssxsh 46 Jan 1, 2023
A Java Code Generator for Pojo Builders

PojoBuilder - A Code Generator for Pojo Builders Author: Michael Karneim Project Homepage: http://github.com/mkarneim/pojobuilder About The PojoBuilde

Michael Karneim 330 Dec 11, 2022
Bad Apple!! AA Generator

BadAppleK Bad Apple!! ASCII Art Generator for macOS Terminal. Youtube: https://www.youtube.com/watch?v=Iv8jbo4KDFo How to execute on your environment.

kuu(Fumiya Kume) 18 Jul 25, 2022
StoryGen - A simple story generator (or it will be eventually) to learn Kotlin

StoryGen A simple story generator (or it will be eventually) to learn Kotlin. To

Markus Reinke 0 Jan 7, 2022
:package: Android Parcelables made easy through code generation.

Parceler Have a question? Ask it on StackOverflow. Found an issue? Please report it. In Android, Parcelables are a great way to serialize Java Objects

John Ericksen 3.6k Dec 27, 2022
A custom view styling library for Android that generates the obtainStyledAttributes() and TypedArray boilerplate code for you.

DEPRECATED This project is no longer maintained. Consider using https://github.com/airbnb/paris Barber Barber is your personal custom view stylist. Si

Zac Sweers 716 Dec 30, 2022
Codegeneration tool for isomorphic server and mobile Go apps with gRPC & Protobuf. Share code between your backend, Android & iOS app! :sun_with_face:

Anakin Codegeneration tool for isomorphic server and mobile Go apps with gRPC & Protobuf. Share code between your backend, Android & iOS app! Descript

Kirill Biakov 17 Jun 25, 2020
A small tool to help you generate android projects that have a base code.

Volt Project A small tool to help you generate android projects that have a base code. Usage Change project in base directory. python volt-gen.py <pac

Victor Varenik 3 Feb 2, 2022
Annotation Processor for generating Parcelable code

ParcelablePlease An AnnotationProcessor for generating Android Parcelable boilerplate code. See this blog entry for comparison with other parcel libra

Hannes Dorfmann 260 Mar 31, 2022
Kotlin code generation for commercetools platform type-safe product-types, reference expansion and custom fields

Kotlin code generation for commercetools platform type-safe product-types, reference expansion and custom fields

null 8 Dec 15, 2022
Android Parcelable models made easy

AutoParcel AutoParcel is an AutoValue extension that enables Parcelable values generation. Just add implements Parcelable to your @AutoValue annotated

Francesco Sardo 1.4k Dec 23, 2022
A tool to generate Android ContentProviders.

Android ContentProvider Generator (acpg) A tool to generate Android ContentProviders. It takes a set of entity (a.k.a "table") definitions as the inpu

Benoit Lubek 623 Dec 13, 2022
A easy way to use android sharepreference

Favor A easy way of using Android SharedPreferences. How to use this library Using Gradle compile 'com.cocosw:favor:0.2.0@aar' Using Maven <depend

Kai Liao 467 Nov 10, 2022
Android 注解自动生成与 Flutter 通信的代码

Android-Flutter-Annotation 用于 Android 端项目,通过使用注解自动生成与 Flutter 通信的代码。 可生成的三种通信渠道有: MethodChannel EventChannel BasicMessageChannel 集成 在项目的 build.gradle

JOYY UED 4 Nov 1, 2021
Pure Java code generation tool for generating a fully functional ContentProvider for Android.

RoboCoP RoboCoP is a Java library that can generate a fully-functional ContentProvider from a simple JSON schema file. Get the latest version from our

Rain 246 Dec 29, 2022
AndroidQuery is an Android ORM for SQLite and ContentProvider which focuses on easy of use and performances thanks to annotation processing and code generation

WARNING: now that Room is out, I no longer maintain that library. If you need a library to easy access to default android ContentProvider, I would may

Frédéric Julian 19 Dec 11, 2021
Mirai-device-generator - Mirai Device Generator with kotlin

Mirai Device Generator Mirai DeviceInfo 生成器 作为插件运行时会提供 BotConfigurationAlterer 服

cssxsh 46 Jan 1, 2023
A Java Code Generator for Pojo Builders

PojoBuilder - A Code Generator for Pojo Builders Author: Michael Karneim Project Homepage: http://github.com/mkarneim/pojobuilder About The PojoBuilde

Michael Karneim 330 Dec 11, 2022
Exposed spring integration and code generator for dsl interface

Infra-ORM 欢迎使用 Infra-ORM, 这是一个基于 Exposed 的 ORM 框架,可以和 Spring Boot 集成良好,如果你是 Kotlin 开发者,推荐你试试 Exposed, 配合 Infra-ORM 可以给你带来最佳的开发体验。 为什么造这个轮子? Exposed 提供

Red Sparrow 1 Jan 2, 2022
Auto-pipeline: a source code generator, it will generate your component's pipeline

auto-pipeline ?? auto-pipeline is a source code generator, it will generate your

Zava 106 Dec 20, 2022