From 8f838553490c21d88869e2652521b2ad33d156e9 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 23 Apr 2015 20:22:18 -0700 Subject: [PATCH 01/26] Add skeleton code for automatic annotation processing Add preliminary code that will eventually replace table config files with a class containing inline code to build the data structures that is generated automatically when the annotated client code is compiled. --- pom.xml | 18 + .../apptools/OrmLiteAnnotationProcessor.java | 447 ++++++++++++++++++ .../javax.annotation.processing.Processor | 1 + .../templates/OrmLiteSqliteOpenHelper.java | 307 ++++++++++++ 4 files changed, 773 insertions(+) create mode 100644 src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java create mode 100644 src/main/resources/META-INF/services/javax.annotation.processing.Processor create mode 100644 src/main/resources/templates/OrmLiteSqliteOpenHelper.java diff --git a/pom.xml b/pom.xml index 89c87e6b..c2f7339e 100644 --- a/pom.xml +++ b/pom.xml @@ -146,6 +146,24 @@ 1.5 1.5 + + + default-compile + + -proc:none + + com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java + + + + + compile-everything-else + compile + + compile + + + org.apache.maven.plugins diff --git a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java new file mode 100644 index 00000000..04f6f99a --- /dev/null +++ b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java @@ -0,0 +1,447 @@ +package com.j256.ormlite.android.apptools; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.SourceVersion; +import javax.tools.JavaFileObject; + +//TODO: handle ForeignCollectionField annotations +//TODO: handle javax.persistance annotations +//TODO: add note that this must be updated to Annotation classes +//TODO: analyze if this should be part of core (and if config file stuff can be removed) +//TODO: make sure no generated code is added to ormlite.android jar +//TODO: add error messages +//TODO: use cleaner resource loading code + +/** + * Class that is automatically run when compiling client code that automatically + * generates an OrmLiteSqliteOpenHelper class that has inline code to generate + * the arguments for DaoManager.addCachedDatabaseConfigs() without needing a + * config file. + * + * @author nathancrouther + */ +// TODO: understand this +@SuppressWarnings("restriction") +public final class OrmLiteAnnotationProcessor extends AbstractProcessor { + + static final class TableModel { + String fullyQualifiedClassName; + String simpleClassName; + DatabaseTable annotation; + List fields = new ArrayList(); + } + + static final class FieldModel { + String fullyQualifiedTypeName; + String fieldName; + DatabaseField annotation; + } + + static final class AnnotationFileWriter { + private AnnotationFileWriter() { + } + + private static final List templateLinesBefore = new ArrayList(); + private static final List templateLinesAfter = new ArrayList(); + + static { + InputStreamReader reader; + try { + reader = new InputStreamReader(new FileInputStream( + AnnotationFileWriter.class.getResource( + "template/OrmLiteSqliteOpenHelper.java") + .getFile()), StandardCharsets.UTF_8); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + BufferedReader br = new BufferedReader(reader); + try { + boolean pastInsertionPoint = false; + String line; + while ((line = br.readLine()) != null) { + if (line.trim() + .equals("//********** GENERATED CODE INSERTED HERE **********//")) { + pastInsertionPoint = true; + } else if (pastInsertionPoint) { + templateLinesAfter.add(line); + } else { + templateLinesBefore.add(line); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + try { + br.close(); + } catch (IOException e) { + } + } + } + + static void writeHeader(Writer writer) throws IOException { + for (String line : templateLinesBefore) { + writer.write(line); + writer.write("\n"); + } + writer.write("\t\t\tList> databaseTableConfigs = new ArrayList>();\n"); + } + + static void writeTable(Writer writer, TableModel table) + throws IOException { + writer.write("\t\t\t{\n"); + writer.write("\t\t\t\tList databaseFieldConfigs = new ArrayList();\n"); + for (FieldModel field : table.fields) { + + if (!field.annotation.persisted()) { + continue; + } + + writer.write("\t\t\t\t{\n"); + writer.write(String + .format("\t\t\t\t\tDatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig(\"%s\")", + field.fieldName)); + + if (!field.annotation.columnName().equals( + getDefaultAnnotationValue(field, "columnName"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setColumnName(\"%s\");", + field.annotation.columnName())); + } + + if (!field.annotation.dataType().equals( + getDefaultAnnotationValue(field, "dataType"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setDataType(DataType.%s);", + field.annotation.dataType().toString())); + } + + if (!field.annotation.defaultValue().equals( + getDefaultAnnotationValue(field, "defaultValue"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setDefaultValue(\"%s\");", + field.annotation.defaultValue())); + } + + if (Integer.valueOf(field.annotation.width()).equals( + getDefaultAnnotationValue(field, "width"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setWidth(%d);", + field.annotation.width())); + } + + if (Boolean.valueOf(field.annotation.canBeNull()).equals( + getDefaultAnnotationValue(field, "canBeNull"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setCanBeNull(%b);", + field.annotation.canBeNull())); + } + + if (Boolean.valueOf(field.annotation.id()).equals( + getDefaultAnnotationValue(field, "id"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setId(%b);", + field.annotation.id())); + } + + if (Boolean.valueOf(field.annotation.generatedId()).equals( + getDefaultAnnotationValue(field, "generatedId"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setGeneratedId(%b);", + field.annotation.generatedId())); + } + + if (!field.annotation.generatedIdSequence() + .equals(getDefaultAnnotationValue(field, + "generatedIdSequence"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setGeneratedIdSequence(\"%s\");", + field.annotation.generatedIdSequence())); + } + + if (Boolean.valueOf(field.annotation.foreign()).equals( + getDefaultAnnotationValue(field, "foreign"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setForeign(%b);", + field.annotation.foreign())); + } + + if (Boolean.valueOf(field.annotation.useGetSet()).equals( + getDefaultAnnotationValue(field, "useGetSet"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setUseGetSet(%b);", + field.annotation.useGetSet())); + } + + if (!field.annotation.unknownEnumName().equals( + getDefaultAnnotationValue(field, "unknownEnumName"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setUnknownEnumName(%s.%s);", + field.fullyQualifiedTypeName, + field.annotation.unknownEnumName())); + } + + if (Boolean.valueOf(field.annotation.throwIfNull()).equals( + getDefaultAnnotationValue(field, "throwIfNull"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setThrowIfNull(%b);", + field.annotation.throwIfNull())); + } + + if (!field.annotation.format().equals( + getDefaultAnnotationValue(field, "format"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setFormat(\"%s\");", + field.annotation.format())); + } + + if (Boolean.valueOf(field.annotation.unique()).equals( + getDefaultAnnotationValue(field, "unique"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setUnique(%b);", + field.annotation.unique())); + } + + if (Boolean.valueOf(field.annotation.uniqueCombo()).equals( + getDefaultAnnotationValue(field, "uniqueCombo"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setUniqueCombo(%b);", + field.annotation.uniqueCombo())); + } + + if (Boolean.valueOf(field.annotation.index()).equals( + getDefaultAnnotationValue(field, "index"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setIndex(%b);", + field.annotation.index())); + } + + if (Boolean.valueOf(field.annotation.uniqueIndex()).equals( + getDefaultAnnotationValue(field, "uniqueIndex"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setUniqueIndex(%b);", + field.annotation.uniqueIndex())); + } + + if (!field.annotation.indexName().equals( + getDefaultAnnotationValue(field, "indexName"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setIndexName(\"%s\");", + field.annotation.indexName())); + } + + if (!field.annotation.uniqueIndexName().equals( + getDefaultAnnotationValue(field, "uniqueIndexName"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setUniqueIndexName(\"%s\");", + field.annotation.uniqueIndexName())); + } + + if (Boolean.valueOf(field.annotation.foreignAutoRefresh()) + .equals(getDefaultAnnotationValue(field, + "foreignAutoRefresh"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setForeignAutoRefresh(%b);", + field.annotation.foreignAutoRefresh())); + } + + if (Integer.valueOf( + field.annotation.maxForeignAutoRefreshLevel()).equals( + getDefaultAnnotationValue(field, + "maxForeignAutoRefreshLevel"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setMaxForeignAutoRefreshLevel(%d);", + field.annotation + .maxForeignAutoRefreshLevel())); + } + + if (!field.annotation.persisterClass().equals( + getDefaultAnnotationValue(field, "persisterClass"))) { + writer.write(String + .format("\t\t\t\t\t\ttdatabaseFieldConfig.setPersisterClass(%s.class);\n", + field.annotation.persisterClass() + .getCanonicalName())); + } + + if (Boolean.valueOf(field.annotation.allowGeneratedIdInsert()) + .equals(getDefaultAnnotationValue(field, + "allowGeneratedIdInsert"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setAllowGeneratedIdInsert(%b);", + field.annotation.allowGeneratedIdInsert())); + } + + if (!field.annotation.columnDefinition().equals( + getDefaultAnnotationValue(field, "columnDefinition"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setColumnDefinition(\"%s\");", + field.annotation.columnDefinition())); + } + + if (Boolean.valueOf(field.annotation.foreignAutoCreate()) + .equals(getDefaultAnnotationValue(field, + "foreignAutoCreate"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setForeignAutoCreate(%b);", + field.annotation.foreignAutoCreate())); + } + + if (Boolean.valueOf(field.annotation.version()).equals( + getDefaultAnnotationValue(field, "version"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setVersion(%b);", + field.annotation.version())); + } + + if (!field.annotation.foreignColumnName().equals( + getDefaultAnnotationValue(field, "foreignColumnName"))) { + writer.write(String + .format("\t\t\t\t\tdatabaseFieldConfig.setForeignColumnName(\"%s\");", + field.annotation.foreignColumnName())); + } + + if (Boolean.valueOf(field.annotation.readOnly()).equals( + getDefaultAnnotationValue(field, "readOnly"))) { + writer.write(String.format( + "\t\t\t\t\tdatabaseFieldConfig.setReadOnly(%b);", + field.annotation.readOnly())); + } + + writer.write("\t\t\t\t\tdatabaseFieldConfigs.add(databaseFieldConfig);\n"); + writer.write("\t\t\t\t}\n"); + } + + String tableName; + if (table.annotation.tableName() != null + && table.annotation.tableName().length() > 0) { + tableName = table.annotation.tableName(); + } else { + tableName = table.simpleClassName.toLowerCase(); + } + + writer.write(String + .format("\t\t\t\tdatabaseTableConfigs.add(new DatabaseTableConfig(%s.class, \"%s\", databaseFieldConfigs));\n", + table.fullyQualifiedClassName, tableName)); + writer.write("\t\t\t}\n"); + } + + private static Object getDefaultAnnotationValue(FieldModel field, + String name) { + try { + return field.annotation.annotationType().getMethod(name) + .getDefaultValue(); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (SecurityException e) { + throw new RuntimeException(e); + } + } + + static void writeFooter(Writer writer) throws IOException { + writer.write("\t\t\tDaoManager.addCachedDatabaseConfigs(databaseTableConfigs);\n"); + for (String line : templateLinesAfter) { + writer.write(line); + writer.write("\n"); + } + } + } + + @Override + public Set getSupportedAnnotationTypes() { + Set types = new LinkedHashSet(); + types.add(DatabaseTable.class.getCanonicalName()); + return types; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + @Override + public boolean process(Set elements, + RoundEnvironment env) { + List tables = new ArrayList(); + + for (Element element : env + .getElementsAnnotatedWith(DatabaseTable.class)) { + TypeElement tableClassElement = (TypeElement) element; + + TableModel table = new TableModel(); + table.fullyQualifiedClassName = tableClassElement + .getQualifiedName().toString(); + table.simpleClassName = tableClassElement.getSimpleName() + .toString(); + table.annotation = tableClassElement + .getAnnotation(DatabaseTable.class); + + // get all fields from this and all parents until we hit Object + do { + for (Element child : tableClassElement.getEnclosedElements()) { + if (child.getKind().isField()) { + DatabaseField databaseField = child + .getAnnotation(DatabaseField.class); + if (databaseField != null) { + TypeElement fieldClassElement = (TypeElement) processingEnv + .getTypeUtils().asElement(child.asType()); + + FieldModel field = new FieldModel(); + field.fullyQualifiedTypeName = fieldClassElement + .getQualifiedName().toString(); + field.fieldName = child.getSimpleName().toString(); + field.annotation = databaseField; + table.fields.add(field); + } + } + } + + tableClassElement = (TypeElement) processingEnv.getTypeUtils() + .asElement(tableClassElement.getSuperclass()); + } while (!tableClassElement.getQualifiedName().toString() + .equals("java.lang.Object")); + } + + createSourceFile(tables); + return true; + } + + private void createSourceFile(List tables) { + try { + JavaFileObject javaFileObject = processingEnv + .getFiler() + .createSourceFile( + "com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelperAutomatic"); //TODO + try { + Writer writer = javaFileObject.openWriter(); + try { + AnnotationFileWriter.writeHeader(writer); + for (TableModel table : tables) { + AnnotationFileWriter.writeTable(writer, table); + } + AnnotationFileWriter.writeFooter(writer); + } finally { + writer.close(); + } + } catch (IOException ex) { + } + } catch (IOException e) { + } + } +} diff --git a/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000..a7f6ca1e --- /dev/null +++ b/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor diff --git a/src/main/resources/templates/OrmLiteSqliteOpenHelper.java b/src/main/resources/templates/OrmLiteSqliteOpenHelper.java new file mode 100644 index 00000000..48ae6375 --- /dev/null +++ b/src/main/resources/templates/OrmLiteSqliteOpenHelper.java @@ -0,0 +1,307 @@ +package com.j256.ormlite.android.apptools; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.sql.SQLException; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.database.sqlite.SQLiteOpenHelper; + +import com.j256.ormlite.android.AndroidConnectionSource; +import com.j256.ormlite.android.AndroidDatabaseConnection; +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.dao.RuntimeExceptionDao; +import com.j256.ormlite.logger.Logger; +import com.j256.ormlite.logger.LoggerFactory; +import com.j256.ormlite.misc.IOUtils; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.support.DatabaseConnection; +import com.j256.ormlite.table.DatabaseTableConfigLoader; + +/** + * SQLite database open helper which can be extended by your application to help manage when the application needs to + * create or upgrade its database. + * + * @author kevingalligan, graywatson + */ +public abstract class OrmLiteSqliteOpenHelper extends SQLiteOpenHelper { + + protected static Logger logger = LoggerFactory.getLogger(OrmLiteSqliteOpenHelper.class); + protected AndroidConnectionSource connectionSource = new AndroidConnectionSource(this); + + protected boolean cancelQueriesEnabled; + private volatile boolean isOpen = true; + + /** + * @param context + * Associated content from the application. This is needed to locate the database. + * @param databaseName + * Name of the database we are opening. + * @param factory + * Cursor factory or null if none. + * @param databaseVersion + * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be + * called if the stored database is a different version. + */ + public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { + super(context, databaseName, factory, databaseVersion); + logger.trace("{}: constructed connectionSource {}", this, connectionSource); + + //********** GENERATED CODE INSERTED HERE **********// + } + + /** + * Same as the other constructor with the addition of a file-id of the table config-file. See + * {@link OrmLiteConfigUtil} for details. + * + * @deprecated Table config files are no longer used since now the annotation processor + * generates equivalent information automatically. + * + * @param context + * Associated content from the application. This is needed to locate the database. + * @param databaseName + * Name of the database we are opening. + * @param factory + * Cursor factory or null if none. + * @param databaseVersion + * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be + * called if the stored database is a different version. + * @param configFileId + * file-id which probably should be a R.raw.ormlite_config.txt or some static value. + */ + @Deprecated + public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion, + int configFileId) { + this(context, databaseName, factory, databaseVersion); + } + + /** + * Same as the other constructor with the addition of a config-file. See {@link OrmLiteConfigUtil} for details. + * + * @deprecated Table config files are no longer used since now the annotation processor + * generates equivalent information automatically. + * + * @param context + * Associated content from the application. This is needed to locate the database. + * @param databaseName + * Name of the database we are opening. + * @param factory + * Cursor factory or null if none. + * @param databaseVersion + * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be + * called if the stored database is a different version. + * @param configFile + * Configuration file to be loaded. + */ + @Deprecated + public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion, + File configFile) { + this(context, databaseName, factory, databaseVersion); + } + + /** + * Same as the other constructor with the addition of a input stream to the table config-file. See + * {@link OrmLiteConfigUtil} for details. + * + * @deprecated Table config files are no longer used since now the annotation processor + * generates equivalent information automatically. + * + * @param context + * Associated content from the application. This is needed to locate the database. + * @param databaseName + * Name of the database we are opening. + * @param factory + * Cursor factory or null if none. + * @param databaseVersion + * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be + * called if the stored database is a different version. + * @param stream + * Stream opened to the configuration file to be loaded. It will be closed when this method returns. + */ + @Deprecated + public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion, + InputStream stream) { + this(context, databaseName, factory, databaseVersion); + if (stream != null) { + IOUtils.closeQuietly(stream); + } + } + + /** + * What to do when your database needs to be created. Usually this entails creating the tables and loading any + * initial data. + * + *

+ * NOTE: You should use the connectionSource argument that is passed into this method call or the one + * returned by getConnectionSource(). If you use your own, a recursive call or other unexpected results may result. + *

+ * + * @param database + * Database being created. + * @param connectionSource + * To use get connections to the database to be created. + */ + public abstract void onCreate(SQLiteDatabase database, ConnectionSource connectionSource); + + /** + * What to do when your database needs to be updated. This could mean careful migration of old data to new data. + * Maybe adding or deleting database columns, etc.. + * + *

+ * NOTE: You should use the connectionSource argument that is passed into this method call or the one + * returned by getConnectionSource(). If you use your own, a recursive call or other unexpected results may result. + *

+ * + * @param database + * Database being upgraded. + * @param connectionSource + * To use get connections to the database to be updated. + * @param oldVersion + * The version of the current database so we can know what to do to the database. + * @param newVersion + * The version that we are upgrading the database to. + */ + public abstract void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, + int newVersion); + + /** + * Get the connection source associated with the helper. + */ + public ConnectionSource getConnectionSource() { + if (!isOpen) { + // we don't throw this exception, but log it for debugging purposes + logger.warn(new IllegalStateException(), "Getting connectionSource was called after closed"); + } + return connectionSource; + } + + /** + * Satisfies the {@link SQLiteOpenHelper#onCreate(SQLiteDatabase)} interface method. + */ + @Override + public final void onCreate(SQLiteDatabase db) { + ConnectionSource cs = getConnectionSource(); + /* + * The method is called by Android database helper's get-database calls when Android detects that we need to + * create or update the database. So we have to use the database argument and save a connection to it on the + * AndroidConnectionSource, otherwise it will go recursive if the subclass calls getConnectionSource(). + */ + DatabaseConnection conn = cs.getSpecialConnection(); + boolean clearSpecial = false; + if (conn == null) { + conn = new AndroidDatabaseConnection(db, true, cancelQueriesEnabled); + try { + cs.saveSpecialConnection(conn); + clearSpecial = true; + } catch (SQLException e) { + throw new IllegalStateException("Could not save special connection", e); + } + } + try { + onCreate(db, cs); + } finally { + if (clearSpecial) { + cs.clearSpecialConnection(conn); + } + } + } + + /** + * Satisfies the {@link SQLiteOpenHelper#onUpgrade(SQLiteDatabase, int, int)} interface method. + */ + @Override + public final void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + ConnectionSource cs = getConnectionSource(); + /* + * The method is called by Android database helper's get-database calls when Android detects that we need to + * create or update the database. So we have to use the database argument and save a connection to it on the + * AndroidConnectionSource, otherwise it will go recursive if the subclass calls getConnectionSource(). + */ + DatabaseConnection conn = cs.getSpecialConnection(); + boolean clearSpecial = false; + if (conn == null) { + conn = new AndroidDatabaseConnection(db, true, cancelQueriesEnabled); + try { + cs.saveSpecialConnection(conn); + clearSpecial = true; + } catch (SQLException e) { + throw new IllegalStateException("Could not save special connection", e); + } + } + try { + onUpgrade(db, cs, oldVersion, newVersion); + } finally { + if (clearSpecial) { + cs.clearSpecialConnection(conn); + } + } + } + + /** + * Close any open connections. + */ + @Override + public void close() { + super.close(); + connectionSource.close(); + /* + * We used to set connectionSource to null here but now we just set the closed flag and then log heavily if + * someone uses getConectionSource() after this point. + */ + isOpen = false; + } + + /** + * Return true if the helper is still open. Once {@link #close()} is called then this will return false. + */ + public boolean isOpen() { + return isOpen; + } + + /** + * Get a DAO for our class. This uses the {@link DaoManager} to cache the DAO for future gets. + * + *

+ * NOTE: This routing does not return Dao<T, ID> because of casting issues if we are assigning it to a custom DAO. + * Grumble. + *

+ */ + public , T> D getDao(Class clazz) throws SQLException { + // special reflection fu is now handled internally by create dao calling the database type + Dao dao = DaoManager.createDao(getConnectionSource(), clazz); + @SuppressWarnings("unchecked") + D castDao = (D) dao; + return castDao; + } + + /** + * Get a RuntimeExceptionDao for our class. This uses the {@link DaoManager} to cache the DAO for future gets. + * + *

+ * NOTE: This routing does not return RuntimeExceptionDao<T, ID> because of casting issues if we are assigning it to + * a custom DAO. Grumble. + *

+ */ + public , T> D getRuntimeExceptionDao(Class clazz) { + try { + Dao dao = getDao(clazz); + @SuppressWarnings({ "unchecked", "rawtypes" }) + D castDao = (D) new RuntimeExceptionDao(dao); + return castDao; + } catch (SQLException e) { + throw new RuntimeException("Could not create RuntimeExcepitionDao for class " + clazz, e); + } + } + + @Override + public String toString() { + return getClass().getSimpleName() + "@" + Integer.toHexString(super.hashCode()); + } +} From 0bb58f96727d0ac35410940642a8275cb5d3dfbd Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 27 Apr 2015 19:40:35 -0700 Subject: [PATCH 02/26] Make a separate file for each table Since the javac compiler does multiple passes over the source code and calls process once each pass, it is better to create a separate file for each class. --- .../apptools/OrmLiteAnnotationProcessor.java | 627 ++++++++---------- .../templates/OrmLiteSqliteOpenHelper.java | 307 --------- 2 files changed, 289 insertions(+), 645 deletions(-) delete mode 100644 src/main/resources/templates/OrmLiteSqliteOpenHelper.java diff --git a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java index 04f6f99a..d6157f5f 100644 --- a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java @@ -1,15 +1,11 @@ package com.j256.ormlite.android.apptools; +import com.j256.ormlite.field.DataPersister; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStreamReader; import java.io.Writer; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; @@ -20,15 +16,16 @@ import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.SourceVersion; +import javax.lang.model.type.MirroredTypeException; +import javax.lang.model.type.TypeMirror; import javax.tools.JavaFileObject; //TODO: handle ForeignCollectionField annotations //TODO: handle javax.persistance annotations //TODO: add note that this must be updated to Annotation classes //TODO: analyze if this should be part of core (and if config file stuff can be removed) -//TODO: make sure no generated code is added to ormlite.android jar +//TODO: make sure no generated code is added to ormlite.android jar (and optimize pom) //TODO: add error messages -//TODO: use cleaner resource loading code /** * Class that is automatically run when compiling client code that automatically @@ -41,6 +38,8 @@ // TODO: understand this @SuppressWarnings("restriction") public final class OrmLiteAnnotationProcessor extends AbstractProcessor { + private static final String PACKAGE = "com.j256.ormlite.android.apptools.tableconfigs"; + private static final String SUFFIX = "Config"; static final class TableModel { String fullyQualifiedClassName; @@ -55,314 +54,6 @@ static final class FieldModel { DatabaseField annotation; } - static final class AnnotationFileWriter { - private AnnotationFileWriter() { - } - - private static final List templateLinesBefore = new ArrayList(); - private static final List templateLinesAfter = new ArrayList(); - - static { - InputStreamReader reader; - try { - reader = new InputStreamReader(new FileInputStream( - AnnotationFileWriter.class.getResource( - "template/OrmLiteSqliteOpenHelper.java") - .getFile()), StandardCharsets.UTF_8); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - BufferedReader br = new BufferedReader(reader); - try { - boolean pastInsertionPoint = false; - String line; - while ((line = br.readLine()) != null) { - if (line.trim() - .equals("//********** GENERATED CODE INSERTED HERE **********//")) { - pastInsertionPoint = true; - } else if (pastInsertionPoint) { - templateLinesAfter.add(line); - } else { - templateLinesBefore.add(line); - } - } - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - try { - br.close(); - } catch (IOException e) { - } - } - } - - static void writeHeader(Writer writer) throws IOException { - for (String line : templateLinesBefore) { - writer.write(line); - writer.write("\n"); - } - writer.write("\t\t\tList> databaseTableConfigs = new ArrayList>();\n"); - } - - static void writeTable(Writer writer, TableModel table) - throws IOException { - writer.write("\t\t\t{\n"); - writer.write("\t\t\t\tList databaseFieldConfigs = new ArrayList();\n"); - for (FieldModel field : table.fields) { - - if (!field.annotation.persisted()) { - continue; - } - - writer.write("\t\t\t\t{\n"); - writer.write(String - .format("\t\t\t\t\tDatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig(\"%s\")", - field.fieldName)); - - if (!field.annotation.columnName().equals( - getDefaultAnnotationValue(field, "columnName"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setColumnName(\"%s\");", - field.annotation.columnName())); - } - - if (!field.annotation.dataType().equals( - getDefaultAnnotationValue(field, "dataType"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setDataType(DataType.%s);", - field.annotation.dataType().toString())); - } - - if (!field.annotation.defaultValue().equals( - getDefaultAnnotationValue(field, "defaultValue"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setDefaultValue(\"%s\");", - field.annotation.defaultValue())); - } - - if (Integer.valueOf(field.annotation.width()).equals( - getDefaultAnnotationValue(field, "width"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setWidth(%d);", - field.annotation.width())); - } - - if (Boolean.valueOf(field.annotation.canBeNull()).equals( - getDefaultAnnotationValue(field, "canBeNull"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setCanBeNull(%b);", - field.annotation.canBeNull())); - } - - if (Boolean.valueOf(field.annotation.id()).equals( - getDefaultAnnotationValue(field, "id"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setId(%b);", - field.annotation.id())); - } - - if (Boolean.valueOf(field.annotation.generatedId()).equals( - getDefaultAnnotationValue(field, "generatedId"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setGeneratedId(%b);", - field.annotation.generatedId())); - } - - if (!field.annotation.generatedIdSequence() - .equals(getDefaultAnnotationValue(field, - "generatedIdSequence"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setGeneratedIdSequence(\"%s\");", - field.annotation.generatedIdSequence())); - } - - if (Boolean.valueOf(field.annotation.foreign()).equals( - getDefaultAnnotationValue(field, "foreign"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setForeign(%b);", - field.annotation.foreign())); - } - - if (Boolean.valueOf(field.annotation.useGetSet()).equals( - getDefaultAnnotationValue(field, "useGetSet"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setUseGetSet(%b);", - field.annotation.useGetSet())); - } - - if (!field.annotation.unknownEnumName().equals( - getDefaultAnnotationValue(field, "unknownEnumName"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setUnknownEnumName(%s.%s);", - field.fullyQualifiedTypeName, - field.annotation.unknownEnumName())); - } - - if (Boolean.valueOf(field.annotation.throwIfNull()).equals( - getDefaultAnnotationValue(field, "throwIfNull"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setThrowIfNull(%b);", - field.annotation.throwIfNull())); - } - - if (!field.annotation.format().equals( - getDefaultAnnotationValue(field, "format"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setFormat(\"%s\");", - field.annotation.format())); - } - - if (Boolean.valueOf(field.annotation.unique()).equals( - getDefaultAnnotationValue(field, "unique"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setUnique(%b);", - field.annotation.unique())); - } - - if (Boolean.valueOf(field.annotation.uniqueCombo()).equals( - getDefaultAnnotationValue(field, "uniqueCombo"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setUniqueCombo(%b);", - field.annotation.uniqueCombo())); - } - - if (Boolean.valueOf(field.annotation.index()).equals( - getDefaultAnnotationValue(field, "index"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setIndex(%b);", - field.annotation.index())); - } - - if (Boolean.valueOf(field.annotation.uniqueIndex()).equals( - getDefaultAnnotationValue(field, "uniqueIndex"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setUniqueIndex(%b);", - field.annotation.uniqueIndex())); - } - - if (!field.annotation.indexName().equals( - getDefaultAnnotationValue(field, "indexName"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setIndexName(\"%s\");", - field.annotation.indexName())); - } - - if (!field.annotation.uniqueIndexName().equals( - getDefaultAnnotationValue(field, "uniqueIndexName"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setUniqueIndexName(\"%s\");", - field.annotation.uniqueIndexName())); - } - - if (Boolean.valueOf(field.annotation.foreignAutoRefresh()) - .equals(getDefaultAnnotationValue(field, - "foreignAutoRefresh"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setForeignAutoRefresh(%b);", - field.annotation.foreignAutoRefresh())); - } - - if (Integer.valueOf( - field.annotation.maxForeignAutoRefreshLevel()).equals( - getDefaultAnnotationValue(field, - "maxForeignAutoRefreshLevel"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setMaxForeignAutoRefreshLevel(%d);", - field.annotation - .maxForeignAutoRefreshLevel())); - } - - if (!field.annotation.persisterClass().equals( - getDefaultAnnotationValue(field, "persisterClass"))) { - writer.write(String - .format("\t\t\t\t\t\ttdatabaseFieldConfig.setPersisterClass(%s.class);\n", - field.annotation.persisterClass() - .getCanonicalName())); - } - - if (Boolean.valueOf(field.annotation.allowGeneratedIdInsert()) - .equals(getDefaultAnnotationValue(field, - "allowGeneratedIdInsert"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setAllowGeneratedIdInsert(%b);", - field.annotation.allowGeneratedIdInsert())); - } - - if (!field.annotation.columnDefinition().equals( - getDefaultAnnotationValue(field, "columnDefinition"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setColumnDefinition(\"%s\");", - field.annotation.columnDefinition())); - } - - if (Boolean.valueOf(field.annotation.foreignAutoCreate()) - .equals(getDefaultAnnotationValue(field, - "foreignAutoCreate"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setForeignAutoCreate(%b);", - field.annotation.foreignAutoCreate())); - } - - if (Boolean.valueOf(field.annotation.version()).equals( - getDefaultAnnotationValue(field, "version"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setVersion(%b);", - field.annotation.version())); - } - - if (!field.annotation.foreignColumnName().equals( - getDefaultAnnotationValue(field, "foreignColumnName"))) { - writer.write(String - .format("\t\t\t\t\tdatabaseFieldConfig.setForeignColumnName(\"%s\");", - field.annotation.foreignColumnName())); - } - - if (Boolean.valueOf(field.annotation.readOnly()).equals( - getDefaultAnnotationValue(field, "readOnly"))) { - writer.write(String.format( - "\t\t\t\t\tdatabaseFieldConfig.setReadOnly(%b);", - field.annotation.readOnly())); - } - - writer.write("\t\t\t\t\tdatabaseFieldConfigs.add(databaseFieldConfig);\n"); - writer.write("\t\t\t\t}\n"); - } - - String tableName; - if (table.annotation.tableName() != null - && table.annotation.tableName().length() > 0) { - tableName = table.annotation.tableName(); - } else { - tableName = table.simpleClassName.toLowerCase(); - } - - writer.write(String - .format("\t\t\t\tdatabaseTableConfigs.add(new DatabaseTableConfig(%s.class, \"%s\", databaseFieldConfigs));\n", - table.fullyQualifiedClassName, tableName)); - writer.write("\t\t\t}\n"); - } - - private static Object getDefaultAnnotationValue(FieldModel field, - String name) { - try { - return field.annotation.annotationType().getMethod(name) - .getDefaultValue(); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (SecurityException e) { - throw new RuntimeException(e); - } - } - - static void writeFooter(Writer writer) throws IOException { - writer.write("\t\t\tDaoManager.addCachedDatabaseConfigs(databaseTableConfigs);\n"); - for (String line : templateLinesAfter) { - writer.write(line); - writer.write("\n"); - } - } - } - @Override public Set getSupportedAnnotationTypes() { Set types = new LinkedHashSet(); @@ -378,8 +69,6 @@ public SourceVersion getSupportedSourceVersion() { @Override public boolean process(Set elements, RoundEnvironment env) { - List tables = new ArrayList(); - for (Element element : env .getElementsAnnotatedWith(DatabaseTable.class)) { TypeElement tableClassElement = (TypeElement) element; @@ -399,12 +88,9 @@ public boolean process(Set elements, DatabaseField databaseField = child .getAnnotation(DatabaseField.class); if (databaseField != null) { - TypeElement fieldClassElement = (TypeElement) processingEnv - .getTypeUtils().asElement(child.asType()); - FieldModel field = new FieldModel(); - field.fullyQualifiedTypeName = fieldClassElement - .getQualifiedName().toString(); + field.fullyQualifiedTypeName = child.asType() + .toString(); field.fieldName = child.getSimpleName().toString(); field.annotation = databaseField; table.fields.add(field); @@ -416,32 +102,297 @@ public boolean process(Set elements, .asElement(tableClassElement.getSuperclass()); } while (!tableClassElement.getQualifiedName().toString() .equals("java.lang.Object")); + + createSourceFile(table); } - createSourceFile(tables); return true; } - private void createSourceFile(List tables) { + private void createSourceFile(TableModel table) { try { - JavaFileObject javaFileObject = processingEnv - .getFiler() + JavaFileObject javaFileObject = processingEnv.getFiler() .createSourceFile( - "com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelperAutomatic"); //TODO + PACKAGE + "." + table.simpleClassName + SUFFIX); + + Writer writer = javaFileObject.openWriter(); try { - Writer writer = javaFileObject.openWriter(); - try { - AnnotationFileWriter.writeHeader(writer); - for (TableModel table : tables) { - AnnotationFileWriter.writeTable(writer, table); - } - AnnotationFileWriter.writeFooter(writer); - } finally { - writer.close(); - } - } catch (IOException ex) { + writeTable(writer, table); + } finally { + writer.close(); } } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void writeTable(Writer writer, TableModel table) throws IOException { + writer.write("package " + PACKAGE + ";\n"); + writer.write("\n"); + writer.write("import java.util.ArrayList;\n"); + writer.write("import java.util.List;\n"); + writer.write("\n"); + writer.write("import com.j256.ormlite.field.DatabaseFieldConfig;\n"); + writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); + writer.write("\n"); + writer.write("public final class " + table.simpleClassName + SUFFIX + " {\n"); + writer.write("\tprivate " + table.simpleClassName + SUFFIX + "() {\n"); + writer.write("\t}\n"); + writer.write("\n"); + writer.write("\tpublic static final DatabaseTableConfig<" + + table.fullyQualifiedClassName + "> CONFIG;\n"); + writer.write("\n"); + writer.write("\tstatic {\n"); + writer.write("\t\tList databaseFieldConfigs = new ArrayList();\n"); + for (FieldModel field : table.fields) { + + if (!field.annotation.persisted()) { + continue; + } + + writer.write("\t\t{\n"); + writer.write(String + .format("\t\t\tDatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig(\"%s\");\n", + field.fieldName)); + + if (!field.annotation.columnName().equals( + getDefaultAnnotationValue(field, "columnName"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setColumnName(\"%s\");\n", + field.annotation.columnName())); + } + + if (!field.annotation.dataType().equals( + getDefaultAnnotationValue(field, "dataType"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setDataType(com.j256.ormlite.field.DataType.%s);\n", + field.annotation.dataType().toString())); + } + + if (!field.annotation.defaultValue().equals( + getDefaultAnnotationValue(field, "defaultValue"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setDefaultValue(\"%s\");\n", + field.annotation.defaultValue())); + } + + if (!Integer.valueOf(field.annotation.width()).equals( + getDefaultAnnotationValue(field, "width"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setWidth(%d);\n", + field.annotation.width())); + } + + if (!Boolean.valueOf(field.annotation.canBeNull()).equals( + getDefaultAnnotationValue(field, "canBeNull"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setCanBeNull(%b);\n", + field.annotation.canBeNull())); + } + + if (!Boolean.valueOf(field.annotation.id()).equals( + getDefaultAnnotationValue(field, "id"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setId(%b);\n", + field.annotation.id())); + } + + if (!Boolean.valueOf(field.annotation.generatedId()).equals( + getDefaultAnnotationValue(field, "generatedId"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setGeneratedId(%b);\n", + field.annotation.generatedId())); + } + + if (!field.annotation.generatedIdSequence().equals( + getDefaultAnnotationValue(field, "generatedIdSequence"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setGeneratedIdSequence(\"%s\");\n", + field.annotation.generatedIdSequence())); + } + + if (!Boolean.valueOf(field.annotation.foreign()).equals( + getDefaultAnnotationValue(field, "foreign"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setForeign(%b);\n", + field.annotation.foreign())); + } + + if (!Boolean.valueOf(field.annotation.useGetSet()).equals( + getDefaultAnnotationValue(field, "useGetSet"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setUseGetSet(%b);\n", + field.annotation.useGetSet())); + } + + if (!field.annotation.unknownEnumName().equals( + getDefaultAnnotationValue(field, "unknownEnumName"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setUnknownEnumName(%s.%s);\n", + field.fullyQualifiedTypeName, + field.annotation.unknownEnumName())); + } + + if (!Boolean.valueOf(field.annotation.throwIfNull()).equals( + getDefaultAnnotationValue(field, "throwIfNull"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setThrowIfNull(%b);\n", + field.annotation.throwIfNull())); + } + + if (!field.annotation.format().equals( + getDefaultAnnotationValue(field, "format"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setFormat(\"%s\");\n", + field.annotation.format())); + } + + if (!Boolean.valueOf(field.annotation.unique()).equals( + getDefaultAnnotationValue(field, "unique"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setUnique(%b);\n", + field.annotation.unique())); + } + + if (!Boolean.valueOf(field.annotation.uniqueCombo()).equals( + getDefaultAnnotationValue(field, "uniqueCombo"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setUniqueCombo(%b);\n", + field.annotation.uniqueCombo())); + } + + if (!Boolean.valueOf(field.annotation.index()).equals( + getDefaultAnnotationValue(field, "index"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setIndex(%b);\n", + field.annotation.index())); + } + + if (!Boolean.valueOf(field.annotation.uniqueIndex()).equals( + getDefaultAnnotationValue(field, "uniqueIndex"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setUniqueIndex(%b);\n", + field.annotation.uniqueIndex())); + } + + if (!field.annotation.indexName().equals( + getDefaultAnnotationValue(field, "indexName"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setIndexName(\"%s\");\n", + field.annotation.indexName())); + } + + if (!field.annotation.uniqueIndexName().equals( + getDefaultAnnotationValue(field, "uniqueIndexName"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setUniqueIndexName(\"%s\");\n", + field.annotation.uniqueIndexName())); + } + + if (!Boolean.valueOf(field.annotation.foreignAutoRefresh()).equals( + getDefaultAnnotationValue(field, "foreignAutoRefresh"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setForeignAutoRefresh(%b);\n", + field.annotation.foreignAutoRefresh())); + } + + if (!Integer.valueOf(field.annotation.maxForeignAutoRefreshLevel()) + .equals(getDefaultAnnotationValue(field, + "maxForeignAutoRefreshLevel"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setMaxForeignAutoRefreshLevel(%d);\n", + field.annotation.maxForeignAutoRefreshLevel())); + } + + TypeMirror persisterClassActual; + try { + field.annotation.persisterClass(); // this will throw + throw new RuntimeException("Failed to get TypeMirror"); + } catch (MirroredTypeException mte) { + persisterClassActual = mte.getTypeMirror(); + } + @SuppressWarnings("unchecked") + Class persisterClassDefault = (Class) getDefaultAnnotationValue( + field, "persisterClass"); + if (!persisterClassActual.toString().equals( + persisterClassDefault.getCanonicalName())) { + writer.write(String + .format("\t\t\t\tdatabaseFieldConfig.setPersisterClass(%s.class);\n", + persisterClassActual.toString())); + } + + if (!Boolean.valueOf(field.annotation.allowGeneratedIdInsert()) + .equals(getDefaultAnnotationValue(field, + "allowGeneratedIdInsert"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setAllowGeneratedIdInsert(%b);\n", + field.annotation.allowGeneratedIdInsert())); + } + + if (!field.annotation.columnDefinition().equals( + getDefaultAnnotationValue(field, "columnDefinition"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setColumnDefinition(\"%s\");\n", + field.annotation.columnDefinition())); + } + + if (!Boolean.valueOf(field.annotation.foreignAutoCreate()).equals( + getDefaultAnnotationValue(field, "foreignAutoCreate"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setForeignAutoCreate(%b);\n", + field.annotation.foreignAutoCreate())); + } + + if (!Boolean.valueOf(field.annotation.version()).equals( + getDefaultAnnotationValue(field, "version"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setVersion(%b);\n", + field.annotation.version())); + } + + if (!field.annotation.foreignColumnName().equals( + getDefaultAnnotationValue(field, "foreignColumnName"))) { + writer.write(String + .format("\t\t\tdatabaseFieldConfig.setForeignColumnName(\"%s\");\n", + field.annotation.foreignColumnName())); + } + + if (!Boolean.valueOf(field.annotation.readOnly()).equals( + getDefaultAnnotationValue(field, "readOnly"))) { + writer.write(String.format( + "\t\t\tdatabaseFieldConfig.setReadOnly(%b);\n", + field.annotation.readOnly())); + } + + writer.write("\t\t\tdatabaseFieldConfigs.add(databaseFieldConfig);\n"); + writer.write("\t\t}\n"); + } + + String tableName; + if (table.annotation.tableName() != null + && table.annotation.tableName().length() > 0) { + tableName = table.annotation.tableName(); + } else { + tableName = table.simpleClassName.toLowerCase(); + } + + writer.write(String + .format("\t\tCONFIG = new DatabaseTableConfig<%s>(%s.class, \"%s\", databaseFieldConfigs);\n", + table.fullyQualifiedClassName, + table.fullyQualifiedClassName, tableName)); + writer.write("\t}\n"); + writer.write("}\n"); + } + + private static Object getDefaultAnnotationValue(FieldModel field, + String name) { + try { + return field.annotation.annotationType().getMethod(name) + .getDefaultValue(); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (SecurityException e) { + throw new RuntimeException(e); } } } diff --git a/src/main/resources/templates/OrmLiteSqliteOpenHelper.java b/src/main/resources/templates/OrmLiteSqliteOpenHelper.java deleted file mode 100644 index 48ae6375..00000000 --- a/src/main/resources/templates/OrmLiteSqliteOpenHelper.java +++ /dev/null @@ -1,307 +0,0 @@ -package com.j256.ormlite.android.apptools; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.sql.SQLException; - -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteDatabase.CursorFactory; -import android.database.sqlite.SQLiteOpenHelper; - -import com.j256.ormlite.android.AndroidConnectionSource; -import com.j256.ormlite.android.AndroidDatabaseConnection; -import com.j256.ormlite.dao.Dao; -import com.j256.ormlite.dao.DaoManager; -import com.j256.ormlite.dao.RuntimeExceptionDao; -import com.j256.ormlite.logger.Logger; -import com.j256.ormlite.logger.LoggerFactory; -import com.j256.ormlite.misc.IOUtils; -import com.j256.ormlite.support.ConnectionSource; -import com.j256.ormlite.support.DatabaseConnection; -import com.j256.ormlite.table.DatabaseTableConfigLoader; - -/** - * SQLite database open helper which can be extended by your application to help manage when the application needs to - * create or upgrade its database. - * - * @author kevingalligan, graywatson - */ -public abstract class OrmLiteSqliteOpenHelper extends SQLiteOpenHelper { - - protected static Logger logger = LoggerFactory.getLogger(OrmLiteSqliteOpenHelper.class); - protected AndroidConnectionSource connectionSource = new AndroidConnectionSource(this); - - protected boolean cancelQueriesEnabled; - private volatile boolean isOpen = true; - - /** - * @param context - * Associated content from the application. This is needed to locate the database. - * @param databaseName - * Name of the database we are opening. - * @param factory - * Cursor factory or null if none. - * @param databaseVersion - * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be - * called if the stored database is a different version. - */ - public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { - super(context, databaseName, factory, databaseVersion); - logger.trace("{}: constructed connectionSource {}", this, connectionSource); - - //********** GENERATED CODE INSERTED HERE **********// - } - - /** - * Same as the other constructor with the addition of a file-id of the table config-file. See - * {@link OrmLiteConfigUtil} for details. - * - * @deprecated Table config files are no longer used since now the annotation processor - * generates equivalent information automatically. - * - * @param context - * Associated content from the application. This is needed to locate the database. - * @param databaseName - * Name of the database we are opening. - * @param factory - * Cursor factory or null if none. - * @param databaseVersion - * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be - * called if the stored database is a different version. - * @param configFileId - * file-id which probably should be a R.raw.ormlite_config.txt or some static value. - */ - @Deprecated - public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion, - int configFileId) { - this(context, databaseName, factory, databaseVersion); - } - - /** - * Same as the other constructor with the addition of a config-file. See {@link OrmLiteConfigUtil} for details. - * - * @deprecated Table config files are no longer used since now the annotation processor - * generates equivalent information automatically. - * - * @param context - * Associated content from the application. This is needed to locate the database. - * @param databaseName - * Name of the database we are opening. - * @param factory - * Cursor factory or null if none. - * @param databaseVersion - * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be - * called if the stored database is a different version. - * @param configFile - * Configuration file to be loaded. - */ - @Deprecated - public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion, - File configFile) { - this(context, databaseName, factory, databaseVersion); - } - - /** - * Same as the other constructor with the addition of a input stream to the table config-file. See - * {@link OrmLiteConfigUtil} for details. - * - * @deprecated Table config files are no longer used since now the annotation processor - * generates equivalent information automatically. - * - * @param context - * Associated content from the application. This is needed to locate the database. - * @param databaseName - * Name of the database we are opening. - * @param factory - * Cursor factory or null if none. - * @param databaseVersion - * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be - * called if the stored database is a different version. - * @param stream - * Stream opened to the configuration file to be loaded. It will be closed when this method returns. - */ - @Deprecated - public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion, - InputStream stream) { - this(context, databaseName, factory, databaseVersion); - if (stream != null) { - IOUtils.closeQuietly(stream); - } - } - - /** - * What to do when your database needs to be created. Usually this entails creating the tables and loading any - * initial data. - * - *

- * NOTE: You should use the connectionSource argument that is passed into this method call or the one - * returned by getConnectionSource(). If you use your own, a recursive call or other unexpected results may result. - *

- * - * @param database - * Database being created. - * @param connectionSource - * To use get connections to the database to be created. - */ - public abstract void onCreate(SQLiteDatabase database, ConnectionSource connectionSource); - - /** - * What to do when your database needs to be updated. This could mean careful migration of old data to new data. - * Maybe adding or deleting database columns, etc.. - * - *

- * NOTE: You should use the connectionSource argument that is passed into this method call or the one - * returned by getConnectionSource(). If you use your own, a recursive call or other unexpected results may result. - *

- * - * @param database - * Database being upgraded. - * @param connectionSource - * To use get connections to the database to be updated. - * @param oldVersion - * The version of the current database so we can know what to do to the database. - * @param newVersion - * The version that we are upgrading the database to. - */ - public abstract void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, - int newVersion); - - /** - * Get the connection source associated with the helper. - */ - public ConnectionSource getConnectionSource() { - if (!isOpen) { - // we don't throw this exception, but log it for debugging purposes - logger.warn(new IllegalStateException(), "Getting connectionSource was called after closed"); - } - return connectionSource; - } - - /** - * Satisfies the {@link SQLiteOpenHelper#onCreate(SQLiteDatabase)} interface method. - */ - @Override - public final void onCreate(SQLiteDatabase db) { - ConnectionSource cs = getConnectionSource(); - /* - * The method is called by Android database helper's get-database calls when Android detects that we need to - * create or update the database. So we have to use the database argument and save a connection to it on the - * AndroidConnectionSource, otherwise it will go recursive if the subclass calls getConnectionSource(). - */ - DatabaseConnection conn = cs.getSpecialConnection(); - boolean clearSpecial = false; - if (conn == null) { - conn = new AndroidDatabaseConnection(db, true, cancelQueriesEnabled); - try { - cs.saveSpecialConnection(conn); - clearSpecial = true; - } catch (SQLException e) { - throw new IllegalStateException("Could not save special connection", e); - } - } - try { - onCreate(db, cs); - } finally { - if (clearSpecial) { - cs.clearSpecialConnection(conn); - } - } - } - - /** - * Satisfies the {@link SQLiteOpenHelper#onUpgrade(SQLiteDatabase, int, int)} interface method. - */ - @Override - public final void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - ConnectionSource cs = getConnectionSource(); - /* - * The method is called by Android database helper's get-database calls when Android detects that we need to - * create or update the database. So we have to use the database argument and save a connection to it on the - * AndroidConnectionSource, otherwise it will go recursive if the subclass calls getConnectionSource(). - */ - DatabaseConnection conn = cs.getSpecialConnection(); - boolean clearSpecial = false; - if (conn == null) { - conn = new AndroidDatabaseConnection(db, true, cancelQueriesEnabled); - try { - cs.saveSpecialConnection(conn); - clearSpecial = true; - } catch (SQLException e) { - throw new IllegalStateException("Could not save special connection", e); - } - } - try { - onUpgrade(db, cs, oldVersion, newVersion); - } finally { - if (clearSpecial) { - cs.clearSpecialConnection(conn); - } - } - } - - /** - * Close any open connections. - */ - @Override - public void close() { - super.close(); - connectionSource.close(); - /* - * We used to set connectionSource to null here but now we just set the closed flag and then log heavily if - * someone uses getConectionSource() after this point. - */ - isOpen = false; - } - - /** - * Return true if the helper is still open. Once {@link #close()} is called then this will return false. - */ - public boolean isOpen() { - return isOpen; - } - - /** - * Get a DAO for our class. This uses the {@link DaoManager} to cache the DAO for future gets. - * - *

- * NOTE: This routing does not return Dao<T, ID> because of casting issues if we are assigning it to a custom DAO. - * Grumble. - *

- */ - public , T> D getDao(Class clazz) throws SQLException { - // special reflection fu is now handled internally by create dao calling the database type - Dao dao = DaoManager.createDao(getConnectionSource(), clazz); - @SuppressWarnings("unchecked") - D castDao = (D) dao; - return castDao; - } - - /** - * Get a RuntimeExceptionDao for our class. This uses the {@link DaoManager} to cache the DAO for future gets. - * - *

- * NOTE: This routing does not return RuntimeExceptionDao<T, ID> because of casting issues if we are assigning it to - * a custom DAO. Grumble. - *

- */ - public , T> D getRuntimeExceptionDao(Class clazz) { - try { - Dao dao = getDao(clazz); - @SuppressWarnings({ "unchecked", "rawtypes" }) - D castDao = (D) new RuntimeExceptionDao(dao); - return castDao; - } catch (SQLException e) { - throw new RuntimeException("Could not create RuntimeExcepitionDao for class " + clazz, e); - } - } - - @Override - public String toString() { - return getClass().getSimpleName() + "@" + Integer.toHexString(super.hashCode()); - } -} From d7e548844eddd6fd718f812b40f363f26323a777 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 30 Apr 2015 19:37:28 -0700 Subject: [PATCH 03/26] Handle ForeignCollectionField annotations --- .../apptools/OrmLiteAnnotationProcessor.java | 403 +++++++++--------- 1 file changed, 208 insertions(+), 195 deletions(-) diff --git a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java index d6157f5f..704199d3 100644 --- a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java @@ -1,11 +1,13 @@ package com.j256.ormlite.android.apptools; -import com.j256.ormlite.field.DataPersister; import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.field.ForeignCollectionField; import com.j256.ormlite.table.DatabaseTable; import java.io.IOException; import java.io.Writer; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; @@ -17,15 +19,17 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.SourceVersion; import javax.lang.model.type.MirroredTypeException; -import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileObject; -//TODO: handle ForeignCollectionField annotations //TODO: handle javax.persistance annotations //TODO: add note that this must be updated to Annotation classes //TODO: analyze if this should be part of core (and if config file stuff can be removed) //TODO: make sure no generated code is added to ormlite.android jar (and optimize pom) //TODO: add error messages +//TODO: understand when/if columns need to be uppercased +//TODO: handle non-public entities (put generated files in same package) +//TODO: add @Generated annotation to generated files /** * Class that is automatically run when compiling client code that automatically @@ -41,6 +45,9 @@ public final class OrmLiteAnnotationProcessor extends AbstractProcessor { private static final String PACKAGE = "com.j256.ormlite.android.apptools.tableconfigs"; private static final String SUFFIX = "Config"; + private static final String FQCN_Object = "java.lang.Object"; + private static final String FQCN_Class = "java.lang.Class"; + static final class TableModel { String fullyQualifiedClassName; String simpleClassName; @@ -51,7 +58,8 @@ static final class TableModel { static final class FieldModel { String fullyQualifiedTypeName; String fieldName; - DatabaseField annotation; + DatabaseField databaseFieldAnnotation; + ForeignCollectionField foreignCollectionFieldAnnotation; } @Override @@ -87,21 +95,35 @@ public boolean process(Set elements, if (child.getKind().isField()) { DatabaseField databaseField = child .getAnnotation(DatabaseField.class); - if (databaseField != null) { + ForeignCollectionField foreignCollectionField = child + .getAnnotation(ForeignCollectionField.class); + if (databaseField != null + || foreignCollectionField != null) { FieldModel field = new FieldModel(); field.fullyQualifiedTypeName = child.asType() .toString(); field.fieldName = child.getSimpleName().toString(); - field.annotation = databaseField; + field.databaseFieldAnnotation = databaseField; + field.foreignCollectionFieldAnnotation = foreignCollectionField; table.fields.add(field); } + + if (databaseField != null + && foreignCollectionField != null) { + raiseError( + String.format( + "Fields cannot be annotated with both %s and %s", + DatabaseField.class.getSimpleName(), + ForeignCollectionField.class + .getSimpleName()), child); + } } } tableClassElement = (TypeElement) processingEnv.getTypeUtils() .asElement(tableClassElement.getSuperclass()); } while (!tableClassElement.getQualifiedName().toString() - .equals("java.lang.Object")); + .equals(FQCN_Object)); createSourceFile(table); } @@ -135,7 +157,8 @@ private void writeTable(Writer writer, TableModel table) throws IOException { writer.write("import com.j256.ormlite.field.DatabaseFieldConfig;\n"); writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); writer.write("\n"); - writer.write("public final class " + table.simpleClassName + SUFFIX + " {\n"); + writer.write("public final class " + table.simpleClassName + SUFFIX + + " {\n"); writer.write("\tprivate " + table.simpleClassName + SUFFIX + "() {\n"); writer.write("\t}\n"); writer.write("\n"); @@ -146,7 +169,8 @@ private void writeTable(Writer writer, TableModel table) throws IOException { writer.write("\t\tList databaseFieldConfigs = new ArrayList();\n"); for (FieldModel field : table.fields) { - if (!field.annotation.persisted()) { + if (field.databaseFieldAnnotation != null + && !field.databaseFieldAnnotation.persisted()) { continue; } @@ -155,213 +179,142 @@ private void writeTable(Writer writer, TableModel table) throws IOException { .format("\t\t\tDatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig(\"%s\");\n", field.fieldName)); - if (!field.annotation.columnName().equals( - getDefaultAnnotationValue(field, "columnName"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setColumnName(\"%s\");\n", - field.annotation.columnName())); - } + if (field.databaseFieldAnnotation != null) { + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "columnName", "setColumnName(\"%s\")", writer); - if (!field.annotation.dataType().equals( - getDefaultAnnotationValue(field, "dataType"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setDataType(com.j256.ormlite.field.DataType.%s);\n", - field.annotation.dataType().toString())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "dataType", + "setDataType(com.j256.ormlite.field.DataType.%s)", + writer); - if (!field.annotation.defaultValue().equals( - getDefaultAnnotationValue(field, "defaultValue"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setDefaultValue(\"%s\");\n", - field.annotation.defaultValue())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "defaultValue", "setDefaultValue(\"%s\")", writer); - if (!Integer.valueOf(field.annotation.width()).equals( - getDefaultAnnotationValue(field, "width"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setWidth(%d);\n", - field.annotation.width())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, "width", + "setWidth(%d)", writer); - if (!Boolean.valueOf(field.annotation.canBeNull()).equals( - getDefaultAnnotationValue(field, "canBeNull"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setCanBeNull(%b);\n", - field.annotation.canBeNull())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "canBeNull", "setCanBeNull(%b)", writer); - if (!Boolean.valueOf(field.annotation.id()).equals( - getDefaultAnnotationValue(field, "id"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setId(%b);\n", - field.annotation.id())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, "id", + "setId(%b)", writer); - if (!Boolean.valueOf(field.annotation.generatedId()).equals( - getDefaultAnnotationValue(field, "generatedId"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setGeneratedId(%b);\n", - field.annotation.generatedId())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "generatedId", "setGeneratedId(%b)", writer); - if (!field.annotation.generatedIdSequence().equals( - getDefaultAnnotationValue(field, "generatedIdSequence"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setGeneratedIdSequence(\"%s\");\n", - field.annotation.generatedIdSequence())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "generatedIdSequence", + "setGeneratedIdSequence(\"%s\")", writer); - if (!Boolean.valueOf(field.annotation.foreign()).equals( - getDefaultAnnotationValue(field, "foreign"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setForeign(%b);\n", - field.annotation.foreign())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "foreign", "setForeign(%b)", writer); - if (!Boolean.valueOf(field.annotation.useGetSet()).equals( - getDefaultAnnotationValue(field, "useGetSet"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setUseGetSet(%b);\n", - field.annotation.useGetSet())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "useGetSet", "setUseGetSet(%b)", writer); - if (!field.annotation.unknownEnumName().equals( - getDefaultAnnotationValue(field, "unknownEnumName"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setUnknownEnumName(%s.%s);\n", - field.fullyQualifiedTypeName, - field.annotation.unknownEnumName())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "unknownEnumName", "setUnknownEnumValue(" + + field.fullyQualifiedTypeName + ".%s)", writer); - if (!Boolean.valueOf(field.annotation.throwIfNull()).equals( - getDefaultAnnotationValue(field, "throwIfNull"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setThrowIfNull(%b);\n", - field.annotation.throwIfNull())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "throwIfNull", "setThrowIfNull(%b)", writer); - if (!field.annotation.format().equals( - getDefaultAnnotationValue(field, "format"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setFormat(\"%s\");\n", - field.annotation.format())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "format", "setFormat(\"%s\")", writer); - if (!Boolean.valueOf(field.annotation.unique()).equals( - getDefaultAnnotationValue(field, "unique"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setUnique(%b);\n", - field.annotation.unique())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "unique", "setUnique(%b)", writer); - if (!Boolean.valueOf(field.annotation.uniqueCombo()).equals( - getDefaultAnnotationValue(field, "uniqueCombo"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setUniqueCombo(%b);\n", - field.annotation.uniqueCombo())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "uniqueCombo", "setUniqueCombo(%b)", writer); - if (!Boolean.valueOf(field.annotation.index()).equals( - getDefaultAnnotationValue(field, "index"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setIndex(%b);\n", - field.annotation.index())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, "index", + "setIndex(%b)", writer); - if (!Boolean.valueOf(field.annotation.uniqueIndex()).equals( - getDefaultAnnotationValue(field, "uniqueIndex"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setUniqueIndex(%b);\n", - field.annotation.uniqueIndex())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "uniqueIndex", "setUniqueIndex(%b)", writer); - if (!field.annotation.indexName().equals( - getDefaultAnnotationValue(field, "indexName"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setIndexName(\"%s\");\n", - field.annotation.indexName())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "indexName", "setIndexName(\"%s\")", writer); - if (!field.annotation.uniqueIndexName().equals( - getDefaultAnnotationValue(field, "uniqueIndexName"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setUniqueIndexName(\"%s\");\n", - field.annotation.uniqueIndexName())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "uniqueIndexName", "setUniqueIndexName(\"%s\")", writer); - if (!Boolean.valueOf(field.annotation.foreignAutoRefresh()).equals( - getDefaultAnnotationValue(field, "foreignAutoRefresh"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setForeignAutoRefresh(%b);\n", - field.annotation.foreignAutoRefresh())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "foreignAutoRefresh", "setForeignAutoRefresh(%b)", + writer); - if (!Integer.valueOf(field.annotation.maxForeignAutoRefreshLevel()) - .equals(getDefaultAnnotationValue(field, - "maxForeignAutoRefreshLevel"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setMaxForeignAutoRefreshLevel(%d);\n", - field.annotation.maxForeignAutoRefreshLevel())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "maxForeignAutoRefreshLevel", + "setMaxForeignAutoRefreshLevel(%d)", writer); - TypeMirror persisterClassActual; - try { - field.annotation.persisterClass(); // this will throw - throw new RuntimeException("Failed to get TypeMirror"); - } catch (MirroredTypeException mte) { - persisterClassActual = mte.getTypeMirror(); - } - @SuppressWarnings("unchecked") - Class persisterClassDefault = (Class) getDefaultAnnotationValue( - field, "persisterClass"); - if (!persisterClassActual.toString().equals( - persisterClassDefault.getCanonicalName())) { - writer.write(String - .format("\t\t\t\tdatabaseFieldConfig.setPersisterClass(%s.class);\n", - persisterClassActual.toString())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "persisterClass", "setPersisterClass(%s.class)", writer); - if (!Boolean.valueOf(field.annotation.allowGeneratedIdInsert()) - .equals(getDefaultAnnotationValue(field, - "allowGeneratedIdInsert"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setAllowGeneratedIdInsert(%b);\n", - field.annotation.allowGeneratedIdInsert())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "allowGeneratedIdInsert", + "setAllowGeneratedIdInsert(%b)", writer); - if (!field.annotation.columnDefinition().equals( - getDefaultAnnotationValue(field, "columnDefinition"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setColumnDefinition(\"%s\");\n", - field.annotation.columnDefinition())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "columnDefinition", "setColumnDefinition(\"%s\")", + writer); - if (!Boolean.valueOf(field.annotation.foreignAutoCreate()).equals( - getDefaultAnnotationValue(field, "foreignAutoCreate"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setForeignAutoCreate(%b);\n", - field.annotation.foreignAutoCreate())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "foreignAutoCreate", "setForeignAutoCreate(%b)", writer); - if (!Boolean.valueOf(field.annotation.version()).equals( - getDefaultAnnotationValue(field, "version"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setVersion(%b);\n", - field.annotation.version())); - } + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "version", "setVersion(%b)", writer); - if (!field.annotation.foreignColumnName().equals( - getDefaultAnnotationValue(field, "foreignColumnName"))) { - writer.write(String - .format("\t\t\tdatabaseFieldConfig.setForeignColumnName(\"%s\");\n", - field.annotation.foreignColumnName())); + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "foreignColumnName", "setForeignColumnName(\"%s\")", + writer); + + writeSetterIfNotDefault(field.databaseFieldAnnotation, + "readOnly", "setReadOnly(%b)", writer); } - if (!Boolean.valueOf(field.annotation.readOnly()).equals( - getDefaultAnnotationValue(field, "readOnly"))) { - writer.write(String.format( - "\t\t\tdatabaseFieldConfig.setReadOnly(%b);\n", - field.annotation.readOnly())); + if (field.foreignCollectionFieldAnnotation != null) { + writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, + "columnName", "setColumnName(\"%s\")", writer); + + writeSetter(true, "setForeignCollection(%b)", writer); + + writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, + "eager", "setForeignCollectionEager(%b)", writer); + + if (!writeSetterIfNotDefault( + field.foreignCollectionFieldAnnotation, + "maxEagerLevel", + "setForeignCollectionMaxEagerLevel(%d)", writer)) { + writeSetterIfNotDefault( + field.foreignCollectionFieldAnnotation, + "maxEagerForeignCollectionLevel", + "setForeignCollectionMaxEagerLevel(%d)", writer); + } + + writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, + "columnName", "setForeignCollectionColumnName(\"%s\")", + writer); + + writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, + "orderColumnName", + "setForeignCollectionOrderColumnName(\"%s\")", writer); + + writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, + "orderAscending", + "setForeignCollectionOrderAscending(%b)", writer); + + if (!writeSetterIfNotDefault( + field.foreignCollectionFieldAnnotation, + "foreignFieldName", + "setForeignCollectionForeignFieldName(\"%s\")", writer)) { + writeSetterIfNotDefault( + field.foreignCollectionFieldAnnotation, + "foreignColumnName", + "setForeignCollectionForeignFieldName(\"%s\")", + writer); + } } writer.write("\t\t\tdatabaseFieldConfigs.add(databaseFieldConfig);\n"); @@ -384,15 +337,75 @@ private void writeTable(Writer writer, TableModel table) throws IOException { writer.write("}\n"); } - private static Object getDefaultAnnotationValue(FieldModel field, - String name) { + private static boolean writeSetterIfNotDefault(Annotation annotation, + String annotationFieldName, String setterCall, Writer writer) { try { - return field.annotation.annotationType().getMethod(name) - .getDefaultValue(); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (SecurityException e) { + Method method = annotation.annotationType().getMethod( + annotationFieldName); + + Object actualValue; + Object defaultValue; + if (method.getReturnType().getCanonicalName().equals(FQCN_Class)) { + try { + actualValue = getClassNameFromClassObject(method + .invoke(annotation)); + } catch (Exception ex) { + actualValue = getMirroredClassNameFromException(ex); + } + try { + defaultValue = getClassNameFromClassObject(method + .getDefaultValue()); + } catch (Exception ex) { + defaultValue = getMirroredClassNameFromException(ex); + } + } else { + actualValue = method.invoke(annotation); + defaultValue = method.getDefaultValue(); + } + + return writeSetterIfNotEqual(actualValue, defaultValue, setterCall, + writer); + } catch (Exception e) { throw new RuntimeException(e); } } + + private static String getClassNameFromClassObject(Object object) { + return ((Class) object).getCanonicalName(); + } + + private static String getMirroredClassNameFromException(Exception ex) + throws Exception { + Throwable t = ex; + do { + if (t instanceof MirroredTypeException) { + return ((MirroredTypeException) t).getTypeMirror().toString(); + } + t = t.getCause(); + } while (t != null); + + throw ex; + } + + private static boolean writeSetterIfNotEqual(Object actualValue, + Object defaultValue, String setterCall, Writer writer) + throws IOException { + if (!actualValue.equals(defaultValue)) { + writeSetter(actualValue, setterCall, writer); + return true; + } else { + return false; + } + } + + private static void writeSetter(Object value, String setterCall, + Writer writer) throws IOException { + writer.write(String.format("\t\t\tdatabaseFieldConfig." + setterCall + + ";\n", value)); + } + + private void raiseError(String message, Element element) { + this.processingEnv.getMessager().printMessage(Kind.ERROR, message, + element); + } } From 44fc71ac0ef18bdf5afb0351002f908ae9ae15c0 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 30 Apr 2015 19:38:29 -0700 Subject: [PATCH 04/26] Add automated unit tests of annotation parsing --- pom.xml | 6 + .../OrmLiteAnnotationProcessorTest.java | 67 +++++++++ .../NamedTableWithSpecifiedDatabaseField.java | 142 ++++++++++++++++++ ...leWithSpecifiedForeignCollectionField.java | 15 ++ .../UnnamedTableWithDefaultDatabaseField.java | 10 ++ ...ableWithDefaultForeignCollectionField.java | 12 ++ ...TableWithSpecifiedDatabaseFieldConfig.java | 51 +++++++ ...SpecifiedForeignCollectionFieldConfig.java | 38 +++++ ...edTableWithDefaultDatabaseFieldConfig.java | 23 +++ ...thDefaultForeignCollectionFieldConfig.java | 24 +++ 10 files changed, 388 insertions(+) create mode 100644 src/test/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessorTest.java create mode 100644 src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java create mode 100644 src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java create mode 100644 src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java create mode 100644 src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java create mode 100644 src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java create mode 100644 src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java create mode 100644 src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java create mode 100644 src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java diff --git a/pom.xml b/pom.xml index c2f7339e..b8d4fb01 100644 --- a/pom.xml +++ b/pom.xml @@ -404,5 +404,11 @@ ${easymock-version} test + + com.google.testing.compile + compile-testing + 0.6 + test + diff --git a/src/test/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessorTest.java b/src/test/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessorTest.java new file mode 100644 index 00000000..7e9a2a04 --- /dev/null +++ b/src/test/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessorTest.java @@ -0,0 +1,67 @@ +package com.j256.ormlite.android.apptools; + +import static com.google.common.truth.Truth.assert_; +import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; + +import org.junit.Test; + +import com.google.testing.compile.JavaFileObjects; + +public class OrmLiteAnnotationProcessorTest { + + @Test + public void testDatabaseFieldAllDefaults() { + assert_() + .about(javaSource()) + .that(JavaFileObjects + .forResource("inputs/UnnamedTableWithDefaultDatabaseField.java")) + .processedWith(new OrmLiteAnnotationProcessor()) + .compilesWithoutError() + .and() + .generatesSources( + JavaFileObjects + .forResource("outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java")); + } + + @Test + public void testDatabaseFieldAllSpecified() { + assert_() + .about(javaSource()) + .that(JavaFileObjects + .forResource("inputs/NamedTableWithSpecifiedDatabaseField.java")) + .processedWith(new OrmLiteAnnotationProcessor()) + .compilesWithoutError() + .and() + .generatesSources( + JavaFileObjects + .forResource("outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java")); + } + + @Test + public void testForeignCollectionFieldAllDefaults() { + assert_() + .about(javaSource()) + .that(JavaFileObjects + .forResource("inputs/UnnamedTableWithDefaultForeignCollectionField.java")) + .processedWith(new OrmLiteAnnotationProcessor()) + .compilesWithoutError() + .and() + .generatesSources( + JavaFileObjects + .forResource("outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java")); + } + + @Test + public void testForeignCollectionFieldAllSpecified() { + assert_() + .about(javaSource()) + .that(JavaFileObjects + .forResource("inputs/NamedTableWithSpecifiedForeignCollectionField.java")) + .processedWith(new OrmLiteAnnotationProcessor()) + .compilesWithoutError() + .and() + .generatesSources( + JavaFileObjects + .forResource("outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java")); + } +} diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java new file mode 100644 index 00000000..5f8e8b35 --- /dev/null +++ b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java @@ -0,0 +1,142 @@ +package inputs; + +import java.lang.reflect.Field; +import java.sql.SQLException; + +import com.j256.ormlite.field.DataPersister; +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.field.FieldType; +import com.j256.ormlite.field.SqlType; +import com.j256.ormlite.support.DatabaseResults; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable(tableName = "table") +public class NamedTableWithSpecifiedDatabaseField { + + public static enum FieldTypeEnum { + VALUE, OTHER_VALUE; + } + + public static class CustomPersister implements DataPersister { + public Object parseDefaultString(FieldType fieldType, String defaultStr) + throws SQLException { + return null; + } + + public Object javaToSqlArg(FieldType fieldType, Object obj) + throws SQLException { + return null; + } + + public Object resultToSqlArg(FieldType fieldType, + DatabaseResults results, int columnPos) throws SQLException { + return null; + } + + public Object resultToJava(FieldType fieldType, + DatabaseResults results, int columnPos) throws SQLException { + return null; + } + + public Object sqlArgToJava(FieldType fieldType, Object sqlArg, + int columnPos) throws SQLException { + return null; + } + + public SqlType getSqlType() { + return null; + } + + public boolean isStreamType() { + return false; + } + + public Object resultStringToJava(FieldType fieldType, + String stringValue, int columnPos) throws SQLException { + return null; + } + + public Class[] getAssociatedClasses() { + return null; + } + + public String[] getAssociatedClassNames() { + return null; + } + + public Object makeConfigObject(FieldType fieldType) throws SQLException { + return null; + } + + public Object convertIdNumber(Number number) { + return null; + } + + public boolean isValidGeneratedType() { + return false; + } + + public boolean isValidForField(Field field) { + return false; + } + + public Class getPrimaryClass() { + return null; + } + + public boolean isEscapedDefaultValue() { + return false; + } + + public boolean isEscapedValue() { + return false; + } + + public boolean isPrimitive() { + return false; + } + + public boolean isComparable() { + return false; + } + + public boolean isAppropriateId() { + return false; + } + + public boolean isArgumentHolderRequired() { + return false; + } + + public boolean isSelfGeneratedId() { + return false; + } + + public Object generateId() { + return null; + } + + public int getDefaultWidth() { + return 0; + } + + public boolean dataIsEqual(Object obj1, Object obj2) { + return false; + } + + public boolean isValidForVersion() { + return false; + } + + public Object moveToNextValue(Object currentValue) throws SQLException { + return null; + } + } + + @DatabaseField(columnName = "column", dataType = DataType.ENUM_INTEGER, defaultValue = "VALUE", width = 100, canBeNull = false, id = true, generatedId = true, generatedIdSequence = "id_sequence", foreign = true, useGetSet = true, unknownEnumName = "OTHER_VALUE", throwIfNull = true, format = "%f", unique = true, uniqueCombo = true, index = true, uniqueIndex = true, indexName = "index", uniqueIndexName = "unique_index", foreignAutoRefresh = true, maxForeignAutoRefreshLevel = 5, persisterClass = CustomPersister.class, allowGeneratedIdInsert = true, columnDefinition = "INT NOT NULL", foreignAutoCreate = true, version = true, foreignColumnName = "foreign", readOnly = true) + public FieldTypeEnum field; + + @DatabaseField(persisted = false) + public int ignored; +} diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java new file mode 100644 index 00000000..b7b5e3e2 --- /dev/null +++ b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java @@ -0,0 +1,15 @@ +package inputs; + +import java.util.List; + +import com.j256.ormlite.field.ForeignCollectionField; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable(tableName = "table") +public class NamedTableWithSpecifiedForeignCollectionField { + @ForeignCollectionField(eager = true, maxEagerLevel = 5, columnName = "column", orderColumnName = "order_column", orderAscending = false, foreignFieldName = "foreign_field") + public List numbers; + + @ForeignCollectionField(maxEagerForeignCollectionLevel = 5, foreignColumnName = "foreign_field") + public List numbers_deprecated; +} diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java new file mode 100644 index 00000000..61b680ea --- /dev/null +++ b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java @@ -0,0 +1,10 @@ +package inputs; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable +public class UnnamedTableWithDefaultDatabaseField { + @DatabaseField + public int field; +} diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java new file mode 100644 index 00000000..3938f5d5 --- /dev/null +++ b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java @@ -0,0 +1,12 @@ +package inputs; + +import java.util.List; + +import com.j256.ormlite.field.ForeignCollectionField; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable +public class UnnamedTableWithDefaultForeignCollectionField { + @ForeignCollectionField + public List numbers; +} diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java new file mode 100644 index 00000000..8d300b76 --- /dev/null +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java @@ -0,0 +1,51 @@ +package com.j256.ormlite.android.apptools.tableconfigs; + +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.field.DatabaseFieldConfig; +import com.j256.ormlite.table.DatabaseTableConfig; + +public final class NamedTableWithSpecifiedDatabaseFieldConfig { + private NamedTableWithSpecifiedDatabaseFieldConfig() { + } + + public static final DatabaseTableConfig CONFIG; + + static { + List databaseFieldConfigs = new ArrayList(); + { + DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); + databaseFieldConfig.setColumnName("column"); + databaseFieldConfig.setDataType(com.j256.ormlite.field.DataType.ENUM_INTEGER); + databaseFieldConfig.setDefaultValue("VALUE"); + databaseFieldConfig.setWidth(100); + databaseFieldConfig.setCanBeNull(false); + databaseFieldConfig.setId(true); + databaseFieldConfig.setGeneratedId(true); + databaseFieldConfig.setGeneratedIdSequence("id_sequence"); + databaseFieldConfig.setForeign(true); + databaseFieldConfig.setUseGetSet(true); + databaseFieldConfig.setUnknownEnumValue(inputs.NamedTableWithSpecifiedDatabaseField.FieldTypeEnum.OTHER_VALUE); + databaseFieldConfig.setThrowIfNull(true); + databaseFieldConfig.setFormat("%f"); + databaseFieldConfig.setUnique(true); + databaseFieldConfig.setUniqueCombo(true); + databaseFieldConfig.setIndex(true); + databaseFieldConfig.setUniqueIndex(true); + databaseFieldConfig.setIndexName("index"); + databaseFieldConfig.setUniqueIndexName("unique_index"); + databaseFieldConfig.setForeignAutoRefresh(true); + databaseFieldConfig.setMaxForeignAutoRefreshLevel(5); + databaseFieldConfig.setPersisterClass(inputs.NamedTableWithSpecifiedDatabaseField.CustomPersister.class); + databaseFieldConfig.setAllowGeneratedIdInsert(true); + databaseFieldConfig.setColumnDefinition("INT NOT NULL"); + databaseFieldConfig.setForeignAutoCreate(true); + databaseFieldConfig.setVersion(true); + databaseFieldConfig.setForeignColumnName("foreign"); + databaseFieldConfig.setReadOnly(true); + databaseFieldConfigs.add(databaseFieldConfig); + } + CONFIG = new DatabaseTableConfig(inputs.NamedTableWithSpecifiedDatabaseField.class, "table", databaseFieldConfigs); + } +} diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java new file mode 100644 index 00000000..5b7f0c08 --- /dev/null +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java @@ -0,0 +1,38 @@ +package com.j256.ormlite.android.apptools.tableconfigs; + +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.field.DatabaseFieldConfig; +import com.j256.ormlite.table.DatabaseTableConfig; + +public final class NamedTableWithSpecifiedForeignCollectionFieldConfig { + private NamedTableWithSpecifiedForeignCollectionFieldConfig() { + } + + public static final DatabaseTableConfig CONFIG; + + static { + List databaseFieldConfigs = new ArrayList(); + { + DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("numbers"); + databaseFieldConfig.setColumnName("column"); + databaseFieldConfig.setForeignCollection(true); + databaseFieldConfig.setForeignCollectionEager(true); + databaseFieldConfig.setForeignCollectionMaxEagerLevel(5); + databaseFieldConfig.setForeignCollectionColumnName("column"); + databaseFieldConfig.setForeignCollectionOrderColumnName("order_column"); + databaseFieldConfig.setForeignCollectionOrderAscending(false); + databaseFieldConfig.setForeignCollectionForeignFieldName("foreign_field"); + databaseFieldConfigs.add(databaseFieldConfig); + } + { + DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("numbers_deprecated"); + databaseFieldConfig.setForeignCollection(true); + databaseFieldConfig.setForeignCollectionMaxEagerLevel(5); + databaseFieldConfig.setForeignCollectionForeignFieldName("foreign_field"); + databaseFieldConfigs.add(databaseFieldConfig); + } + CONFIG = new DatabaseTableConfig(inputs.NamedTableWithSpecifiedForeignCollectionField.class, "table", databaseFieldConfigs); + } +} diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java new file mode 100644 index 00000000..ac8a6655 --- /dev/null +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java @@ -0,0 +1,23 @@ +package com.j256.ormlite.android.apptools.tableconfigs; + +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.field.DatabaseFieldConfig; +import com.j256.ormlite.table.DatabaseTableConfig; + +public final class UnnamedTableWithDefaultDatabaseFieldConfig { + private UnnamedTableWithDefaultDatabaseFieldConfig() { + } + + public static final DatabaseTableConfig CONFIG; + + static { + List databaseFieldConfigs = new ArrayList(); + { + DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); + databaseFieldConfigs.add(databaseFieldConfig); + } + CONFIG = new DatabaseTableConfig(inputs.UnnamedTableWithDefaultDatabaseField.class, "unnamedtablewithdefaultdatabasefield", databaseFieldConfigs); + } +} diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java new file mode 100644 index 00000000..dfd82d03 --- /dev/null +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java @@ -0,0 +1,24 @@ +package com.j256.ormlite.android.apptools.tableconfigs; + +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.field.DatabaseFieldConfig; +import com.j256.ormlite.table.DatabaseTableConfig; + +public final class UnnamedTableWithDefaultForeignCollectionFieldConfig { + private UnnamedTableWithDefaultForeignCollectionFieldConfig() { + } + + public static final DatabaseTableConfig CONFIG; + + static { + List databaseFieldConfigs = new ArrayList(); + { + DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("numbers"); + databaseFieldConfig.setForeignCollection(true); + databaseFieldConfigs.add(databaseFieldConfig); + } + CONFIG = new DatabaseTableConfig(inputs.UnnamedTableWithDefaultForeignCollectionField.class, "unnamedtablewithdefaultforeigncollectionfield", databaseFieldConfigs); + } +} From d2fd0da12576b272dd5cfeb654f9f82823bec4a1 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 30 Apr 2015 20:49:36 -0700 Subject: [PATCH 05/26] Add @Generated annotation to outputs --- .../ormlite/android/apptools/OrmLiteAnnotationProcessor.java | 5 ++++- .../outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java | 3 +++ .../NamedTableWithSpecifiedForeignCollectionFieldConfig.java | 3 +++ .../outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java | 3 +++ .../UnnamedTableWithDefaultForeignCollectionFieldConfig.java | 3 +++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java index 704199d3..a10c6c3b 100644 --- a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java @@ -29,7 +29,6 @@ //TODO: add error messages //TODO: understand when/if columns need to be uppercased //TODO: handle non-public entities (put generated files in same package) -//TODO: add @Generated annotation to generated files /** * Class that is automatically run when compiling client code that automatically @@ -157,6 +156,10 @@ private void writeTable(Writer writer, TableModel table) throws IOException { writer.write("import com.j256.ormlite.field.DatabaseFieldConfig;\n"); writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); writer.write("\n"); + writer.write("import javax.annotation.Generated;\n"); + writer.write("\n"); + writer.write(String.format("@Generated(\"%s\")\n", getClass() + .getCanonicalName())); writer.write("public final class " + table.simpleClassName + SUFFIX + " {\n"); writer.write("\tprivate " + table.simpleClassName + SUFFIX + "() {\n"); diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java index 8d300b76..66c18aca 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java @@ -6,6 +6,9 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import javax.annotation.Generated; + +@Generated("com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor") public final class NamedTableWithSpecifiedDatabaseFieldConfig { private NamedTableWithSpecifiedDatabaseFieldConfig() { } diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java index 5b7f0c08..797663df 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java @@ -6,6 +6,9 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import javax.annotation.Generated; + +@Generated("com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor") public final class NamedTableWithSpecifiedForeignCollectionFieldConfig { private NamedTableWithSpecifiedForeignCollectionFieldConfig() { } diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java index ac8a6655..56b9dcba 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java @@ -6,6 +6,9 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import javax.annotation.Generated; + +@Generated("com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor") public final class UnnamedTableWithDefaultDatabaseFieldConfig { private UnnamedTableWithDefaultDatabaseFieldConfig() { } diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java index dfd82d03..d9a54c33 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java @@ -6,6 +6,9 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import javax.annotation.Generated; + +@Generated("com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor") public final class UnnamedTableWithDefaultForeignCollectionFieldConfig { private UnnamedTableWithDefaultForeignCollectionFieldConfig() { } From e95821c7e82b64acd2d673aa63cb261113032c05 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Fri, 1 May 2015 19:05:02 -0700 Subject: [PATCH 06/26] Revert "Add @Generated annotation to outputs" This reverts commit d2fd0da12576b272dd5cfeb654f9f82823bec4a1. --- .../ormlite/android/apptools/OrmLiteAnnotationProcessor.java | 5 +---- .../outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java | 3 --- .../NamedTableWithSpecifiedForeignCollectionFieldConfig.java | 3 --- .../outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java | 3 --- .../UnnamedTableWithDefaultForeignCollectionFieldConfig.java | 3 --- 5 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java index a10c6c3b..704199d3 100644 --- a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java @@ -29,6 +29,7 @@ //TODO: add error messages //TODO: understand when/if columns need to be uppercased //TODO: handle non-public entities (put generated files in same package) +//TODO: add @Generated annotation to generated files /** * Class that is automatically run when compiling client code that automatically @@ -156,10 +157,6 @@ private void writeTable(Writer writer, TableModel table) throws IOException { writer.write("import com.j256.ormlite.field.DatabaseFieldConfig;\n"); writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); writer.write("\n"); - writer.write("import javax.annotation.Generated;\n"); - writer.write("\n"); - writer.write(String.format("@Generated(\"%s\")\n", getClass() - .getCanonicalName())); writer.write("public final class " + table.simpleClassName + SUFFIX + " {\n"); writer.write("\tprivate " + table.simpleClassName + SUFFIX + "() {\n"); diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java index 66c18aca..8d300b76 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java @@ -6,9 +6,6 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; -import javax.annotation.Generated; - -@Generated("com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor") public final class NamedTableWithSpecifiedDatabaseFieldConfig { private NamedTableWithSpecifiedDatabaseFieldConfig() { } diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java index 797663df..5b7f0c08 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java @@ -6,9 +6,6 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; -import javax.annotation.Generated; - -@Generated("com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor") public final class NamedTableWithSpecifiedForeignCollectionFieldConfig { private NamedTableWithSpecifiedForeignCollectionFieldConfig() { } diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java index 56b9dcba..ac8a6655 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java @@ -6,9 +6,6 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; -import javax.annotation.Generated; - -@Generated("com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor") public final class UnnamedTableWithDefaultDatabaseFieldConfig { private UnnamedTableWithDefaultDatabaseFieldConfig() { } diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java index d9a54c33..dfd82d03 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java @@ -6,9 +6,6 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; -import javax.annotation.Generated; - -@Generated("com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor") public final class UnnamedTableWithDefaultForeignCollectionFieldConfig { private UnnamedTableWithDefaultForeignCollectionFieldConfig() { } From 20f08c113a0f589c785285bd7390039216b997b9 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 7 May 2015 20:20:18 -0700 Subject: [PATCH 07/26] Support non public classes --- pom.xml | 36 +++--- .../android/annotations/DatabaseTables.java | 12 ++ .../OrmLiteAnnotationProcessor.java | 105 +++++++++++++----- .../javax.annotation.processing.Processor | 2 +- .../OrmLiteAnnotationProcessorTest.java | 30 +++-- .../resources/inputs/InnerClassTable.java | 18 +++ .../NamedTableWithSpecifiedDatabaseField.java | 6 +- ...leWithSpecifiedForeignCollectionField.java | 6 +- .../UnnamedTableWithDefaultDatabaseField.java | 4 +- ...ableWithDefaultForeignCollectionField.java | 4 +- ...nnerClassTable_InnerClass_TableConfig.java | 23 ++++ ...lassTable_OtherInnerClass_TableConfig.java | 23 ++++ ...thSpecifiedDatabaseField_TableConfig.java} | 6 +- ...edForeignCollectionField_TableConfig.java} | 6 +- ...WithDefaultDatabaseField_TableConfig.java} | 6 +- ...ltForeignCollectionField_TableConfig.java} | 6 +- 16 files changed, 218 insertions(+), 75 deletions(-) create mode 100644 src/main/java/com/j256/ormlite/android/annotations/DatabaseTables.java rename src/main/java/com/j256/ormlite/android/{apptools => annotations}/OrmLiteAnnotationProcessor.java (83%) rename src/test/java/com/j256/ormlite/android/{apptools => annotations}/OrmLiteAnnotationProcessorTest.java (74%) create mode 100644 src/test/resources/inputs/InnerClassTable.java create mode 100644 src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java create mode 100644 src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java rename src/test/resources/outputs/{NamedTableWithSpecifiedDatabaseFieldConfig.java => NamedTableWithSpecifiedDatabaseField_TableConfig.java} (92%) rename src/test/resources/outputs/{NamedTableWithSpecifiedForeignCollectionFieldConfig.java => NamedTableWithSpecifiedForeignCollectionField_TableConfig.java} (92%) rename src/test/resources/outputs/{UnnamedTableWithDefaultDatabaseFieldConfig.java => UnnamedTableWithDefaultDatabaseField_TableConfig.java} (79%) rename src/test/resources/outputs/{UnnamedTableWithDefaultForeignCollectionFieldConfig.java => UnnamedTableWithDefaultForeignCollectionField_TableConfig.java} (86%) diff --git a/pom.xml b/pom.xml index b8d4fb01..da792f9e 100644 --- a/pom.xml +++ b/pom.xml @@ -146,24 +146,24 @@ 1.5 1.5 - - - default-compile - - -proc:none - - com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java - - - - - compile-everything-else - compile - - compile - - - + + + default-compile + + -proc:none + + com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java + + + + + compile-everything-else + compile + + compile + + +
org.apache.maven.plugins diff --git a/src/main/java/com/j256/ormlite/android/annotations/DatabaseTables.java b/src/main/java/com/j256/ormlite/android/annotations/DatabaseTables.java new file mode 100644 index 00000000..e7f5c3cb --- /dev/null +++ b/src/main/java/com/j256/ormlite/android/annotations/DatabaseTables.java @@ -0,0 +1,12 @@ +package com.j256.ormlite.android.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface DatabaseTables { + Class[] value(); +} diff --git a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java similarity index 83% rename from src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java rename to src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java index 704199d3..e4b5557e 100644 --- a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java @@ -1,4 +1,4 @@ -package com.j256.ormlite.android.apptools; +package com.j256.ormlite.android.annotations; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.ForeignCollectionField; @@ -9,6 +9,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -16,6 +17,7 @@ import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.SourceVersion; import javax.lang.model.type.MirroredTypeException; @@ -28,31 +30,69 @@ //TODO: make sure no generated code is added to ormlite.android jar (and optimize pom) //TODO: add error messages //TODO: understand when/if columns need to be uppercased -//TODO: handle non-public entities (put generated files in same package) -//TODO: add @Generated annotation to generated files +//TODO: automatically call the generated code /** * Class that is automatically run when compiling client code that automatically - * generates an OrmLiteSqliteOpenHelper class that has inline code to generate - * the arguments for DaoManager.addCachedDatabaseConfigs() without needing a - * config file. + * generates code to call DaoManager.addCachedDatabaseConfigs() without needing + * a config file. * * @author nathancrouther */ // TODO: understand this @SuppressWarnings("restriction") public final class OrmLiteAnnotationProcessor extends AbstractProcessor { - private static final String PACKAGE = "com.j256.ormlite.android.apptools.tableconfigs"; - private static final String SUFFIX = "Config"; - private static final String FQCN_Object = "java.lang.Object"; private static final String FQCN_Class = "java.lang.Class"; static final class TableModel { - String fullyQualifiedClassName; - String simpleClassName; + String packageName; + List nestedClasses = new ArrayList(); DatabaseTable annotation; List fields = new ArrayList(); + + String getInputFullyQualifiedClassName() { + StringBuilder sb = new StringBuilder(); + if (!packageName.isEmpty()) { + sb.append(packageName); + sb.append('.'); + } + for (int i = 0; i < nestedClasses.size(); ++i) { + if (i != 0) { + sb.append('.'); + } + sb.append(nestedClasses.get(i)); + } + return sb.toString(); + } + + String getInputSimpleClassName() { + return nestedClasses.get(nestedClasses.size() - 1); + } + + String getGeneratedClassName() { + final String SUFFIX = "_TableConfig"; + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < nestedClasses.size(); ++i) { + if (i != 0) { + sb.append('_'); + } + sb.append(nestedClasses.get(i)); + } + sb.append(SUFFIX); + return sb.toString(); + } + + String getGeneratedFullyQualifiedClassName() { + StringBuilder sb = new StringBuilder(); + if (!packageName.isEmpty()) { + sb.append(packageName); + sb.append('.'); + } + sb.append(getGeneratedClassName()); + return sb.toString(); + } } static final class FieldModel { @@ -79,17 +119,13 @@ public boolean process(Set elements, RoundEnvironment env) { for (Element element : env .getElementsAnnotatedWith(DatabaseTable.class)) { - TypeElement tableClassElement = (TypeElement) element; TableModel table = new TableModel(); - table.fullyQualifiedClassName = tableClassElement - .getQualifiedName().toString(); - table.simpleClassName = tableClassElement.getSimpleName() - .toString(); - table.annotation = tableClassElement - .getAnnotation(DatabaseTable.class); + extractPackageAndNestedClasses(element, table); + table.annotation = element.getAnnotation(DatabaseTable.class); // get all fields from this and all parents until we hit Object + TypeElement tableClassElement = (TypeElement) element; do { for (Element child : tableClassElement.getEnclosedElements()) { if (child.getKind().isField()) { @@ -131,11 +167,24 @@ public boolean process(Set elements, return true; } + private void extractPackageAndNestedClasses(Element element, + TableModel table) { + Element enclosingElement = element; + do { + table.nestedClasses + .add(enclosingElement.getSimpleName().toString()); + enclosingElement = enclosingElement.getEnclosingElement(); + } while (enclosingElement.getKind().isClass()); + Collections.reverse(table.nestedClasses); + table.packageName = ((PackageElement) enclosingElement) + .getQualifiedName().toString(); + } + private void createSourceFile(TableModel table) { try { JavaFileObject javaFileObject = processingEnv.getFiler() .createSourceFile( - PACKAGE + "." + table.simpleClassName + SUFFIX); + table.getGeneratedFullyQualifiedClassName()); Writer writer = javaFileObject.openWriter(); try { @@ -149,21 +198,23 @@ private void createSourceFile(TableModel table) { } private void writeTable(Writer writer, TableModel table) throws IOException { - writer.write("package " + PACKAGE + ";\n"); - writer.write("\n"); + if (!table.packageName.isEmpty()) { + writer.write("package " + table.packageName + ";\n"); + writer.write("\n"); + } writer.write("import java.util.ArrayList;\n"); writer.write("import java.util.List;\n"); writer.write("\n"); writer.write("import com.j256.ormlite.field.DatabaseFieldConfig;\n"); writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); writer.write("\n"); - writer.write("public final class " + table.simpleClassName + SUFFIX + writer.write("public final class " + table.getGeneratedClassName() + " {\n"); - writer.write("\tprivate " + table.simpleClassName + SUFFIX + "() {\n"); + writer.write("\tprivate " + table.getGeneratedClassName() + "() {\n"); writer.write("\t}\n"); writer.write("\n"); writer.write("\tpublic static final DatabaseTableConfig<" - + table.fullyQualifiedClassName + "> CONFIG;\n"); + + table.getInputFullyQualifiedClassName() + "> CONFIG;\n"); writer.write("\n"); writer.write("\tstatic {\n"); writer.write("\t\tList databaseFieldConfigs = new ArrayList();\n"); @@ -326,13 +377,13 @@ private void writeTable(Writer writer, TableModel table) throws IOException { && table.annotation.tableName().length() > 0) { tableName = table.annotation.tableName(); } else { - tableName = table.simpleClassName.toLowerCase(); + tableName = table.getInputSimpleClassName().toLowerCase(); } writer.write(String .format("\t\tCONFIG = new DatabaseTableConfig<%s>(%s.class, \"%s\", databaseFieldConfigs);\n", - table.fullyQualifiedClassName, - table.fullyQualifiedClassName, tableName)); + table.getInputFullyQualifiedClassName(), + table.getInputFullyQualifiedClassName(), tableName)); writer.write("\t}\n"); writer.write("}\n"); } diff --git a/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/src/main/resources/META-INF/services/javax.annotation.processing.Processor index a7f6ca1e..83eb6add 100644 --- a/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ b/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -1 +1 @@ -com.j256.ormlite.android.apptools.OrmLiteAnnotationProcessor +com.j256.ormlite.android.annotations.OrmLiteAnnotationProcessor diff --git a/src/test/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessorTest.java b/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java similarity index 74% rename from src/test/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessorTest.java rename to src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java index 7e9a2a04..8549d9e4 100644 --- a/src/test/java/com/j256/ormlite/android/apptools/OrmLiteAnnotationProcessorTest.java +++ b/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java @@ -1,4 +1,4 @@ -package com.j256.ormlite.android.apptools; +package com.j256.ormlite.android.annotations; import static com.google.common.truth.Truth.assert_; import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; @@ -20,7 +20,7 @@ public void testDatabaseFieldAllDefaults() { .and() .generatesSources( JavaFileObjects - .forResource("outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java")); + .forResource("outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java")); } @Test @@ -34,9 +34,9 @@ public void testDatabaseFieldAllSpecified() { .and() .generatesSources( JavaFileObjects - .forResource("outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java")); + .forResource("outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java")); } - + @Test public void testForeignCollectionFieldAllDefaults() { assert_() @@ -48,9 +48,9 @@ public void testForeignCollectionFieldAllDefaults() { .and() .generatesSources( JavaFileObjects - .forResource("outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java")); + .forResource("outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java")); } - + @Test public void testForeignCollectionFieldAllSpecified() { assert_() @@ -62,6 +62,22 @@ public void testForeignCollectionFieldAllSpecified() { .and() .generatesSources( JavaFileObjects - .forResource("outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java")); + .forResource("outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java")); + } + + @Test + public void testInnerClasses() { + assert_() + .about(javaSource()) + .that(JavaFileObjects + .forResource("inputs/InnerClassTable.java")) + .processedWith(new OrmLiteAnnotationProcessor()) + .compilesWithoutError() + .and() + .generatesSources( + JavaFileObjects + .forResource("outputs/InnerClassTable_InnerClass_TableConfig.java"), + JavaFileObjects + .forResource("outputs/InnerClassTable_OtherInnerClass_TableConfig.java")); } } diff --git a/src/test/resources/inputs/InnerClassTable.java b/src/test/resources/inputs/InnerClassTable.java new file mode 100644 index 00000000..a0a13cc7 --- /dev/null +++ b/src/test/resources/inputs/InnerClassTable.java @@ -0,0 +1,18 @@ +package inputs; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +class InnerClassTable { + @DatabaseTable + static class InnerClass { + @DatabaseField + int field; + } + + @DatabaseTable + static class OtherInnerClass { + @DatabaseField + int field; + } +} diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java index 5f8e8b35..d18abb61 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java @@ -12,7 +12,7 @@ import com.j256.ormlite.table.DatabaseTable; @DatabaseTable(tableName = "table") -public class NamedTableWithSpecifiedDatabaseField { +class NamedTableWithSpecifiedDatabaseField { public static enum FieldTypeEnum { VALUE, OTHER_VALUE; @@ -135,8 +135,8 @@ public Object moveToNextValue(Object currentValue) throws SQLException { } @DatabaseField(columnName = "column", dataType = DataType.ENUM_INTEGER, defaultValue = "VALUE", width = 100, canBeNull = false, id = true, generatedId = true, generatedIdSequence = "id_sequence", foreign = true, useGetSet = true, unknownEnumName = "OTHER_VALUE", throwIfNull = true, format = "%f", unique = true, uniqueCombo = true, index = true, uniqueIndex = true, indexName = "index", uniqueIndexName = "unique_index", foreignAutoRefresh = true, maxForeignAutoRefreshLevel = 5, persisterClass = CustomPersister.class, allowGeneratedIdInsert = true, columnDefinition = "INT NOT NULL", foreignAutoCreate = true, version = true, foreignColumnName = "foreign", readOnly = true) - public FieldTypeEnum field; + FieldTypeEnum field; @DatabaseField(persisted = false) - public int ignored; + int ignored; } diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java index b7b5e3e2..4586a085 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java @@ -6,10 +6,10 @@ import com.j256.ormlite.table.DatabaseTable; @DatabaseTable(tableName = "table") -public class NamedTableWithSpecifiedForeignCollectionField { +class NamedTableWithSpecifiedForeignCollectionField { @ForeignCollectionField(eager = true, maxEagerLevel = 5, columnName = "column", orderColumnName = "order_column", orderAscending = false, foreignFieldName = "foreign_field") - public List numbers; + List numbers; @ForeignCollectionField(maxEagerForeignCollectionLevel = 5, foreignColumnName = "foreign_field") - public List numbers_deprecated; + List numbers_deprecated; } diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java index 61b680ea..58372367 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java @@ -4,7 +4,7 @@ import com.j256.ormlite.table.DatabaseTable; @DatabaseTable -public class UnnamedTableWithDefaultDatabaseField { +class UnnamedTableWithDefaultDatabaseField { @DatabaseField - public int field; + int field; } diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java index 3938f5d5..9e42a142 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java @@ -6,7 +6,7 @@ import com.j256.ormlite.table.DatabaseTable; @DatabaseTable -public class UnnamedTableWithDefaultForeignCollectionField { +class UnnamedTableWithDefaultForeignCollectionField { @ForeignCollectionField - public List numbers; + List numbers; } diff --git a/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java b/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java new file mode 100644 index 00000000..9294e2ab --- /dev/null +++ b/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java @@ -0,0 +1,23 @@ +package inputs; + +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.field.DatabaseFieldConfig; +import com.j256.ormlite.table.DatabaseTableConfig; + +public final class InnerClassTable_InnerClass_TableConfig { + private InnerClassTable_InnerClass_TableConfig() { + } + + public static final DatabaseTableConfig CONFIG; + + static { + List databaseFieldConfigs = new ArrayList(); + { + DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); + databaseFieldConfigs.add(databaseFieldConfig); + } + CONFIG = new DatabaseTableConfig(inputs.InnerClassTable.InnerClass.class, "innerclass", databaseFieldConfigs); + } +} diff --git a/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java b/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java new file mode 100644 index 00000000..83c93004 --- /dev/null +++ b/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java @@ -0,0 +1,23 @@ +package inputs; + +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.field.DatabaseFieldConfig; +import com.j256.ormlite.table.DatabaseTableConfig; + +public final class InnerClassTable_OtherInnerClass_TableConfig { + private InnerClassTable_OtherInnerClass_TableConfig() { + } + + public static final DatabaseTableConfig CONFIG; + + static { + List databaseFieldConfigs = new ArrayList(); + { + DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); + databaseFieldConfigs.add(databaseFieldConfig); + } + CONFIG = new DatabaseTableConfig(inputs.InnerClassTable.OtherInnerClass.class, "otherinnerclass", databaseFieldConfigs); + } +} diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java similarity index 92% rename from src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java rename to src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java index 8d300b76..dd05aeb0 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseFieldConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java @@ -1,4 +1,4 @@ -package com.j256.ormlite.android.apptools.tableconfigs; +package inputs; import java.util.ArrayList; import java.util.List; @@ -6,8 +6,8 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; -public final class NamedTableWithSpecifiedDatabaseFieldConfig { - private NamedTableWithSpecifiedDatabaseFieldConfig() { +public final class NamedTableWithSpecifiedDatabaseField_TableConfig { + private NamedTableWithSpecifiedDatabaseField_TableConfig() { } public static final DatabaseTableConfig CONFIG; diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java similarity index 92% rename from src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java rename to src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java index 5b7f0c08..0cf646d5 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionFieldConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java @@ -1,4 +1,4 @@ -package com.j256.ormlite.android.apptools.tableconfigs; +package inputs; import java.util.ArrayList; import java.util.List; @@ -6,8 +6,8 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; -public final class NamedTableWithSpecifiedForeignCollectionFieldConfig { - private NamedTableWithSpecifiedForeignCollectionFieldConfig() { +public final class NamedTableWithSpecifiedForeignCollectionField_TableConfig { + private NamedTableWithSpecifiedForeignCollectionField_TableConfig() { } public static final DatabaseTableConfig CONFIG; diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java similarity index 79% rename from src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java rename to src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java index ac8a6655..db958ea8 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseFieldConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java @@ -1,4 +1,4 @@ -package com.j256.ormlite.android.apptools.tableconfigs; +package inputs; import java.util.ArrayList; import java.util.List; @@ -6,8 +6,8 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; -public final class UnnamedTableWithDefaultDatabaseFieldConfig { - private UnnamedTableWithDefaultDatabaseFieldConfig() { +public final class UnnamedTableWithDefaultDatabaseField_TableConfig { + private UnnamedTableWithDefaultDatabaseField_TableConfig() { } public static final DatabaseTableConfig CONFIG; diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java similarity index 86% rename from src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java rename to src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java index dfd82d03..d6bbb46c 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionFieldConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java @@ -1,4 +1,4 @@ -package com.j256.ormlite.android.apptools.tableconfigs; +package inputs; import java.util.ArrayList; import java.util.List; @@ -6,8 +6,8 @@ import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; -public final class UnnamedTableWithDefaultForeignCollectionFieldConfig { - private UnnamedTableWithDefaultForeignCollectionFieldConfig() { +public final class UnnamedTableWithDefaultForeignCollectionField_TableConfig { + private UnnamedTableWithDefaultForeignCollectionField_TableConfig() { } public static final DatabaseTableConfig CONFIG; From 0a60583b2d428583ccf533e2609886d619f0bba4 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 7 May 2015 20:34:36 -0700 Subject: [PATCH 08/26] Add processing skeleton for DatabaseTables annotation --- .../OrmLiteAnnotationProcessor.java | 63 +++++++++++++++++++ .../resources/inputs/InnerClassTable.java | 7 ++- .../NamedTableWithSpecifiedDatabaseField.java | 5 ++ ...leWithSpecifiedForeignCollectionField.java | 5 ++ .../UnnamedTableWithDefaultDatabaseField.java | 5 ++ ...ableWithDefaultForeignCollectionField.java | 5 ++ 6 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java index e4b5557e..f2fc7117 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java @@ -10,6 +10,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -21,6 +22,8 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.SourceVersion; import javax.lang.model.type.MirroredTypeException; +import javax.lang.model.type.MirroredTypesException; +import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileObject; @@ -45,6 +48,9 @@ public final class OrmLiteAnnotationProcessor extends AbstractProcessor { private static final String FQCN_Object = "java.lang.Object"; private static final String FQCN_Class = "java.lang.Class"; + private Set declaredTables = new HashSet(); + private Set foundTables = new HashSet(); + static final class TableModel { String packageName; List nestedClasses = new ArrayList(); @@ -106,6 +112,7 @@ static final class FieldModel { public Set getSupportedAnnotationTypes() { Set types = new LinkedHashSet(); types.add(DatabaseTable.class.getCanonicalName()); + types.add(DatabaseTables.class.getCanonicalName()); return types; } @@ -119,6 +126,9 @@ public boolean process(Set elements, RoundEnvironment env) { for (Element element : env .getElementsAnnotatedWith(DatabaseTable.class)) { + if (element.getAnnotation(DatabaseTable.class) == null) { + continue; + } TableModel table = new TableModel(); extractPackageAndNestedClasses(element, table); @@ -126,6 +136,7 @@ public boolean process(Set elements, // get all fields from this and all parents until we hit Object TypeElement tableClassElement = (TypeElement) element; + foundTables.add(tableClassElement); do { for (Element child : tableClassElement.getEnclosedElements()) { if (child.getKind().isField()) { @@ -164,6 +175,58 @@ public boolean process(Set elements, createSourceFile(table); } + Set tablesCollectionElements = env + .getElementsAnnotatedWith(DatabaseTables.class); + for (Element element : tablesCollectionElements) { + DatabaseTables annotation = element + .getAnnotation(DatabaseTables.class); + if (annotation == null) { + continue; + } + try { + Class[] classes = annotation.value(); + for (int i = 0; i < classes.length; ++i) { + TypeElement typeElement; + try { + typeElement = processingEnv.getElementUtils() + .getTypeElement(classes[i].getCanonicalName()); + } catch (MirroredTypeException mte) { + typeElement = (TypeElement) processingEnv + .getTypeUtils().asElement(mte.getTypeMirror()); + } + declaredTables.add(typeElement); + } + } catch (MirroredTypesException mte) { + for (TypeMirror m : mte.getTypeMirrors()) { + declaredTables.add((TypeElement) processingEnv + .getTypeUtils().asElement(m)); + } + } + + // TODO: generate class for database that creates tables and loads + // the cached field info + } + + if (env.processingOver()) { + for (TypeElement declared : declaredTables) { + if (foundTables.contains(declared)) { + foundTables.remove(declared); + } else { + // TODO: tag the declaration annotation with an error + } + } + + for (TypeElement undeclared : foundTables) { + // TODO: make warning + raiseError( + String.format( + "Class annotated with %s is not declared in any %s annotation", + DatabaseTable.class.getSimpleName(), + DatabaseTables.class.getSimpleName()), + undeclared); + } + } + return true; } diff --git a/src/test/resources/inputs/InnerClassTable.java b/src/test/resources/inputs/InnerClassTable.java index a0a13cc7..90f7dc76 100644 --- a/src/test/resources/inputs/InnerClassTable.java +++ b/src/test/resources/inputs/InnerClassTable.java @@ -1,5 +1,6 @@ package inputs; +import com.j256.ormlite.android.annotations.DatabaseTables; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; @@ -9,10 +10,14 @@ static class InnerClass { @DatabaseField int field; } - + @DatabaseTable static class OtherInnerClass { @DatabaseField int field; } + + @DatabaseTables({ InnerClass.class, OtherInnerClass.class }) + static class Main { + } } diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java index d18abb61..6a2e66e8 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java @@ -3,6 +3,7 @@ import java.lang.reflect.Field; import java.sql.SQLException; +import com.j256.ormlite.android.annotations.DatabaseTables; import com.j256.ormlite.field.DataPersister; import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; @@ -139,4 +140,8 @@ public Object moveToNextValue(Object currentValue) throws SQLException { @DatabaseField(persisted = false) int ignored; + + @DatabaseTables(NamedTableWithSpecifiedDatabaseField.class) + static class Main { + } } diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java index 4586a085..d77ed7be 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java @@ -2,6 +2,7 @@ import java.util.List; +import com.j256.ormlite.android.annotations.DatabaseTables; import com.j256.ormlite.field.ForeignCollectionField; import com.j256.ormlite.table.DatabaseTable; @@ -12,4 +13,8 @@ class NamedTableWithSpecifiedForeignCollectionField { @ForeignCollectionField(maxEagerForeignCollectionLevel = 5, foreignColumnName = "foreign_field") List numbers_deprecated; + + @DatabaseTables(NamedTableWithSpecifiedForeignCollectionField.class) + static class Main { + } } diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java index 58372367..cbb85ae1 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java @@ -1,5 +1,6 @@ package inputs; +import com.j256.ormlite.android.annotations.DatabaseTables; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; @@ -7,4 +8,8 @@ class UnnamedTableWithDefaultDatabaseField { @DatabaseField int field; + + @DatabaseTables(UnnamedTableWithDefaultDatabaseField.class) + static class Main { + } } diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java index 9e42a142..453b257f 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java @@ -2,6 +2,7 @@ import java.util.List; +import com.j256.ormlite.android.annotations.DatabaseTables; import com.j256.ormlite.field.ForeignCollectionField; import com.j256.ormlite.table.DatabaseTable; @@ -9,4 +10,8 @@ class UnnamedTableWithDefaultForeignCollectionField { @ForeignCollectionField List numbers; + + @DatabaseTables(UnnamedTableWithDefaultForeignCollectionField.class) + static class Main { + } } From 589ab1b3a05a894152a5e977434076b970aaff28 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 7 May 2015 20:38:20 -0700 Subject: [PATCH 09/26] Add more consistency checks --- .../{DatabaseTables.java => Database.java} | 2 +- .../OrmLiteAnnotationProcessor.java | 126 ++++++++++++++---- .../resources/inputs/InnerClassTable.java | 14 +- .../NamedTableWithSpecifiedDatabaseField.java | 14 +- ...leWithSpecifiedForeignCollectionField.java | 14 +- .../UnnamedTableWithDefaultDatabaseField.java | 14 +- ...ableWithDefaultForeignCollectionField.java | 14 +- 7 files changed, 153 insertions(+), 45 deletions(-) rename src/main/java/com/j256/ormlite/android/annotations/{DatabaseTables.java => Database.java} (89%) diff --git a/src/main/java/com/j256/ormlite/android/annotations/DatabaseTables.java b/src/main/java/com/j256/ormlite/android/annotations/Database.java similarity index 89% rename from src/main/java/com/j256/ormlite/android/annotations/DatabaseTables.java rename to src/main/java/com/j256/ormlite/android/annotations/Database.java index e7f5c3cb..0822dc56 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/DatabaseTables.java +++ b/src/main/java/com/j256/ormlite/android/annotations/Database.java @@ -7,6 +7,6 @@ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) -public @interface DatabaseTables { +public @interface Database { Class[] value(); } diff --git a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java index f2fc7117..3bf98546 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java @@ -10,9 +10,11 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; @@ -28,12 +30,7 @@ import javax.tools.JavaFileObject; //TODO: handle javax.persistance annotations -//TODO: add note that this must be updated to Annotation classes //TODO: analyze if this should be part of core (and if config file stuff can be removed) -//TODO: make sure no generated code is added to ormlite.android jar (and optimize pom) -//TODO: add error messages -//TODO: understand when/if columns need to be uppercased -//TODO: automatically call the generated code /** * Class that is automatically run when compiling client code that automatically @@ -48,7 +45,12 @@ public final class OrmLiteAnnotationProcessor extends AbstractProcessor { private static final String FQCN_Object = "java.lang.Object"; private static final String FQCN_Class = "java.lang.Class"; + // TODO: understand why reading these from Class throws exception + private static final String FQCN_OpenHelper = "com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper"; + private static final String CN_OpenHelper = "OrmLiteSqliteOpenHelper"; + private Set declaredTables = new HashSet(); + private Map> declaredTableToDatabaseMap = new HashMap>(); private Set foundTables = new HashSet(); static final class TableModel { @@ -112,7 +114,7 @@ static final class FieldModel { public Set getSupportedAnnotationTypes() { Set types = new LinkedHashSet(); types.add(DatabaseTable.class.getCanonicalName()); - types.add(DatabaseTables.class.getCanonicalName()); + types.add(Database.class.getCanonicalName()); return types; } @@ -172,37 +174,91 @@ public boolean process(Set elements, } while (!tableClassElement.getQualifiedName().toString() .equals(FQCN_Object)); - createSourceFile(table); + if (table.fields.isEmpty()) { + raiseWarning( + String.format( + "No fields annotated with %s found for class annotated with %s", + DatabaseField.class.getSimpleName(), + DatabaseTable.class.getSimpleName()), element); + } + + createSourceFile(table, element); } Set tablesCollectionElements = env - .getElementsAnnotatedWith(DatabaseTables.class); + .getElementsAnnotatedWith(Database.class); for (Element element : tablesCollectionElements) { - DatabaseTables annotation = element - .getAnnotation(DatabaseTables.class); + Database annotation = element.getAnnotation(Database.class); if (annotation == null) { continue; } + + boolean derivedFromOpenHelper = false; + TypeElement annotatedClassElement = (TypeElement) element; + do { + if (annotatedClassElement.getQualifiedName().toString() + .equals(FQCN_OpenHelper)) { + derivedFromOpenHelper = true; + } + annotatedClassElement = (TypeElement) processingEnv + .getTypeUtils().asElement( + annotatedClassElement.getSuperclass()); + } while (!annotatedClassElement.getQualifiedName().toString() + .equals(FQCN_Object)); + if (!derivedFromOpenHelper) { + raiseError( + String.format( + "%s annotation must be applied to a class deriving from %s", + Database.class.getSimpleName(), CN_OpenHelper), + element); + } + + List tableTypes = new ArrayList(); try { Class[] classes = annotation.value(); - for (int i = 0; i < classes.length; ++i) { - TypeElement typeElement; - try { - typeElement = processingEnv.getElementUtils() - .getTypeElement(classes[i].getCanonicalName()); - } catch (MirroredTypeException mte) { - typeElement = (TypeElement) processingEnv - .getTypeUtils().asElement(mte.getTypeMirror()); + // TODO: understand why this is ever null + if (classes != null) { + for (int i = 0; i < classes.length; ++i) { + TypeElement typeElement; + try { + typeElement = processingEnv.getElementUtils() + .getTypeElement( + classes[i].getCanonicalName()); + } catch (MirroredTypeException mte) { + typeElement = (TypeElement) processingEnv + .getTypeUtils().asElement( + mte.getTypeMirror()); + } + tableTypes.add(typeElement); } - declaredTables.add(typeElement); } } catch (MirroredTypesException mte) { for (TypeMirror m : mte.getTypeMirrors()) { - declaredTables.add((TypeElement) processingEnv - .getTypeUtils().asElement(m)); + tableTypes.add((TypeElement) processingEnv.getTypeUtils() + .asElement(m)); } } + if (tableTypes.isEmpty()) { + raiseError( + String.format( + "%s annotation must contain at least one class annotated with %s", + Database.class.getSimpleName(), + DatabaseTable.class.getSimpleName()), element); + } + + for (TypeElement tableType : tableTypes) { + List databases = declaredTableToDatabaseMap + .get(tableType); + if (databases == null) { + databases = new ArrayList(); + declaredTableToDatabaseMap.put(tableType, databases); + } + databases.add((TypeElement) element); + + declaredTables.add(tableType); + } + // TODO: generate class for database that creates tables and loads // the cached field info } @@ -212,18 +268,24 @@ public boolean process(Set elements, if (foundTables.contains(declared)) { foundTables.remove(declared); } else { - // TODO: tag the declaration annotation with an error + for (TypeElement database : declaredTableToDatabaseMap + .get(declared)) { + raiseError( + String.format( + "%s annotation must contain only classes annotated with %s", + Database.class.getSimpleName(), + DatabaseTable.class.getSimpleName()), + database); + } } } for (TypeElement undeclared : foundTables) { - // TODO: make warning - raiseError( + raiseWarning( String.format( - "Class annotated with %s is not declared in any %s annotation", + "Class annotated with %s is not included in any %s annotation", DatabaseTable.class.getSimpleName(), - DatabaseTables.class.getSimpleName()), - undeclared); + Database.class.getSimpleName()), undeclared); } } @@ -243,11 +305,12 @@ private void extractPackageAndNestedClasses(Element element, .getQualifiedName().toString(); } - private void createSourceFile(TableModel table) { + private void createSourceFile(TableModel table, Element tableClassElement) { try { JavaFileObject javaFileObject = processingEnv.getFiler() .createSourceFile( - table.getGeneratedFullyQualifiedClassName()); + table.getGeneratedFullyQualifiedClassName(), + tableClassElement); Writer writer = javaFileObject.openWriter(); try { @@ -518,6 +581,11 @@ private static void writeSetter(Object value, String setterCall, + ";\n", value)); } + private void raiseWarning(String message, Element element) { + this.processingEnv.getMessager().printMessage(Kind.WARNING, message, + element); + } + private void raiseError(String message, Element element) { this.processingEnv.getMessager().printMessage(Kind.ERROR, message, element); diff --git a/src/test/resources/inputs/InnerClassTable.java b/src/test/resources/inputs/InnerClassTable.java index 90f7dc76..ee6b3404 100644 --- a/src/test/resources/inputs/InnerClassTable.java +++ b/src/test/resources/inputs/InnerClassTable.java @@ -1,6 +1,10 @@ package inputs; -import com.j256.ormlite.android.annotations.DatabaseTables; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase.CursorFactory; + +import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; @@ -17,7 +21,11 @@ static class OtherInnerClass { int field; } - @DatabaseTables({ InnerClass.class, OtherInnerClass.class }) - static class Main { + @Database({ InnerClass.class, OtherInnerClass.class }) + static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { + OpenHelper(Context context, String databaseName, CursorFactory factory, + int databaseVersion) { + super(context, databaseName, factory, databaseVersion); + } } } diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java index 6a2e66e8..9cd641e1 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java @@ -3,7 +3,11 @@ import java.lang.reflect.Field; import java.sql.SQLException; -import com.j256.ormlite.android.annotations.DatabaseTables; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase.CursorFactory; + +import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.DataPersister; import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; @@ -141,7 +145,11 @@ public Object moveToNextValue(Object currentValue) throws SQLException { @DatabaseField(persisted = false) int ignored; - @DatabaseTables(NamedTableWithSpecifiedDatabaseField.class) - static class Main { + @Database(NamedTableWithSpecifiedDatabaseField.class) + static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { + OpenHelper(Context context, String databaseName, CursorFactory factory, + int databaseVersion) { + super(context, databaseName, factory, databaseVersion); + } } } diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java index d77ed7be..3b55628d 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java @@ -2,7 +2,11 @@ import java.util.List; -import com.j256.ormlite.android.annotations.DatabaseTables; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase.CursorFactory; + +import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.ForeignCollectionField; import com.j256.ormlite.table.DatabaseTable; @@ -14,7 +18,11 @@ class NamedTableWithSpecifiedForeignCollectionField { @ForeignCollectionField(maxEagerForeignCollectionLevel = 5, foreignColumnName = "foreign_field") List numbers_deprecated; - @DatabaseTables(NamedTableWithSpecifiedForeignCollectionField.class) - static class Main { + @Database(NamedTableWithSpecifiedForeignCollectionField.class) + static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { + OpenHelper(Context context, String databaseName, CursorFactory factory, + int databaseVersion) { + super(context, databaseName, factory, databaseVersion); + } } } diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java index cbb85ae1..50d705d8 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java @@ -1,6 +1,10 @@ package inputs; -import com.j256.ormlite.android.annotations.DatabaseTables; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase.CursorFactory; + +import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; @@ -9,7 +13,11 @@ class UnnamedTableWithDefaultDatabaseField { @DatabaseField int field; - @DatabaseTables(UnnamedTableWithDefaultDatabaseField.class) - static class Main { + @Database(UnnamedTableWithDefaultDatabaseField.class) + static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { + OpenHelper(Context context, String databaseName, CursorFactory factory, + int databaseVersion) { + super(context, databaseName, factory, databaseVersion); + } } } diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java index 453b257f..510f023f 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java @@ -2,7 +2,11 @@ import java.util.List; -import com.j256.ormlite.android.annotations.DatabaseTables; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase.CursorFactory; + +import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.ForeignCollectionField; import com.j256.ormlite.table.DatabaseTable; @@ -11,7 +15,11 @@ class UnnamedTableWithDefaultForeignCollectionField { @ForeignCollectionField List numbers; - @DatabaseTables(UnnamedTableWithDefaultForeignCollectionField.class) - static class Main { + @Database(UnnamedTableWithDefaultForeignCollectionField.class) + static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { + OpenHelper(Context context, String databaseName, CursorFactory factory, + int databaseVersion) { + super(context, databaseName, factory, databaseVersion); + } } } From d0b5dbe60d634a86c4d5d65afb63617da7d80307 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 7 May 2015 20:39:19 -0700 Subject: [PATCH 10/26] Fix crashes during incremental builds --- .../OrmLiteAnnotationProcessor.java | 31 ++++++++++++++++--- .../NamedTableWithSpecifiedDatabaseField.java | 2 +- ...leWithSpecifiedForeignCollectionField.java | 2 +- .../UnnamedTableWithDefaultDatabaseField.java | 2 +- ...ableWithDefaultForeignCollectionField.java | 2 +- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java index 3bf98546..5519ef3c 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java @@ -18,6 +18,7 @@ import java.util.Set; import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.FilerException; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.PackageElement; @@ -216,7 +217,6 @@ public boolean process(Set elements, List tableTypes = new ArrayList(); try { Class[] classes = annotation.value(); - // TODO: understand why this is ever null if (classes != null) { for (int i = 0; i < classes.length; ++i) { TypeElement typeElement; @@ -231,6 +231,13 @@ public boolean process(Set elements, } tableTypes.add(typeElement); } + } else { + // eclipse populates this with null if annotation populated + // with scalar (no {}) even though this is a legal shortcut + raiseError(String.format( + "%s annotation must enclose values array with {}", + Database.class.getSimpleName()), element); + continue; } } catch (MirroredTypesException mte) { for (TypeMirror m : mte.getTypeMirrors()) { @@ -264,9 +271,12 @@ public boolean process(Set elements, } if (env.processingOver()) { + Set undeclaredFoundTables = new HashSet( + foundTables); + for (TypeElement declared : declaredTables) { if (foundTables.contains(declared)) { - foundTables.remove(declared); + undeclaredFoundTables.remove(declared); } else { for (TypeElement database : declaredTableToDatabaseMap .get(declared)) { @@ -280,7 +290,7 @@ public boolean process(Set elements, } } - for (TypeElement undeclared : foundTables) { + for (TypeElement undeclared : undeclaredFoundTables) { raiseWarning( String.format( "Class annotated with %s is not included in any %s annotation", @@ -318,12 +328,21 @@ private void createSourceFile(TableModel table, Element tableClassElement) { } finally { writer.close(); } + } catch (FilerException e) { + // if multiple classes are in the same file (e.g. inner/nested + // classes), eclipse will do an incremental compilation for all of + // them. The unchanged ones' generated files will not be deleted, so + // we can ignore this benign error. + raiseNote(String + .format("Skipping file generation for %s since file already exists", + table.getGeneratedFullyQualifiedClassName())); } catch (IOException e) { throw new RuntimeException(e); } } - private void writeTable(Writer writer, TableModel table) throws IOException { + private static void writeTable(Writer writer, TableModel table) + throws IOException { if (!table.packageName.isEmpty()) { writer.write("package " + table.packageName + ";\n"); writer.write("\n"); @@ -581,6 +600,10 @@ private static void writeSetter(Object value, String setterCall, + ";\n", value)); } + private void raiseNote(String message) { + this.processingEnv.getMessager().printMessage(Kind.NOTE, message); + } + private void raiseWarning(String message, Element element) { this.processingEnv.getMessager().printMessage(Kind.WARNING, message, element); diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java index 9cd641e1..93b399dd 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java @@ -145,7 +145,7 @@ public Object moveToNextValue(Object currentValue) throws SQLException { @DatabaseField(persisted = false) int ignored; - @Database(NamedTableWithSpecifiedDatabaseField.class) + @Database({ NamedTableWithSpecifiedDatabaseField.class }) static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { OpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java index 3b55628d..4597876e 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java @@ -18,7 +18,7 @@ class NamedTableWithSpecifiedForeignCollectionField { @ForeignCollectionField(maxEagerForeignCollectionLevel = 5, foreignColumnName = "foreign_field") List numbers_deprecated; - @Database(NamedTableWithSpecifiedForeignCollectionField.class) + @Database({ NamedTableWithSpecifiedForeignCollectionField.class }) static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { OpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java index 50d705d8..1d4fee13 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java @@ -13,7 +13,7 @@ class UnnamedTableWithDefaultDatabaseField { @DatabaseField int field; - @Database(UnnamedTableWithDefaultDatabaseField.class) + @Database({ UnnamedTableWithDefaultDatabaseField.class }) static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { OpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java index 510f023f..79944c4b 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java @@ -15,7 +15,7 @@ class UnnamedTableWithDefaultForeignCollectionField { @ForeignCollectionField List numbers; - @Database(UnnamedTableWithDefaultForeignCollectionField.class) + @Database({ UnnamedTableWithDefaultForeignCollectionField.class }) static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { OpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { From 3c90306d82ce63a1583450c84d5a05ee03e60f68 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 7 May 2015 20:46:26 -0700 Subject: [PATCH 11/26] Generate file to cache table configurations --- .../OrmLiteAnnotationProcessor.java | 143 +++++++++++++----- .../OrmLiteAnnotationProcessorTest.java | 20 ++- .../resources/inputs/InnerClassTable.java | 16 ++ .../NamedTableWithSpecifiedDatabaseField.java | 15 ++ ...leWithSpecifiedForeignCollectionField.java | 18 ++- .../UnnamedTableWithDefaultDatabaseField.java | 19 ++- ...ableWithDefaultForeignCollectionField.java | 16 ++ ...nnerClassTable_OpenHelper_TableConfig.java | 27 ++++ ...dDatabaseField_OpenHelper_TableConfig.java | 25 +++ ...ollectionField_OpenHelper_TableConfig.java | 25 +++ ...tDatabaseField_OpenHelper_TableConfig.java | 25 +++ ...ollectionField_OpenHelper_TableConfig.java | 25 +++ 12 files changed, 333 insertions(+), 41 deletions(-) create mode 100644 src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java create mode 100644 src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java create mode 100644 src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java create mode 100644 src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java create mode 100644 src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java diff --git a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java index 5519ef3c..53a64ed9 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java @@ -32,6 +32,7 @@ //TODO: handle javax.persistance annotations //TODO: analyze if this should be part of core (and if config file stuff can be removed) +//TODO: handle incremental compilation across files /** * Class that is automatically run when compiling client code that automatically @@ -54,11 +55,20 @@ public final class OrmLiteAnnotationProcessor extends AbstractProcessor { private Map> declaredTableToDatabaseMap = new HashMap>(); private Set foundTables = new HashSet(); - static final class TableModel { - String packageName; - List nestedClasses = new ArrayList(); - DatabaseTable annotation; - List fields = new ArrayList(); + private static final class ParsedClassName { + private String packageName; + private List nestedClasses = new ArrayList(); + + ParsedClassName(Element element) { + Element elementIterator = element; + do { + nestedClasses.add(elementIterator.getSimpleName().toString()); + elementIterator = elementIterator.getEnclosingElement(); + } while (elementIterator.getKind().isClass()); + Collections.reverse(nestedClasses); + packageName = ((PackageElement) elementIterator).getQualifiedName() + .toString(); + } String getInputFullyQualifiedClassName() { StringBuilder sb = new StringBuilder(); @@ -104,7 +114,13 @@ String getGeneratedFullyQualifiedClassName() { } } - static final class FieldModel { + private static final class TableModel { + ParsedClassName parsedClassName; + DatabaseTable annotation; + List fields = new ArrayList(); + } + + private static final class FieldModel { String fullyQualifiedTypeName; String fieldName; DatabaseField databaseFieldAnnotation; @@ -134,7 +150,7 @@ public boolean process(Set elements, } TableModel table = new TableModel(); - extractPackageAndNestedClasses(element, table); + table.parsedClassName = new ParsedClassName(element); table.annotation = element.getAnnotation(DatabaseTable.class); // get all fields from this and all parents until we hit Object @@ -183,7 +199,7 @@ public boolean process(Set elements, DatabaseTable.class.getSimpleName()), element); } - createSourceFile(table, element); + createTableConfigSourceFile(table, element); } Set tablesCollectionElements = env @@ -266,8 +282,7 @@ public boolean process(Set elements, declaredTables.add(tableType); } - // TODO: generate class for database that creates tables and loads - // the cached field info + createDatabaseConfigSourceFile((TypeElement) element, tableTypes); } if (env.processingOver()) { @@ -302,24 +317,79 @@ public boolean process(Set elements, return true; } - private void extractPackageAndNestedClasses(Element element, - TableModel table) { - Element enclosingElement = element; - do { - table.nestedClasses - .add(enclosingElement.getSimpleName().toString()); - enclosingElement = enclosingElement.getEnclosingElement(); - } while (enclosingElement.getKind().isClass()); - Collections.reverse(table.nestedClasses); - table.packageName = ((PackageElement) enclosingElement) - .getQualifiedName().toString(); + private void createDatabaseConfigSourceFile(TypeElement openHelperClass, + List tableClasses) { + try { + ParsedClassName openHelperClassName = new ParsedClassName( + openHelperClass); + + JavaFileObject javaFileObject = processingEnv + .getFiler() + .createSourceFile( + openHelperClassName + .getGeneratedFullyQualifiedClassName(), + openHelperClass); + + Writer writer = javaFileObject.openWriter(); + try { + writer.write("package " + openHelperClassName.packageName + + ";\n"); + writer.write("\n"); + writer.write("import java.sql.SQLException;\n"); + writer.write("import java.util.ArrayList;\n"); + writer.write("import java.util.List;\n"); + writer.write("\n"); + writer.write("import com.j256.ormlite.dao.DaoManager;\n"); + writer.write("import com.j256.ormlite.support.ConnectionSource;\n"); + writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); + writer.write("import com.j256.ormlite.table.TableUtils;\n"); + writer.write("\n"); + writer.write("public final class " + + openHelperClassName.getGeneratedClassName() + " {\n"); + writer.write("\tprivate " + + openHelperClassName.getGeneratedClassName() + + "() {\n"); + writer.write("\t}\n"); + writer.write("\n"); + writer.write("\tpublic static void cacheTableConfigurations() {\n"); + writer.write("\t\tList> tableConfigs = new ArrayList>();\n"); + for (TypeElement tableClass : tableClasses) { + ParsedClassName tableClassName = new ParsedClassName( + tableClass); + writer.write("\t\ttableConfigs.add(" + + tableClassName + .getGeneratedFullyQualifiedClassName() + + ".CONFIG);\n"); + } + writer.write("\t\tDaoManager.addCachedDatabaseConfigs(tableConfigs);\n"); + writer.write("\t}\n"); + writer.write("\n"); + writer.write("\tpublic static void createTables(ConnectionSource connectionSource) throws SQLException {\n"); + for (TypeElement tableClass : tableClasses) { + ParsedClassName tableClassName = new ParsedClassName( + tableClass); + writer.write("\t\tTableUtils.createTable(connectionSource, " + + tableClassName.getInputFullyQualifiedClassName() + + ".class);\n"); + } + writer.write("\t}\n"); + writer.write("}\n"); + } finally { + writer.close(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } } - private void createSourceFile(TableModel table, Element tableClassElement) { + private void createTableConfigSourceFile(TableModel table, + Element tableClassElement) { try { - JavaFileObject javaFileObject = processingEnv.getFiler() + JavaFileObject javaFileObject = processingEnv + .getFiler() .createSourceFile( - table.getGeneratedFullyQualifiedClassName(), + table.parsedClassName + .getGeneratedFullyQualifiedClassName(), tableClassElement); Writer writer = javaFileObject.openWriter(); @@ -335,7 +405,8 @@ private void createSourceFile(TableModel table, Element tableClassElement) { // we can ignore this benign error. raiseNote(String .format("Skipping file generation for %s since file already exists", - table.getGeneratedFullyQualifiedClassName())); + table.parsedClassName + .getGeneratedFullyQualifiedClassName())); } catch (IOException e) { throw new RuntimeException(e); } @@ -343,8 +414,8 @@ private void createSourceFile(TableModel table, Element tableClassElement) { private static void writeTable(Writer writer, TableModel table) throws IOException { - if (!table.packageName.isEmpty()) { - writer.write("package " + table.packageName + ";\n"); + if (!table.parsedClassName.packageName.isEmpty()) { + writer.write("package " + table.parsedClassName.packageName + ";\n"); writer.write("\n"); } writer.write("import java.util.ArrayList;\n"); @@ -353,13 +424,15 @@ private static void writeTable(Writer writer, TableModel table) writer.write("import com.j256.ormlite.field.DatabaseFieldConfig;\n"); writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); writer.write("\n"); - writer.write("public final class " + table.getGeneratedClassName() - + " {\n"); - writer.write("\tprivate " + table.getGeneratedClassName() + "() {\n"); + writer.write("public final class " + + table.parsedClassName.getGeneratedClassName() + " {\n"); + writer.write("\tprivate " + + table.parsedClassName.getGeneratedClassName() + "() {\n"); writer.write("\t}\n"); writer.write("\n"); writer.write("\tpublic static final DatabaseTableConfig<" - + table.getInputFullyQualifiedClassName() + "> CONFIG;\n"); + + table.parsedClassName.getInputFullyQualifiedClassName() + + "> CONFIG;\n"); writer.write("\n"); writer.write("\tstatic {\n"); writer.write("\t\tList databaseFieldConfigs = new ArrayList();\n"); @@ -522,13 +595,15 @@ private static void writeTable(Writer writer, TableModel table) && table.annotation.tableName().length() > 0) { tableName = table.annotation.tableName(); } else { - tableName = table.getInputSimpleClassName().toLowerCase(); + tableName = table.parsedClassName.getInputSimpleClassName() + .toLowerCase(); } writer.write(String .format("\t\tCONFIG = new DatabaseTableConfig<%s>(%s.class, \"%s\", databaseFieldConfigs);\n", - table.getInputFullyQualifiedClassName(), - table.getInputFullyQualifiedClassName(), tableName)); + table.parsedClassName.getInputFullyQualifiedClassName(), + table.parsedClassName.getInputFullyQualifiedClassName(), + tableName)); writer.write("\t}\n"); writer.write("}\n"); } diff --git a/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java b/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java index 8549d9e4..8e985948 100644 --- a/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java +++ b/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java @@ -20,7 +20,9 @@ public void testDatabaseFieldAllDefaults() { .and() .generatesSources( JavaFileObjects - .forResource("outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java")); + .forResource("outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java"), + JavaFileObjects + .forResource("outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java")); } @Test @@ -34,7 +36,9 @@ public void testDatabaseFieldAllSpecified() { .and() .generatesSources( JavaFileObjects - .forResource("outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java")); + .forResource("outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java"), + JavaFileObjects + .forResource("outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java")); } @Test @@ -48,7 +52,9 @@ public void testForeignCollectionFieldAllDefaults() { .and() .generatesSources( JavaFileObjects - .forResource("outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java")); + .forResource("outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java"), + JavaFileObjects + .forResource("outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java")); } @Test @@ -62,7 +68,9 @@ public void testForeignCollectionFieldAllSpecified() { .and() .generatesSources( JavaFileObjects - .forResource("outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java")); + .forResource("outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java"), + JavaFileObjects + .forResource("outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java")); } @Test @@ -78,6 +86,8 @@ public void testInnerClasses() { JavaFileObjects .forResource("outputs/InnerClassTable_InnerClass_TableConfig.java"), JavaFileObjects - .forResource("outputs/InnerClassTable_OtherInnerClass_TableConfig.java")); + .forResource("outputs/InnerClassTable_OtherInnerClass_TableConfig.java"), + JavaFileObjects + .forResource("outputs/InnerClassTable_OpenHelper_TableConfig.java")); } } diff --git a/src/test/resources/inputs/InnerClassTable.java b/src/test/resources/inputs/InnerClassTable.java index ee6b3404..2e460ddf 100644 --- a/src/test/resources/inputs/InnerClassTable.java +++ b/src/test/resources/inputs/InnerClassTable.java @@ -1,11 +1,15 @@ package inputs; +import java.sql.SQLException; + import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import com.j256.ormlite.android.annotations.Database; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTable; class InnerClassTable { @@ -26,6 +30,18 @@ static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { OpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { super(context, databaseName, factory, databaseVersion); + InnerClassTable_OpenHelper_TableConfig.cacheTableConfigurations(); + } + + @Override + public void onCreate(SQLiteDatabase database, + ConnectionSource connectionSource) { + try { + InnerClassTable_OpenHelper_TableConfig + .createTables(connectionSource); + } catch (SQLException e) { + throw new RuntimeException(e); + } } } } diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java index 93b399dd..365148c5 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java @@ -4,6 +4,7 @@ import java.sql.SQLException; import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import com.j256.ormlite.android.annotations.Database; @@ -13,6 +14,7 @@ import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.FieldType; import com.j256.ormlite.field.SqlType; +import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.DatabaseResults; import com.j256.ormlite.table.DatabaseTable; @@ -150,6 +152,19 @@ static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { OpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { super(context, databaseName, factory, databaseVersion); + NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig + .cacheTableConfigurations(); + } + + @Override + public void onCreate(SQLiteDatabase database, + ConnectionSource connectionSource) { + try { + NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig + .createTables(connectionSource); + } catch (SQLException e) { + throw new RuntimeException(e); + } } } } diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java index 4597876e..55fda84d 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java @@ -1,13 +1,16 @@ package inputs; +import java.sql.SQLException; import java.util.List; import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import com.j256.ormlite.android.annotations.Database; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.ForeignCollectionField; +import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTable; @DatabaseTable(tableName = "table") @@ -17,12 +20,25 @@ class NamedTableWithSpecifiedForeignCollectionField { @ForeignCollectionField(maxEagerForeignCollectionLevel = 5, foreignColumnName = "foreign_field") List numbers_deprecated; - + @Database({ NamedTableWithSpecifiedForeignCollectionField.class }) static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { OpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { super(context, databaseName, factory, databaseVersion); + NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig + .cacheTableConfigurations(); + } + + @Override + public void onCreate(SQLiteDatabase database, + ConnectionSource connectionSource) { + try { + NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig + .createTables(connectionSource); + } catch (SQLException e) { + throw new RuntimeException(e); + } } } } diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java index 1d4fee13..ba0e1fb5 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java @@ -1,23 +1,40 @@ package inputs; +import java.sql.SQLException; + import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import com.j256.ormlite.android.annotations.Database; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTable; @DatabaseTable class UnnamedTableWithDefaultDatabaseField { @DatabaseField int field; - + @Database({ UnnamedTableWithDefaultDatabaseField.class }) static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { OpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { super(context, databaseName, factory, databaseVersion); + UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig + .cacheTableConfigurations(); + } + + @Override + public void onCreate(SQLiteDatabase database, + ConnectionSource connectionSource) { + try { + UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig + .createTables(connectionSource); + } catch (SQLException e) { + throw new RuntimeException(e); + } } } } diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java index 79944c4b..d2475f0b 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java @@ -1,13 +1,16 @@ package inputs; +import java.sql.SQLException; import java.util.List; import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import com.j256.ormlite.android.annotations.Database; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.ForeignCollectionField; +import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTable; @DatabaseTable @@ -20,6 +23,19 @@ static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { OpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) { super(context, databaseName, factory, databaseVersion); + UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig + .cacheTableConfigurations(); + } + + @Override + public void onCreate(SQLiteDatabase database, + ConnectionSource connectionSource) { + try { + UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig + .createTables(connectionSource); + } catch (SQLException e) { + throw new RuntimeException(e); + } } } } diff --git a/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java b/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java new file mode 100644 index 00000000..8ffa4c51 --- /dev/null +++ b/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java @@ -0,0 +1,27 @@ +package inputs; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.DatabaseTableConfig; +import com.j256.ormlite.table.TableUtils; + +public final class InnerClassTable_OpenHelper_TableConfig { + private InnerClassTable_OpenHelper_TableConfig() { + } + + public static void cacheTableConfigurations() { + List> tableConfigs = new ArrayList>(); + tableConfigs.add(inputs.InnerClassTable_InnerClass_TableConfig.CONFIG); + tableConfigs.add(inputs.InnerClassTable_OtherInnerClass_TableConfig.CONFIG); + DaoManager.addCachedDatabaseConfigs(tableConfigs); + } + + public static void createTables(ConnectionSource connectionSource) throws SQLException { + TableUtils.createTable(connectionSource, inputs.InnerClassTable.InnerClass.class); + TableUtils.createTable(connectionSource, inputs.InnerClassTable.OtherInnerClass.class); + } +} diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java new file mode 100644 index 00000000..2240412b --- /dev/null +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java @@ -0,0 +1,25 @@ +package inputs; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.DatabaseTableConfig; +import com.j256.ormlite.table.TableUtils; + +public final class NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig { + private NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig() { + } + + public static void cacheTableConfigurations() { + List> tableConfigs = new ArrayList>(); + tableConfigs.add(inputs.NamedTableWithSpecifiedDatabaseField_TableConfig.CONFIG); + DaoManager.addCachedDatabaseConfigs(tableConfigs); + } + + public static void createTables(ConnectionSource connectionSource) throws SQLException { + TableUtils.createTable(connectionSource, inputs.NamedTableWithSpecifiedDatabaseField.class); + } +} diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java new file mode 100644 index 00000000..458672d0 --- /dev/null +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java @@ -0,0 +1,25 @@ +package inputs; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.DatabaseTableConfig; +import com.j256.ormlite.table.TableUtils; + +public final class NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig { + private NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig() { + } + + public static void cacheTableConfigurations() { + List> tableConfigs = new ArrayList>(); + tableConfigs.add(inputs.NamedTableWithSpecifiedForeignCollectionField_TableConfig.CONFIG); + DaoManager.addCachedDatabaseConfigs(tableConfigs); + } + + public static void createTables(ConnectionSource connectionSource) throws SQLException { + TableUtils.createTable(connectionSource, inputs.NamedTableWithSpecifiedForeignCollectionField.class); + } +} diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java new file mode 100644 index 00000000..27024937 --- /dev/null +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java @@ -0,0 +1,25 @@ +package inputs; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.DatabaseTableConfig; +import com.j256.ormlite.table.TableUtils; + +public final class UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig { + private UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig() { + } + + public static void cacheTableConfigurations() { + List> tableConfigs = new ArrayList>(); + tableConfigs.add(inputs.UnnamedTableWithDefaultDatabaseField_TableConfig.CONFIG); + DaoManager.addCachedDatabaseConfigs(tableConfigs); + } + + public static void createTables(ConnectionSource connectionSource) throws SQLException { + TableUtils.createTable(connectionSource, inputs.UnnamedTableWithDefaultDatabaseField.class); + } +} diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java new file mode 100644 index 00000000..2512625e --- /dev/null +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java @@ -0,0 +1,25 @@ +package inputs; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.DatabaseTableConfig; +import com.j256.ormlite.table.TableUtils; + +public final class UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig { + private UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig() { + } + + public static void cacheTableConfigurations() { + List> tableConfigs = new ArrayList>(); + tableConfigs.add(inputs.UnnamedTableWithDefaultForeignCollectionField_TableConfig.CONFIG); + DaoManager.addCachedDatabaseConfigs(tableConfigs); + } + + public static void createTables(ConnectionSource connectionSource) throws SQLException { + TableUtils.createTable(connectionSource, inputs.UnnamedTableWithDefaultForeignCollectionField.class); + } +} From 1ca70035e26571015aed4a978d09af5a3569c8b8 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Thu, 7 May 2015 20:58:14 -0700 Subject: [PATCH 12/26] Fix spurious errors during incremental builds --- .../OrmLiteAnnotationProcessor.java | 72 +++++++++++-------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java index 53a64ed9..0493645d 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java @@ -15,6 +15,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import javax.annotation.processing.AbstractProcessor; @@ -32,7 +33,6 @@ //TODO: handle javax.persistance annotations //TODO: analyze if this should be part of core (and if config file stuff can be removed) -//TODO: handle incremental compilation across files /** * Class that is automatically run when compiling client code that automatically @@ -51,8 +51,7 @@ public final class OrmLiteAnnotationProcessor extends AbstractProcessor { private static final String FQCN_OpenHelper = "com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper"; private static final String CN_OpenHelper = "OrmLiteSqliteOpenHelper"; - private Set declaredTables = new HashSet(); - private Map> declaredTableToDatabaseMap = new HashMap>(); + private Map> foundDatabases = new HashMap>(); private Set foundTables = new HashSet(); private static final class ParsedClassName { @@ -149,6 +148,10 @@ public boolean process(Set elements, continue; } + raiseNote(String.format("Processing %s class: %s", + DatabaseTable.class.getSimpleName(), + ((TypeElement) element).getQualifiedName())); + TableModel table = new TableModel(); table.parsedClassName = new ParsedClassName(element); table.annotation = element.getAnnotation(DatabaseTable.class); @@ -210,6 +213,10 @@ public boolean process(Set elements, continue; } + raiseNote(String.format("Processing %s class: %s", + Database.class.getSimpleName(), + ((TypeElement) element).getQualifiedName())); + boolean derivedFromOpenHelper = false; TypeElement annotatedClassElement = (TypeElement) element; do { @@ -270,47 +277,50 @@ public boolean process(Set elements, DatabaseTable.class.getSimpleName()), element); } - for (TypeElement tableType : tableTypes) { - List databases = declaredTableToDatabaseMap - .get(tableType); - if (databases == null) { - databases = new ArrayList(); - declaredTableToDatabaseMap.put(tableType, databases); - } - databases.add((TypeElement) element); - - declaredTables.add(tableType); - } + foundDatabases.put((TypeElement) element, tableTypes); createDatabaseConfigSourceFile((TypeElement) element, tableTypes); } if (env.processingOver()) { - Set undeclaredFoundTables = new HashSet( - foundTables); - - for (TypeElement declared : declaredTables) { - if (foundTables.contains(declared)) { - undeclaredFoundTables.remove(declared); - } else { - for (TypeElement database : declaredTableToDatabaseMap - .get(declared)) { + raiseNote(String.format( + "Processed %d %s class(es) and %d %s class(es)", + foundTables.size(), DatabaseTable.class.getSimpleName(), + foundDatabases.size(), Database.class.getSimpleName())); + + // compare as strings since TypeElements from different passes may + // not compare as expected + Set tablesIncludedInDatabases = new HashSet(); + + for (Entry> databaseAndTables : foundDatabases + .entrySet()) { + for (TypeElement table : databaseAndTables.getValue()) { + if (table.getAnnotation(DatabaseTable.class) == null) { raiseError( String.format( - "%s annotation must contain only classes annotated with %s", + "%s annotation contains class %s not annotated with %s", Database.class.getSimpleName(), + table.getSimpleName(), DatabaseTable.class.getSimpleName()), - database); + databaseAndTables.getKey()); + } else { + tablesIncludedInDatabases.add(table.getQualifiedName() + .toString()); } } } - for (TypeElement undeclared : undeclaredFoundTables) { - raiseWarning( - String.format( - "Class annotated with %s is not included in any %s annotation", - DatabaseTable.class.getSimpleName(), - Database.class.getSimpleName()), undeclared); + // TODO: fix false positives during incremental compilation of the + // table class only + for (TypeElement foundTable : foundTables) { + if (!tablesIncludedInDatabases.contains(foundTable + .getQualifiedName().toString())) { + raiseWarning( + String.format( + "Class annotated with %s is not included in any %s annotation", + DatabaseTable.class.getSimpleName(), + Database.class.getSimpleName()), foundTable); + } } } From e2d288779853f6ffbd55ddd9d8a31691254cfd62 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Fri, 8 May 2015 20:07:49 -0700 Subject: [PATCH 13/26] Add unit tests for errors --- .../OrmLiteAnnotationProcessorTest.java | 66 +++++++++++++++++++ .../inputs/DatabaseDerivedFromWrongClass.java | 15 +++++ .../inputs/DatabaseWithNoTables.java | 15 +++++ .../inputs/DatabaseWithNonTable.java | 23 +++++++ .../TableWithFieldWithBothAnnotations.java | 27 ++++++++ 5 files changed, 146 insertions(+) create mode 100644 src/test/resources/inputs/DatabaseDerivedFromWrongClass.java create mode 100644 src/test/resources/inputs/DatabaseWithNoTables.java create mode 100644 src/test/resources/inputs/DatabaseWithNonTable.java create mode 100644 src/test/resources/inputs/TableWithFieldWithBothAnnotations.java diff --git a/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java b/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java index 8e985948..7f74ab00 100644 --- a/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java +++ b/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java @@ -7,6 +7,11 @@ import com.google.testing.compile.JavaFileObjects; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.field.ForeignCollectionField; +import com.j256.ormlite.table.DatabaseTable; + public class OrmLiteAnnotationProcessorTest { @Test @@ -90,4 +95,65 @@ public void testInnerClasses() { JavaFileObjects .forResource("outputs/InnerClassTable_OpenHelper_TableConfig.java")); } + + @Test + public void testErrorBothAnnotationsOnField() { + assert_() + .about(javaSource()) + .that(JavaFileObjects + .forResource("inputs/TableWithFieldWithBothAnnotations.java")) + .processedWith(new OrmLiteAnnotationProcessor()) + .failsToCompile() + .withErrorContaining( + String.format( + "Fields cannot be annotated with both %s and %s", + DatabaseField.class.getSimpleName(), + ForeignCollectionField.class.getSimpleName())); + } + + @Test + public void testErrorDatabaseWithNoTables() { + assert_() + .about(javaSource()) + .that(JavaFileObjects + .forResource("inputs/DatabaseWithNoTables.java")) + .processedWith(new OrmLiteAnnotationProcessor()) + .failsToCompile() + .withErrorContaining( + String.format( + "%s annotation must contain at least one class annotated with %s", + Database.class.getSimpleName(), + DatabaseTable.class.getSimpleName())); + } + + @Test + public void testErrorDatabaseDerivedFromWrongClass() { + assert_() + .about(javaSource()) + .that(JavaFileObjects + .forResource("inputs/DatabaseDerivedFromWrongClass.java")) + .processedWith(new OrmLiteAnnotationProcessor()) + .failsToCompile() + .withErrorContaining( + String.format( + "%s annotation must be applied to a class deriving from %s", + Database.class.getSimpleName(), + OrmLiteSqliteOpenHelper.class.getSimpleName())); + } + + @Test + public void testErrorDatabaseWithNonTable() { + assert_() + .about(javaSource()) + .that(JavaFileObjects + .forResource("inputs/DatabaseWithNonTable.java")) + .processedWith(new OrmLiteAnnotationProcessor()) + .failsToCompile() + .withErrorContaining( + String.format( + "%s annotation contains class %s not annotated with %s", + Database.class.getSimpleName(), + String.class.getSimpleName(), + DatabaseTable.class.getSimpleName())); + } } diff --git a/src/test/resources/inputs/DatabaseDerivedFromWrongClass.java b/src/test/resources/inputs/DatabaseDerivedFromWrongClass.java new file mode 100644 index 00000000..20d2f7d2 --- /dev/null +++ b/src/test/resources/inputs/DatabaseDerivedFromWrongClass.java @@ -0,0 +1,15 @@ +package inputs; + +import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable +class DatabaseDerivedFromWrongClass { + @DatabaseField + int field; + + @Database({ DatabaseDerivedFromWrongClass.class }) + static abstract class OpenHelper { + } +} diff --git a/src/test/resources/inputs/DatabaseWithNoTables.java b/src/test/resources/inputs/DatabaseWithNoTables.java new file mode 100644 index 00000000..0a0fe98e --- /dev/null +++ b/src/test/resources/inputs/DatabaseWithNoTables.java @@ -0,0 +1,15 @@ +package inputs; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase.CursorFactory; + +import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; + +@Database({}) +abstract class DatabaseWithNoTables extends OrmLiteSqliteOpenHelper { + DatabaseWithNoTables(Context context, String databaseName, + CursorFactory factory, int databaseVersion) { + super(context, databaseName, factory, databaseVersion); + } +} diff --git a/src/test/resources/inputs/DatabaseWithNonTable.java b/src/test/resources/inputs/DatabaseWithNonTable.java new file mode 100644 index 00000000..b8c2c040 --- /dev/null +++ b/src/test/resources/inputs/DatabaseWithNonTable.java @@ -0,0 +1,23 @@ +package inputs; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase.CursorFactory; + +import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable +class DatabaseWithNonTable { + @DatabaseField + int field; + + @Database({ DatabaseWithNonTable.class, String.class }) + static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { + OpenHelper(Context context, String databaseName, CursorFactory factory, + int databaseVersion) { + super(context, databaseName, factory, databaseVersion); + } + } +} diff --git a/src/test/resources/inputs/TableWithFieldWithBothAnnotations.java b/src/test/resources/inputs/TableWithFieldWithBothAnnotations.java new file mode 100644 index 00000000..49a88e36 --- /dev/null +++ b/src/test/resources/inputs/TableWithFieldWithBothAnnotations.java @@ -0,0 +1,27 @@ +package inputs; + +import java.util.List; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase.CursorFactory; + +import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.field.ForeignCollectionField; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable +class TableWithFieldWithBothAnnotations { + @DatabaseField + @ForeignCollectionField + List field; + + @Database({ TableWithFieldWithBothAnnotations.class }) + static abstract class OpenHelper extends OrmLiteSqliteOpenHelper { + OpenHelper(Context context, String databaseName, CursorFactory factory, + int databaseVersion) { + super(context, databaseName, factory, databaseVersion); + } + } +} From a52ac523800797c6363de3ade7c18eeb1405c029 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Fri, 8 May 2015 20:08:31 -0700 Subject: [PATCH 14/26] Fix incremental compilation issues --- .../OrmLiteAnnotationProcessor.java | 155 +++++++++++++++--- 1 file changed, 133 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java index 0493645d..447a6a07 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java @@ -5,6 +5,8 @@ import com.j256.ormlite.table.DatabaseTable; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Writer; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -29,10 +31,9 @@ import javax.lang.model.type.MirroredTypesException; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic.Kind; +import javax.tools.FileObject; import javax.tools.JavaFileObject; - -//TODO: handle javax.persistance annotations -//TODO: analyze if this should be part of core (and if config file stuff can be removed) +import javax.tools.StandardLocation; /** * Class that is automatically run when compiling client code that automatically @@ -41,13 +42,16 @@ * * @author nathancrouther */ -// TODO: understand this +/* + * Eclipse doesn't like the link to rt.jar and classes therein. This is a + * spurious warning that can be ignored. It is intended to prevent referencing + * com.sun packages that may not be in every JVM, but the annotation processing + * stuff is part of JSR-269, so will always be present. + */ @SuppressWarnings("restriction") public final class OrmLiteAnnotationProcessor extends AbstractProcessor { private static final String FQCN_Object = "java.lang.Object"; private static final String FQCN_Class = "java.lang.Class"; - - // TODO: understand why reading these from Class throws exception private static final String FQCN_OpenHelper = "com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper"; private static final String CN_OpenHelper = "OrmLiteSqliteOpenHelper"; @@ -284,16 +288,60 @@ public boolean process(Set elements, if (env.processingOver()) { raiseNote(String.format( - "Processed %d %s class(es) and %d %s class(es)", + "Finished processing %d %s class(es) and %d %s class(es)", foundTables.size(), DatabaseTable.class.getSimpleName(), foundDatabases.size(), Database.class.getSimpleName())); - // compare as strings since TypeElements from different passes may - // not compare as expected - Set tablesIncludedInDatabases = new HashSet(); + final StandardLocation savedDatabaseInfoLocation = StandardLocation.SOURCE_OUTPUT; + final String savedDatabaseInfoPackageName = getClass().getPackage() + .getName(); + final String savedDatabaseInfoFileName = "savedDatabaseInfo"; + + // Try to read a file from before + Map> savedDatabaseInfo; + try { + FileObject file = processingEnv.getFiler() + .getResource(savedDatabaseInfoLocation, + savedDatabaseInfoPackageName, + savedDatabaseInfoFileName); + ObjectInputStream reader = new ObjectInputStream( + file.openInputStream()); + try { + // We created the file previously, so the cast is safe + @SuppressWarnings("unchecked") + Map> oldDatabaseInfo = (Map>) reader + .readObject(); + raiseNote(String.format( + "Loaded %d Database-to-DatabaseTable mappings", + oldDatabaseInfo.size())); + savedDatabaseInfo = oldDatabaseInfo; + } catch (IOException e) { + // Inability to read is not an error, just initialize with + // empty contents + savedDatabaseInfo = new HashMap>(); + } finally { + reader.close(); + } + } catch (FilerException e) { + // Inability to read is not an error, just initialize with empty + // contents + savedDatabaseInfo = new HashMap>(); + } catch (IOException e) { + // Inability to read is not an error, just initialize with empty + // contents + savedDatabaseInfo = new HashMap>(); + } catch (ClassNotFoundException e) { + // Built-in Java classes will always be available + throw new RuntimeException(e); + } + // Verify each Database annotation only contains valid tables and + // add it to the saved list for future rounds of incremental + // compilation for (Entry> databaseAndTables : foundDatabases .entrySet()) { + List tableNames = new ArrayList(); + for (TypeElement table : databaseAndTables.getValue()) { if (table.getAnnotation(DatabaseTable.class) == null) { raiseError( @@ -303,15 +351,43 @@ public boolean process(Set elements, table.getSimpleName(), DatabaseTable.class.getSimpleName()), databaseAndTables.getKey()); - } else { - tablesIncludedInDatabases.add(table.getQualifiedName() - .toString()); } + + tableNames.add(table.getQualifiedName().toString()); } + + savedDatabaseInfo.put(databaseAndTables.getKey() + .getQualifiedName().toString(), tableNames); } - // TODO: fix false positives during incremental compilation of the - // table class only + // Save the updated information for future rounds of incremental + // compilation + try { + FileObject file = processingEnv.getFiler() + .createResource(savedDatabaseInfoLocation, + savedDatabaseInfoPackageName, + savedDatabaseInfoFileName); + ObjectOutputStream writer = new ObjectOutputStream( + file.openOutputStream()); + writer.writeObject(savedDatabaseInfo); + writer.close(); + raiseNote(String.format( + "Stored %d Database-to-DatabaseTable mappings", + savedDatabaseInfo.size())); + } catch (FilerException e) { + // intentionally ignore the error + } catch (IOException e) { + // intentionally ignore the error + } + + // Verify that every table is in a database (try to enforce using + // the database annotation for better performance) + Set tablesIncludedInDatabases = new HashSet(); + for (List tableNames : savedDatabaseInfo.values()) { + for (String tableName : tableNames) { + tablesIncludedInDatabases.add(tableName); + } + } for (TypeElement foundTable : foundTables) { if (!tablesIncludedInDatabases.contains(foundTable .getQualifiedName().toString())) { @@ -329,10 +405,10 @@ public boolean process(Set elements, private void createDatabaseConfigSourceFile(TypeElement openHelperClass, List tableClasses) { - try { - ParsedClassName openHelperClassName = new ParsedClassName( - openHelperClass); + ParsedClassName openHelperClassName = new ParsedClassName( + openHelperClass); + try { JavaFileObject javaFileObject = processingEnv .getFiler() .createSourceFile( @@ -387,7 +463,17 @@ private void createDatabaseConfigSourceFile(TypeElement openHelperClass, } finally { writer.close(); } + } catch (FilerException e) { + // if multiple classes are in the same file (e.g. inner/nested + // classes), eclipse will do an incremental compilation for all of + // them. The unchanged ones' generated files will not be deleted, so + // we can ignore this benign error. + raiseNote(String + .format("Skipping file generation for %s since file already exists", + openHelperClassName + .getGeneratedFullyQualifiedClassName())); } catch (IOException e) { + // We should always be able to generate the source files throw new RuntimeException(e); } } @@ -418,6 +504,7 @@ private void createTableConfigSourceFile(TableModel table, table.parsedClassName .getGeneratedFullyQualifiedClassName())); } catch (IOException e) { + // We should always be able to generate the source files throw new RuntimeException(e); } } @@ -647,6 +734,8 @@ private static boolean writeSetterIfNotDefault(Annotation annotation, return writeSetterIfNotEqual(actualValue, defaultValue, setterCall, writer); } catch (Exception e) { + // All possible annotation properties are unit tested, so it is not + // possible to get an exception here throw new RuntimeException(e); } } @@ -689,13 +778,35 @@ private void raiseNote(String message) { this.processingEnv.getMessager().printMessage(Kind.NOTE, message); } + /* + * During incremental compiles in eclipse, if the same element raises + * multiple warnings, the internal message printing code can throw a NPE. + * When this happens, all warnings are displayed properly, so we should + * ignore the error. We will validate our arguments ourself to ensure that + * this code doesn't mask a real bug. + */ + private void raiseWarning(String message, Element element) { - this.processingEnv.getMessager().printMessage(Kind.WARNING, message, - element); + if (message == null || element == null) { + throw new NullPointerException(); + } + try { + this.processingEnv.getMessager().printMessage(Kind.WARNING, + message, element); + } catch (NullPointerException e) { + // ignore to workaround issues with eclipse incremental compilation + } } private void raiseError(String message, Element element) { - this.processingEnv.getMessager().printMessage(Kind.ERROR, message, - element); + if (message == null || element == null) { + throw new NullPointerException(); + } + try { + this.processingEnv.getMessager().printMessage(Kind.ERROR, message, + element); + } catch (NullPointerException e) { + // ignore to workaround issues with eclipse incremental compilation + } } } From fb9e4d81244ee09fc70e3e949e2e72591fc1d576 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Fri, 8 May 2015 20:08:42 -0700 Subject: [PATCH 15/26] Add documentation --- .../ormlite/android/annotations/Database.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/java/com/j256/ormlite/android/annotations/Database.java b/src/main/java/com/j256/ormlite/android/annotations/Database.java index 0822dc56..ea606043 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/Database.java +++ b/src/main/java/com/j256/ormlite/android/annotations/Database.java @@ -5,6 +5,26 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * This class is applied to a class derived from + * {@link com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper} and lists + * the classes representing the tables in the database. Compile-time annotation + * processing will generate a method that can be called from your constructor to + * cache table information to avoid slow reflection on Android. This + * functionality replaces table configuration files which achieved the same goal + * by manually creating a text file at build time and parsing it at runtime. + * + * Add a call to YOUR_CLASS_NAME_TableConfig.cacheTableConfigurations() to your + * constructor to make use of this functionality. You can also call + * YOUR_CLASS_NAME_TableConfig.createTables(connectionSource) from your onCreate + * to create all tables included in this annotation. + * + * For inner/nested classes, the generated class name will use underscores to + * separate the classes (e.g. package.Outer.Inner will result in + * package.Outer_Inner_TableConfig begin generated). + * + * @author nathancrouther + */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface Database { From 5e6adacbc8876eaf4cae466c998dd062111cc598 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Fri, 8 May 2015 20:09:18 -0700 Subject: [PATCH 16/26] Deprecate configuration file code --- .../android/apptools/OrmLiteConfigUtil.java | 5 +++++ .../apptools/OrmLiteSqliteOpenHelper.java | 21 +++++++++++++++++++ .../apptools/OrmLiteConfigUtilTest.java | 1 + 3 files changed, 27 insertions(+) diff --git a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtil.java b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtil.java index 52c45966..d2513305 100644 --- a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtil.java +++ b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtil.java @@ -52,7 +52,12 @@ *

* * @author graywatson + * + * @deprecated As of version 4.49 configuration files have been replaced by + * automatic annotation processing at compile time. + * @see com.j256.ormlite.android.annotations.Database */ +@Deprecated public class OrmLiteConfigUtil { /** diff --git a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteSqliteOpenHelper.java b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteSqliteOpenHelper.java index 62a3f457..323c30cc 100644 --- a/src/main/java/com/j256/ormlite/android/apptools/OrmLiteSqliteOpenHelper.java +++ b/src/main/java/com/j256/ormlite/android/apptools/OrmLiteSqliteOpenHelper.java @@ -70,7 +70,14 @@ public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFacto * called if the stored database is a different version. * @param configFileId * file-id which probably should be a R.raw.ormlite_config.txt or some static value. + * + * @deprecated As of version 4.49 configuration files have been replaced by + * automatic annotation processing at compile time. Add an + * {@link com.j256.ormlite.android.annotations.Database} + * annotation to the class that inherits from this class to + * activate annotation processing. */ + @Deprecated public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion, int configFileId) { this(context, databaseName, factory, databaseVersion, openFileId(context, configFileId)); @@ -90,7 +97,14 @@ public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFacto * called if the stored database is a different version. * @param configFile * Configuration file to be loaded. + * + * @deprecated As of version 4.49 configuration files have been replaced by + * automatic annotation processing at compile time. Add an + * {@link com.j256.ormlite.android.annotations.Database} + * annotation to the class that inherits from this class to + * activate annotation processing. */ + @Deprecated public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion, File configFile) { this(context, databaseName, factory, databaseVersion, openFile(configFile)); @@ -111,7 +125,14 @@ public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFacto * called if the stored database is a different version. * @param stream * Stream opened to the configuration file to be loaded. It will be closed when this method returns. + * + * @deprecated As of version 4.49 configuration files have been replaced by + * automatic annotation processing at compile time. Add an + * {@link com.j256.ormlite.android.annotations.Database} + * annotation to the class that inherits from this class to + * activate annotation processing. */ + @Deprecated public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion, InputStream stream) { super(context, databaseName, factory, databaseVersion); diff --git a/src/test/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtilTest.java b/src/test/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtilTest.java index 0859bc6e..52ec0bfc 100644 --- a/src/test/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtilTest.java +++ b/src/test/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtilTest.java @@ -11,6 +11,7 @@ import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.ForeignCollectionField; +@SuppressWarnings("deprecation") public class OrmLiteConfigUtilTest { private static final String lineSeparator = System.getProperty("line.separator"); From bfd65be5a704b673ad143d4a26a9eeb0870c89ba Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 11 May 2015 18:10:37 -0700 Subject: [PATCH 17/26] Move processor from annotations to processor package --- .../{annotations => processor}/OrmLiteAnnotationProcessor.java | 3 ++- .../META-INF/services/javax.annotation.processing.Processor | 2 +- .../OrmLiteAnnotationProcessorTest.java | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) rename src/main/java/com/j256/ormlite/android/{annotations => processor}/OrmLiteAnnotationProcessor.java (99%) rename src/test/java/com/j256/ormlite/android/{annotations => processor}/OrmLiteAnnotationProcessorTest.java (98%) diff --git a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java similarity index 99% rename from src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java rename to src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java index 447a6a07..3d0977d1 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java @@ -1,5 +1,6 @@ -package com.j256.ormlite.android.annotations; +package com.j256.ormlite.android.processor; +import com.j256.ormlite.android.annotations.Database; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.ForeignCollectionField; import com.j256.ormlite.table.DatabaseTable; diff --git a/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/src/main/resources/META-INF/services/javax.annotation.processing.Processor index 83eb6add..a63788c0 100644 --- a/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ b/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -1 +1 @@ -com.j256.ormlite.android.annotations.OrmLiteAnnotationProcessor +com.j256.ormlite.android.processor.OrmLiteAnnotationProcessor diff --git a/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java b/src/test/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessorTest.java similarity index 98% rename from src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java rename to src/test/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessorTest.java index 7f74ab00..73e1d2d6 100644 --- a/src/test/java/com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessorTest.java +++ b/src/test/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessorTest.java @@ -1,4 +1,4 @@ -package com.j256.ormlite.android.annotations; +package com.j256.ormlite.android.processor; import static com.google.common.truth.Truth.assert_; import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; @@ -7,6 +7,7 @@ import com.google.testing.compile.JavaFileObjects; +import com.j256.ormlite.android.annotations.Database; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.ForeignCollectionField; From 569b04154258e70647edc35a033e1c4c188a4567 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 11 May 2015 18:33:08 -0700 Subject: [PATCH 18/26] Refactor Model inner classes into top level Bindings classes --- .../android/processor/FieldBindings.java | 36 +++ .../processor/OrmLiteAnnotationProcessor.java | 239 +++++++----------- .../android/processor/ParsedClassName.java | 78 ++++++ .../android/processor/TableBindings.java | 33 +++ 4 files changed, 233 insertions(+), 153 deletions(-) create mode 100644 src/main/java/com/j256/ormlite/android/processor/FieldBindings.java create mode 100644 src/main/java/com/j256/ormlite/android/processor/ParsedClassName.java create mode 100644 src/main/java/com/j256/ormlite/android/processor/TableBindings.java diff --git a/src/main/java/com/j256/ormlite/android/processor/FieldBindings.java b/src/main/java/com/j256/ormlite/android/processor/FieldBindings.java new file mode 100644 index 00000000..70c99da2 --- /dev/null +++ b/src/main/java/com/j256/ormlite/android/processor/FieldBindings.java @@ -0,0 +1,36 @@ +package com.j256.ormlite.android.processor; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.field.ForeignCollectionField; + +class FieldBindings { + private final String fullyQualifiedTypeName; + private final String fieldName; + private final DatabaseField databaseFieldAnnotation; + private final ForeignCollectionField foreignCollectionFieldAnnotation; + + FieldBindings(String fullyQualifiedTypeName, String fieldName, + DatabaseField databaseFieldAnnotation, + ForeignCollectionField foreignCollectionFieldAnnotation) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + this.fieldName = fieldName; + this.databaseFieldAnnotation = databaseFieldAnnotation; + this.foreignCollectionFieldAnnotation = foreignCollectionFieldAnnotation; + } + + String getFullyQualifiedTypeName() { + return fullyQualifiedTypeName; + } + + String getFieldName() { + return fieldName; + } + + DatabaseField getDatabaseFieldAnnotation() { + return databaseFieldAnnotation; + } + + ForeignCollectionField getForeignCollectionFieldAnnotation() { + return foreignCollectionFieldAnnotation; + } +} diff --git a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java index 3d0977d1..c863dbc8 100644 --- a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java @@ -12,7 +12,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; @@ -25,7 +24,6 @@ import javax.annotation.processing.FilerException; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; -import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.SourceVersion; import javax.lang.model.type.MirroredTypeException; @@ -59,78 +57,6 @@ public final class OrmLiteAnnotationProcessor extends AbstractProcessor { private Map> foundDatabases = new HashMap>(); private Set foundTables = new HashSet(); - private static final class ParsedClassName { - private String packageName; - private List nestedClasses = new ArrayList(); - - ParsedClassName(Element element) { - Element elementIterator = element; - do { - nestedClasses.add(elementIterator.getSimpleName().toString()); - elementIterator = elementIterator.getEnclosingElement(); - } while (elementIterator.getKind().isClass()); - Collections.reverse(nestedClasses); - packageName = ((PackageElement) elementIterator).getQualifiedName() - .toString(); - } - - String getInputFullyQualifiedClassName() { - StringBuilder sb = new StringBuilder(); - if (!packageName.isEmpty()) { - sb.append(packageName); - sb.append('.'); - } - for (int i = 0; i < nestedClasses.size(); ++i) { - if (i != 0) { - sb.append('.'); - } - sb.append(nestedClasses.get(i)); - } - return sb.toString(); - } - - String getInputSimpleClassName() { - return nestedClasses.get(nestedClasses.size() - 1); - } - - String getGeneratedClassName() { - final String SUFFIX = "_TableConfig"; - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < nestedClasses.size(); ++i) { - if (i != 0) { - sb.append('_'); - } - sb.append(nestedClasses.get(i)); - } - sb.append(SUFFIX); - return sb.toString(); - } - - String getGeneratedFullyQualifiedClassName() { - StringBuilder sb = new StringBuilder(); - if (!packageName.isEmpty()) { - sb.append(packageName); - sb.append('.'); - } - sb.append(getGeneratedClassName()); - return sb.toString(); - } - } - - private static final class TableModel { - ParsedClassName parsedClassName; - DatabaseTable annotation; - List fields = new ArrayList(); - } - - private static final class FieldModel { - String fullyQualifiedTypeName; - String fieldName; - DatabaseField databaseFieldAnnotation; - ForeignCollectionField foreignCollectionFieldAnnotation; - } - @Override public Set getSupportedAnnotationTypes() { Set types = new LinkedHashSet(); @@ -157,9 +83,9 @@ public boolean process(Set elements, DatabaseTable.class.getSimpleName(), ((TypeElement) element).getQualifiedName())); - TableModel table = new TableModel(); - table.parsedClassName = new ParsedClassName(element); - table.annotation = element.getAnnotation(DatabaseTable.class); + TableBindings table = new TableBindings( + new ParsedClassName(element), + element.getAnnotation(DatabaseTable.class)); // get all fields from this and all parents until we hit Object TypeElement tableClassElement = (TypeElement) element; @@ -173,13 +99,11 @@ public boolean process(Set elements, .getAnnotation(ForeignCollectionField.class); if (databaseField != null || foreignCollectionField != null) { - FieldModel field = new FieldModel(); - field.fullyQualifiedTypeName = child.asType() - .toString(); - field.fieldName = child.getSimpleName().toString(); - field.databaseFieldAnnotation = databaseField; - field.foreignCollectionFieldAnnotation = foreignCollectionField; - table.fields.add(field); + FieldBindings field = new FieldBindings(child + .asType().toString(), child.getSimpleName() + .toString(), databaseField, + foreignCollectionField); + table.addField(field); } if (databaseField != null @@ -199,7 +123,7 @@ public boolean process(Set elements, } while (!tableClassElement.getQualifiedName().toString() .equals(FQCN_Object)); - if (table.fields.isEmpty()) { + if (table.getFields().isEmpty()) { raiseWarning( String.format( "No fields annotated with %s found for class annotated with %s", @@ -419,7 +343,7 @@ private void createDatabaseConfigSourceFile(TypeElement openHelperClass, Writer writer = javaFileObject.openWriter(); try { - writer.write("package " + openHelperClassName.packageName + writer.write("package " + openHelperClassName.getPackageName() + ";\n"); writer.write("\n"); writer.write("import java.sql.SQLException;\n"); @@ -479,13 +403,12 @@ private void createDatabaseConfigSourceFile(TypeElement openHelperClass, } } - private void createTableConfigSourceFile(TableModel table, + private void createTableConfigSourceFile(TableBindings table, Element tableClassElement) { try { - JavaFileObject javaFileObject = processingEnv - .getFiler() + JavaFileObject javaFileObject = processingEnv.getFiler() .createSourceFile( - table.parsedClassName + table.getParsedClassName() .getGeneratedFullyQualifiedClassName(), tableClassElement); @@ -502,7 +425,7 @@ private void createTableConfigSourceFile(TableModel table, // we can ignore this benign error. raiseNote(String .format("Skipping file generation for %s since file already exists", - table.parsedClassName + table.getParsedClassName() .getGeneratedFullyQualifiedClassName())); } catch (IOException e) { // We should always be able to generate the source files @@ -510,10 +433,11 @@ private void createTableConfigSourceFile(TableModel table, } } - private static void writeTable(Writer writer, TableModel table) + private static void writeTable(Writer writer, TableBindings table) throws IOException { - if (!table.parsedClassName.packageName.isEmpty()) { - writer.write("package " + table.parsedClassName.packageName + ";\n"); + if (!table.getParsedClassName().getPackageName().isEmpty()) { + writer.write("package " + + table.getParsedClassName().getPackageName() + ";\n"); writer.write("\n"); } writer.write("import java.util.ArrayList;\n"); @@ -523,161 +447,169 @@ private static void writeTable(Writer writer, TableModel table) writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); writer.write("\n"); writer.write("public final class " - + table.parsedClassName.getGeneratedClassName() + " {\n"); + + table.getParsedClassName().getGeneratedClassName() + " {\n"); writer.write("\tprivate " - + table.parsedClassName.getGeneratedClassName() + "() {\n"); + + table.getParsedClassName().getGeneratedClassName() + "() {\n"); writer.write("\t}\n"); writer.write("\n"); writer.write("\tpublic static final DatabaseTableConfig<" - + table.parsedClassName.getInputFullyQualifiedClassName() + + table.getParsedClassName().getInputFullyQualifiedClassName() + "> CONFIG;\n"); writer.write("\n"); writer.write("\tstatic {\n"); writer.write("\t\tList databaseFieldConfigs = new ArrayList();\n"); - for (FieldModel field : table.fields) { + for (FieldBindings field : table.getFields()) { - if (field.databaseFieldAnnotation != null - && !field.databaseFieldAnnotation.persisted()) { + if (field.getDatabaseFieldAnnotation() != null + && !field.getDatabaseFieldAnnotation().persisted()) { continue; } writer.write("\t\t{\n"); writer.write(String .format("\t\t\tDatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig(\"%s\");\n", - field.fieldName)); + field.getFieldName())); - if (field.databaseFieldAnnotation != null) { - writeSetterIfNotDefault(field.databaseFieldAnnotation, + if (field.getDatabaseFieldAnnotation() != null) { + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "columnName", "setColumnName(\"%s\")", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "dataType", "setDataType(com.j256.ormlite.field.DataType.%s)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "defaultValue", "setDefaultValue(\"%s\")", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, "width", - "setWidth(%d)", writer); + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), + "width", "setWidth(%d)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "canBeNull", "setCanBeNull(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, "id", - "setId(%b)", writer); + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), + "id", "setId(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "generatedId", "setGeneratedId(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "generatedIdSequence", "setGeneratedIdSequence(\"%s\")", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "foreign", "setForeign(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "useGetSet", "setUseGetSet(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, - "unknownEnumName", "setUnknownEnumValue(" - + field.fullyQualifiedTypeName + ".%s)", writer); + writeSetterIfNotDefault( + field.getDatabaseFieldAnnotation(), + "unknownEnumName", + "setUnknownEnumValue(" + + field.getFullyQualifiedTypeName() + ".%s)", + writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "throwIfNull", "setThrowIfNull(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "format", "setFormat(\"%s\")", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "unique", "setUnique(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "uniqueCombo", "setUniqueCombo(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, "index", - "setIndex(%b)", writer); + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), + "index", "setIndex(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "uniqueIndex", "setUniqueIndex(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "indexName", "setIndexName(\"%s\")", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "uniqueIndexName", "setUniqueIndexName(\"%s\")", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "foreignAutoRefresh", "setForeignAutoRefresh(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "maxForeignAutoRefreshLevel", "setMaxForeignAutoRefreshLevel(%d)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "persisterClass", "setPersisterClass(%s.class)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "allowGeneratedIdInsert", "setAllowGeneratedIdInsert(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "columnDefinition", "setColumnDefinition(\"%s\")", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "foreignAutoCreate", "setForeignAutoCreate(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "version", "setVersion(%b)", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "foreignColumnName", "setForeignColumnName(\"%s\")", writer); - writeSetterIfNotDefault(field.databaseFieldAnnotation, + writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), "readOnly", "setReadOnly(%b)", writer); } - if (field.foreignCollectionFieldAnnotation != null) { - writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, + if (field.getForeignCollectionFieldAnnotation() != null) { + writeSetterIfNotDefault( + field.getForeignCollectionFieldAnnotation(), "columnName", "setColumnName(\"%s\")", writer); writeSetter(true, "setForeignCollection(%b)", writer); - writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, - "eager", "setForeignCollectionEager(%b)", writer); + writeSetterIfNotDefault( + field.getForeignCollectionFieldAnnotation(), "eager", + "setForeignCollectionEager(%b)", writer); if (!writeSetterIfNotDefault( - field.foreignCollectionFieldAnnotation, + field.getForeignCollectionFieldAnnotation(), "maxEagerLevel", "setForeignCollectionMaxEagerLevel(%d)", writer)) { writeSetterIfNotDefault( - field.foreignCollectionFieldAnnotation, + field.getForeignCollectionFieldAnnotation(), "maxEagerForeignCollectionLevel", "setForeignCollectionMaxEagerLevel(%d)", writer); } - writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, + writeSetterIfNotDefault( + field.getForeignCollectionFieldAnnotation(), "columnName", "setForeignCollectionColumnName(\"%s\")", writer); - writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, + writeSetterIfNotDefault( + field.getForeignCollectionFieldAnnotation(), "orderColumnName", "setForeignCollectionOrderColumnName(\"%s\")", writer); - writeSetterIfNotDefault(field.foreignCollectionFieldAnnotation, + writeSetterIfNotDefault( + field.getForeignCollectionFieldAnnotation(), "orderAscending", "setForeignCollectionOrderAscending(%b)", writer); if (!writeSetterIfNotDefault( - field.foreignCollectionFieldAnnotation, + field.getForeignCollectionFieldAnnotation(), "foreignFieldName", "setForeignCollectionForeignFieldName(\"%s\")", writer)) { writeSetterIfNotDefault( - field.foreignCollectionFieldAnnotation, + field.getForeignCollectionFieldAnnotation(), "foreignColumnName", "setForeignCollectionForeignFieldName(\"%s\")", writer); @@ -689,19 +621,20 @@ private static void writeTable(Writer writer, TableModel table) } String tableName; - if (table.annotation.tableName() != null - && table.annotation.tableName().length() > 0) { - tableName = table.annotation.tableName(); + if (table.getAnnotation().tableName() != null + && table.getAnnotation().tableName().length() > 0) { + tableName = table.getAnnotation().tableName(); } else { - tableName = table.parsedClassName.getInputSimpleClassName() + tableName = table.getParsedClassName().getInputSimpleClassName() .toLowerCase(); } writer.write(String .format("\t\tCONFIG = new DatabaseTableConfig<%s>(%s.class, \"%s\", databaseFieldConfigs);\n", - table.parsedClassName.getInputFullyQualifiedClassName(), - table.parsedClassName.getInputFullyQualifiedClassName(), - tableName)); + table.getParsedClassName() + .getInputFullyQualifiedClassName(), table + .getParsedClassName() + .getInputFullyQualifiedClassName(), tableName)); writer.write("\t}\n"); writer.write("}\n"); } diff --git a/src/main/java/com/j256/ormlite/android/processor/ParsedClassName.java b/src/main/java/com/j256/ormlite/android/processor/ParsedClassName.java new file mode 100644 index 00000000..2e93e1aa --- /dev/null +++ b/src/main/java/com/j256/ormlite/android/processor/ParsedClassName.java @@ -0,0 +1,78 @@ +package com.j256.ormlite.android.processor; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; + +/* + * Eclipse doesn't like the link to rt.jar and classes therein. This is a + * spurious warning that can be ignored. It is intended to prevent referencing + * com.sun packages that may not be in every JVM, but the annotation processing + * stuff is part of JSR-269, so will always be present. + */ +@SuppressWarnings("restriction") +class ParsedClassName { + private String packageName; + private List nestedClasses = new ArrayList(); + + ParsedClassName(Element element) { + Element elementIterator = element; + do { + nestedClasses.add(elementIterator.getSimpleName().toString()); + elementIterator = elementIterator.getEnclosingElement(); + } while (elementIterator.getKind().isClass()); + Collections.reverse(nestedClasses); + packageName = ((PackageElement) elementIterator).getQualifiedName() + .toString(); + } + + String getPackageName() { + return packageName; + } + + String getInputFullyQualifiedClassName() { + StringBuilder sb = new StringBuilder(); + if (!packageName.isEmpty()) { + sb.append(packageName); + sb.append('.'); + } + for (int i = 0; i < nestedClasses.size(); ++i) { + if (i != 0) { + sb.append('.'); + } + sb.append(nestedClasses.get(i)); + } + return sb.toString(); + } + + String getInputSimpleClassName() { + return nestedClasses.get(nestedClasses.size() - 1); + } + + String getGeneratedClassName() { + final String SUFFIX = "_TableConfig"; + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < nestedClasses.size(); ++i) { + if (i != 0) { + sb.append('_'); + } + sb.append(nestedClasses.get(i)); + } + sb.append(SUFFIX); + return sb.toString(); + } + + String getGeneratedFullyQualifiedClassName() { + StringBuilder sb = new StringBuilder(); + if (!packageName.isEmpty()) { + sb.append(packageName); + sb.append('.'); + } + sb.append(getGeneratedClassName()); + return sb.toString(); + } +} diff --git a/src/main/java/com/j256/ormlite/android/processor/TableBindings.java b/src/main/java/com/j256/ormlite/android/processor/TableBindings.java new file mode 100644 index 00000000..1888d86f --- /dev/null +++ b/src/main/java/com/j256/ormlite/android/processor/TableBindings.java @@ -0,0 +1,33 @@ +package com.j256.ormlite.android.processor; + +import java.util.ArrayList; +import java.util.List; + +import com.j256.ormlite.table.DatabaseTable; + +class TableBindings { + private final ParsedClassName parsedClassName; + private final DatabaseTable annotation; + private final List fields = new ArrayList(); + + TableBindings(ParsedClassName parsedClassName, DatabaseTable annotation) { + this.parsedClassName = parsedClassName; + this.annotation = annotation; + } + + void addField(FieldBindings field) { + fields.add(field); + } + + ParsedClassName getParsedClassName() { + return parsedClassName; + } + + DatabaseTable getAnnotation() { + return annotation; + } + + List getFields() { + return fields; + } +} From 275a47a1624fe8c688cf1518555b9693766f5c44 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 11 May 2015 18:55:55 -0700 Subject: [PATCH 19/26] Add examples to Database annotation javadoc --- .../ormlite/android/annotations/Database.java | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/main/java/com/j256/ormlite/android/annotations/Database.java b/src/main/java/com/j256/ormlite/android/annotations/Database.java index ea606043..f9623658 100644 --- a/src/main/java/com/j256/ormlite/android/annotations/Database.java +++ b/src/main/java/com/j256/ormlite/android/annotations/Database.java @@ -23,6 +23,109 @@ * separate the classes (e.g. package.Outer.Inner will result in * package.Outer_Inner_TableConfig begin generated). * + *

+ * Example (Table.java) + *

+ * + *

+ *

+ * + *
+ * @DatabaseTable
+ * class Table {
+ * 	@DatabaseField
+ * 	int field;
+ * }
+ * 
+ * + *
+ *

+ * + *

+ * Example (Outer.java) + *

+ * + *

+ *

+ * + *
+ * class Outer {
+ * 	@DatabaseTable
+ * 	class Inner {
+ * 		@DatabaseField
+ * 		int field;
+ * 	}
+ * }
+ * 
+ * + *
+ *

+ * + *

+ * Example (OpenHelper.java) + *

+ * + *

+ *

+ * + *
+ * @Database({ Table.class, Outer.Inner.class })
+ * class OpenHelper extends OrmLiteSqliteOpenHelper {
+ * 	OpenHelper(Context context, String databaseName, CursorFactory factory,
+ * 			int databaseVersion) {
+ * 		super(context, databaseName, factory, databaseVersion);
+ * 		OpenHelper_TableConfig.cacheTableConfigurations();
+ * 	}
+ * 
+ * 	@Override
+ * 	public void onCreate(SQLiteDatabase database,
+ * 			ConnectionSource connectionSource) {
+ * 		try {
+ * 			OpenHelper_TableConfig.createTables(connectionSource);
+ * 		} catch (SQLException e) {
+ * 			throw new RuntimeException(e);
+ * 		}
+ * 	}
+ * }
+ * 
+ * + *
+ *

+ * + * * + *

+ * Example (InnerOpenHelper.java) + *

+ * + *

+ *

+ * + *
+ * class Outer {
+ * 	@Database({ Table.class, Outer.Inner.class })
+ * 	class OpenHelper extends OrmLiteSqliteOpenHelper {
+ * 		OpenHelper(Context context, String databaseName, CursorFactory factory,
+ * 				int databaseVersion) {
+ * 			super(context, databaseName, factory, databaseVersion);
+ * 			Outer_OpenHelper_TableConfig.cacheTableConfigurations();
+ * 		}
+ * 
+ * 		@Override
+ * 		public void onCreate(SQLiteDatabase database,
+ * 				ConnectionSource connectionSource) {
+ * 			try {
+ * 				Outer_OpenHelper_TableConfig.createTables(connectionSource);
+ * 			} catch (SQLException e) {
+ * 				throw new RuntimeException(e);
+ * 			}
+ * 		}
+ * 	}
+ * }
+ * 
+ * + *
+ *

+ * * @author nathancrouther */ @Retention(RetentionPolicy.SOURCE) From a327c0f8617e2a6bcf85eba087596e81c0fe10b4 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 11 May 2015 19:13:45 -0700 Subject: [PATCH 20/26] Improve exception handling Add better comments justifying why each exception is or is not fatal and make sure every unexpected exception is logged. --- .../processor/OrmLiteAnnotationProcessor.java | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java index c863dbc8..e38e7a89 100644 --- a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java @@ -240,23 +240,24 @@ public boolean process(Set elements, "Loaded %d Database-to-DatabaseTable mappings", oldDatabaseInfo.size())); savedDatabaseInfo = oldDatabaseInfo; - } catch (IOException e) { - // Inability to read is not an error, just initialize with - // empty contents - savedDatabaseInfo = new HashMap>(); } finally { reader.close(); } } catch (FilerException e) { - // Inability to read is not an error, just initialize with empty - // contents + // This file will only exist and have content during a round of + // incremental compilation, there is no clean way to detect this + // without trying and failing to read the file, so we catch the + // error and initialize with empty contents. savedDatabaseInfo = new HashMap>(); } catch (IOException e) { - // Inability to read is not an error, just initialize with empty - // contents + // This file will only exist and have content during a round of + // incremental compilation, there is no clean way to detect this + // without trying and failing to read the file, so we catch the + // error and initialize with empty contents. savedDatabaseInfo = new HashMap>(); } catch (ClassNotFoundException e) { - // Built-in Java classes will always be available + // Built-in Java classes will always be available so this should + // never happen throw new RuntimeException(e); } @@ -300,9 +301,19 @@ public boolean process(Set elements, "Stored %d Database-to-DatabaseTable mappings", savedDatabaseInfo.size())); } catch (FilerException e) { - // intentionally ignore the error + // should never happen, but if it does, it shouldn't be fatal + // since the worst consequence would be a spurious warning + // during future incremental compilations that would be cleared + // with a full rebuild. + raiseNote("FilerException while saving Database-to-DatabaseTable mappings: " + + e.toString()); } catch (IOException e) { - // intentionally ignore the error + // should never happen, but if it does, it shouldn't be fatal + // since the worst consequence would be a spurious warning + // during future incremental compilations that would be cleared + // with a full rebuild. + raiseNote("IOException while saving Database-to-DatabaseTable mappings: " + + e.toString()); } // Verify that every table is in a database (try to enforce using @@ -398,7 +409,8 @@ private void createDatabaseConfigSourceFile(TypeElement openHelperClass, openHelperClassName .getGeneratedFullyQualifiedClassName())); } catch (IOException e) { - // We should always be able to generate the source files + // We should always be able to generate the source files and if we + // can't we should bail out throw new RuntimeException(e); } } @@ -428,7 +440,8 @@ private void createTableConfigSourceFile(TableBindings table, table.getParsedClassName() .getGeneratedFullyQualifiedClassName())); } catch (IOException e) { - // We should always be able to generate the source files + // We should always be able to generate the source files and if we + // can't we should bail out throw new RuntimeException(e); } } @@ -729,6 +742,8 @@ private void raiseWarning(String message, Element element) { message, element); } catch (NullPointerException e) { // ignore to workaround issues with eclipse incremental compilation + raiseNote("NullPointerException while raising a warning: " + + e.toString()); } } @@ -741,6 +756,8 @@ private void raiseError(String message, Element element) { element); } catch (NullPointerException e) { // ignore to workaround issues with eclipse incremental compilation + raiseNote("NullPointerException while raising an error: " + + e.toString()); } } } From 353c00489c5f76dfcd00f5780b16532f34d4679e Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 11 May 2015 19:18:52 -0700 Subject: [PATCH 21/26] Remove static qualifier from helper functions --- .../processor/OrmLiteAnnotationProcessor.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java index e38e7a89..e33c4982 100644 --- a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java @@ -446,7 +446,7 @@ private void createTableConfigSourceFile(TableBindings table, } } - private static void writeTable(Writer writer, TableBindings table) + private void writeTable(Writer writer, TableBindings table) throws IOException { if (!table.getParsedClassName().getPackageName().isEmpty()) { writer.write("package " @@ -652,7 +652,7 @@ private static void writeTable(Writer writer, TableBindings table) writer.write("}\n"); } - private static boolean writeSetterIfNotDefault(Annotation annotation, + private boolean writeSetterIfNotDefault(Annotation annotation, String annotationFieldName, String setterCall, Writer writer) { try { Method method = annotation.annotationType().getMethod( @@ -687,11 +687,11 @@ private static boolean writeSetterIfNotDefault(Annotation annotation, } } - private static String getClassNameFromClassObject(Object object) { + private String getClassNameFromClassObject(Object object) { return ((Class) object).getCanonicalName(); } - private static String getMirroredClassNameFromException(Exception ex) + private String getMirroredClassNameFromException(Exception ex) throws Exception { Throwable t = ex; do { @@ -704,7 +704,7 @@ private static String getMirroredClassNameFromException(Exception ex) throw ex; } - private static boolean writeSetterIfNotEqual(Object actualValue, + private boolean writeSetterIfNotEqual(Object actualValue, Object defaultValue, String setterCall, Writer writer) throws IOException { if (!actualValue.equals(defaultValue)) { @@ -715,8 +715,8 @@ private static boolean writeSetterIfNotEqual(Object actualValue, } } - private static void writeSetter(Object value, String setterCall, - Writer writer) throws IOException { + private void writeSetter(Object value, String setterCall, Writer writer) + throws IOException { writer.write(String.format("\t\t\tdatabaseFieldConfig." + setterCall + ";\n", value)); } From 3225a13581cf8bd09e5da32109f633a2b3a632e0 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 11 May 2015 19:25:24 -0700 Subject: [PATCH 22/26] Change package declaration in unit test files Change the package declaration in the unit test input resource files to be under the processor package --- src/test/resources/inputs/DatabaseDerivedFromWrongClass.java | 2 +- src/test/resources/inputs/DatabaseWithNoTables.java | 2 +- src/test/resources/inputs/DatabaseWithNonTable.java | 2 +- src/test/resources/inputs/InnerClassTable.java | 2 +- .../resources/inputs/NamedTableWithSpecifiedDatabaseField.java | 2 +- .../inputs/NamedTableWithSpecifiedForeignCollectionField.java | 2 +- .../resources/inputs/TableWithFieldWithBothAnnotations.java | 2 +- .../resources/inputs/UnnamedTableWithDefaultDatabaseField.java | 2 +- .../inputs/UnnamedTableWithDefaultForeignCollectionField.java | 2 +- .../outputs/InnerClassTable_InnerClass_TableConfig.java | 2 +- .../outputs/InnerClassTable_OpenHelper_TableConfig.java | 2 +- .../outputs/InnerClassTable_OtherInnerClass_TableConfig.java | 2 +- ...dTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java | 2 +- .../NamedTableWithSpecifiedDatabaseField_TableConfig.java | 2 +- ...hSpecifiedForeignCollectionField_OpenHelper_TableConfig.java | 2 +- ...medTableWithSpecifiedForeignCollectionField_TableConfig.java | 2 +- ...medTableWithDefaultDatabaseField_OpenHelper_TableConfig.java | 2 +- .../UnnamedTableWithDefaultDatabaseField_TableConfig.java | 2 +- ...ithDefaultForeignCollectionField_OpenHelper_TableConfig.java | 2 +- ...namedTableWithDefaultForeignCollectionField_TableConfig.java | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/test/resources/inputs/DatabaseDerivedFromWrongClass.java b/src/test/resources/inputs/DatabaseDerivedFromWrongClass.java index 20d2f7d2..50149f2e 100644 --- a/src/test/resources/inputs/DatabaseDerivedFromWrongClass.java +++ b/src/test/resources/inputs/DatabaseDerivedFromWrongClass.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import com.j256.ormlite.android.annotations.Database; import com.j256.ormlite.field.DatabaseField; diff --git a/src/test/resources/inputs/DatabaseWithNoTables.java b/src/test/resources/inputs/DatabaseWithNoTables.java index 0a0fe98e..f051a610 100644 --- a/src/test/resources/inputs/DatabaseWithNoTables.java +++ b/src/test/resources/inputs/DatabaseWithNoTables.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import android.content.Context; import android.database.sqlite.SQLiteDatabase.CursorFactory; diff --git a/src/test/resources/inputs/DatabaseWithNonTable.java b/src/test/resources/inputs/DatabaseWithNonTable.java index b8c2c040..3f3cc082 100644 --- a/src/test/resources/inputs/DatabaseWithNonTable.java +++ b/src/test/resources/inputs/DatabaseWithNonTable.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import android.content.Context; import android.database.sqlite.SQLiteDatabase.CursorFactory; diff --git a/src/test/resources/inputs/InnerClassTable.java b/src/test/resources/inputs/InnerClassTable.java index 2e460ddf..45d0c638 100644 --- a/src/test/resources/inputs/InnerClassTable.java +++ b/src/test/resources/inputs/InnerClassTable.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.sql.SQLException; diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java index 365148c5..d2ebb6bb 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedDatabaseField.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.lang.reflect.Field; import java.sql.SQLException; diff --git a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java index 55fda84d..d1257b56 100644 --- a/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java +++ b/src/test/resources/inputs/NamedTableWithSpecifiedForeignCollectionField.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.sql.SQLException; import java.util.List; diff --git a/src/test/resources/inputs/TableWithFieldWithBothAnnotations.java b/src/test/resources/inputs/TableWithFieldWithBothAnnotations.java index 49a88e36..ad3543d1 100644 --- a/src/test/resources/inputs/TableWithFieldWithBothAnnotations.java +++ b/src/test/resources/inputs/TableWithFieldWithBothAnnotations.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.util.List; diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java index ba0e1fb5..a8a46b29 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultDatabaseField.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.sql.SQLException; diff --git a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java index d2475f0b..a8d94f65 100644 --- a/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java +++ b/src/test/resources/inputs/UnnamedTableWithDefaultForeignCollectionField.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.sql.SQLException; import java.util.List; diff --git a/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java b/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java index 9294e2ab..79e0ab40 100644 --- a/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java +++ b/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.util.ArrayList; import java.util.List; diff --git a/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java b/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java index 8ffa4c51..d538a3b7 100644 --- a/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.sql.SQLException; import java.util.ArrayList; diff --git a/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java b/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java index 83c93004..1c8c7783 100644 --- a/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java +++ b/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.util.ArrayList; import java.util.List; diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java index 2240412b..6e967de5 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.sql.SQLException; import java.util.ArrayList; diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java index dd05aeb0..877990c1 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.util.ArrayList; import java.util.List; diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java index 458672d0..c285f6cf 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.sql.SQLException; import java.util.ArrayList; diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java index 0cf646d5..6f77b1ec 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.util.ArrayList; import java.util.List; diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java index 27024937..5df41c09 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.sql.SQLException; import java.util.ArrayList; diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java index db958ea8..217b4b29 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.util.ArrayList; import java.util.List; diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java index 2512625e..3fd630da 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.sql.SQLException; import java.util.ArrayList; diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java index d6bbb46c..a6103627 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java @@ -1,4 +1,4 @@ -package inputs; +package com.j256.ormlite.android.processor.inputs; import java.util.ArrayList; import java.util.List; From 6c14b0392db4d7823e01d2000a7efcf11d6be267 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 11 May 2015 19:40:48 -0700 Subject: [PATCH 23/26] Add documentation to writeSetterIfNotDefault --- .../processor/OrmLiteAnnotationProcessor.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java index e33c4982..f1a2cd4f 100644 --- a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java @@ -652,6 +652,25 @@ private void writeTable(Writer writer, TableBindings table) writer.write("}\n"); } + /** + * This function examines a single field in an annotation and if the current + * value doesn't match the default, outputs a setter call. It returns + * whether it output the setter call in case calling code needs to fall back + * on another field only if the primary field wasn't set (e.g. a deprecated + * field and its replacement). + * + * @param annotation + * the annotation containing the field of interest + * @param annotationFieldName + * the name of the field in the annotation to read + * @param setterCall + * a format string describing the code that should be emitted to + * set this property in the table configuration + * @param writer + * the writer for the generated file + * @return true if the value was not the default and a setter was emitted, + * false if the field had the default value + */ private boolean writeSetterIfNotDefault(Annotation annotation, String annotationFieldName, String setterCall, Writer writer) { try { From 9504f25ca7d08bca5adfe90afb29f6073d414893 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 11 May 2015 20:00:29 -0700 Subject: [PATCH 24/26] Update pom to new processor class path --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da792f9e..751c51e6 100644 --- a/pom.xml +++ b/pom.xml @@ -152,7 +152,7 @@ -proc:none - com/j256/ormlite/android/annotations/OrmLiteAnnotationProcessor.java + com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java From fb1cebdb5021aa13e9b8b2f841865e150e4d0f6d Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Mon, 11 May 2015 20:07:27 -0700 Subject: [PATCH 25/26] Fix expected results files to use new packages --- .../outputs/InnerClassTable_InnerClass_TableConfig.java | 4 ++-- .../outputs/InnerClassTable_OpenHelper_TableConfig.java | 8 ++++---- .../InnerClassTable_OtherInnerClass_TableConfig.java | 4 ++-- ...WithSpecifiedDatabaseField_OpenHelper_TableConfig.java | 4 ++-- .../NamedTableWithSpecifiedDatabaseField_TableConfig.java | 8 ++++---- ...fiedForeignCollectionField_OpenHelper_TableConfig.java | 4 ++-- ...leWithSpecifiedForeignCollectionField_TableConfig.java | 4 ++-- ...leWithDefaultDatabaseField_OpenHelper_TableConfig.java | 4 ++-- .../UnnamedTableWithDefaultDatabaseField_TableConfig.java | 4 ++-- ...aultForeignCollectionField_OpenHelper_TableConfig.java | 4 ++-- ...ableWithDefaultForeignCollectionField_TableConfig.java | 4 ++-- 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java b/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java index 79e0ab40..318a9dac 100644 --- a/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java +++ b/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java @@ -10,7 +10,7 @@ public final class InnerClassTable_InnerClass_TableConfig { private InnerClassTable_InnerClass_TableConfig() { } - public static final DatabaseTableConfig CONFIG; + public static final DatabaseTableConfig CONFIG; static { List databaseFieldConfigs = new ArrayList(); @@ -18,6 +18,6 @@ private InnerClassTable_InnerClass_TableConfig() { DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); databaseFieldConfigs.add(databaseFieldConfig); } - CONFIG = new DatabaseTableConfig(inputs.InnerClassTable.InnerClass.class, "innerclass", databaseFieldConfigs); + CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.InnerClassTable.InnerClass.class, "innerclass", databaseFieldConfigs); } } diff --git a/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java b/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java index d538a3b7..f82a80cd 100644 --- a/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java @@ -15,13 +15,13 @@ private InnerClassTable_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(inputs.InnerClassTable_InnerClass_TableConfig.CONFIG); - tableConfigs.add(inputs.InnerClassTable_OtherInnerClass_TableConfig.CONFIG); + tableConfigs.add(com.j256.ormlite.android.processor.inputs.InnerClassTable_InnerClass_TableConfig.CONFIG); + tableConfigs.add(com.j256.ormlite.android.processor.inputs.InnerClassTable_OtherInnerClass_TableConfig.CONFIG); DaoManager.addCachedDatabaseConfigs(tableConfigs); } public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, inputs.InnerClassTable.InnerClass.class); - TableUtils.createTable(connectionSource, inputs.InnerClassTable.OtherInnerClass.class); + TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.InnerClassTable.InnerClass.class); + TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.InnerClassTable.OtherInnerClass.class); } } diff --git a/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java b/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java index 1c8c7783..9cd8cd4c 100644 --- a/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java +++ b/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java @@ -10,7 +10,7 @@ public final class InnerClassTable_OtherInnerClass_TableConfig { private InnerClassTable_OtherInnerClass_TableConfig() { } - public static final DatabaseTableConfig CONFIG; + public static final DatabaseTableConfig CONFIG; static { List databaseFieldConfigs = new ArrayList(); @@ -18,6 +18,6 @@ private InnerClassTable_OtherInnerClass_TableConfig() { DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); databaseFieldConfigs.add(databaseFieldConfig); } - CONFIG = new DatabaseTableConfig(inputs.InnerClassTable.OtherInnerClass.class, "otherinnerclass", databaseFieldConfigs); + CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.InnerClassTable.OtherInnerClass.class, "otherinnerclass", databaseFieldConfigs); } } diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java index 6e967de5..4f8bdc81 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java @@ -15,11 +15,11 @@ private NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(inputs.NamedTableWithSpecifiedDatabaseField_TableConfig.CONFIG); + tableConfigs.add(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField_TableConfig.CONFIG); DaoManager.addCachedDatabaseConfigs(tableConfigs); } public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, inputs.NamedTableWithSpecifiedDatabaseField.class); + TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField.class); } } diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java index 877990c1..ad6bd949 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java @@ -10,7 +10,7 @@ public final class NamedTableWithSpecifiedDatabaseField_TableConfig { private NamedTableWithSpecifiedDatabaseField_TableConfig() { } - public static final DatabaseTableConfig CONFIG; + public static final DatabaseTableConfig CONFIG; static { List databaseFieldConfigs = new ArrayList(); @@ -26,7 +26,7 @@ private NamedTableWithSpecifiedDatabaseField_TableConfig() { databaseFieldConfig.setGeneratedIdSequence("id_sequence"); databaseFieldConfig.setForeign(true); databaseFieldConfig.setUseGetSet(true); - databaseFieldConfig.setUnknownEnumValue(inputs.NamedTableWithSpecifiedDatabaseField.FieldTypeEnum.OTHER_VALUE); + databaseFieldConfig.setUnknownEnumValue(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField.FieldTypeEnum.OTHER_VALUE); databaseFieldConfig.setThrowIfNull(true); databaseFieldConfig.setFormat("%f"); databaseFieldConfig.setUnique(true); @@ -37,7 +37,7 @@ private NamedTableWithSpecifiedDatabaseField_TableConfig() { databaseFieldConfig.setUniqueIndexName("unique_index"); databaseFieldConfig.setForeignAutoRefresh(true); databaseFieldConfig.setMaxForeignAutoRefreshLevel(5); - databaseFieldConfig.setPersisterClass(inputs.NamedTableWithSpecifiedDatabaseField.CustomPersister.class); + databaseFieldConfig.setPersisterClass(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField.CustomPersister.class); databaseFieldConfig.setAllowGeneratedIdInsert(true); databaseFieldConfig.setColumnDefinition("INT NOT NULL"); databaseFieldConfig.setForeignAutoCreate(true); @@ -46,6 +46,6 @@ private NamedTableWithSpecifiedDatabaseField_TableConfig() { databaseFieldConfig.setReadOnly(true); databaseFieldConfigs.add(databaseFieldConfig); } - CONFIG = new DatabaseTableConfig(inputs.NamedTableWithSpecifiedDatabaseField.class, "table", databaseFieldConfigs); + CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField.class, "table", databaseFieldConfigs); } } diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java index c285f6cf..b212df61 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java @@ -15,11 +15,11 @@ private NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(inputs.NamedTableWithSpecifiedForeignCollectionField_TableConfig.CONFIG); + tableConfigs.add(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedForeignCollectionField_TableConfig.CONFIG); DaoManager.addCachedDatabaseConfigs(tableConfigs); } public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, inputs.NamedTableWithSpecifiedForeignCollectionField.class); + TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedForeignCollectionField.class); } } diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java index 6f77b1ec..98ae4a73 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java @@ -10,7 +10,7 @@ public final class NamedTableWithSpecifiedForeignCollectionField_TableConfig { private NamedTableWithSpecifiedForeignCollectionField_TableConfig() { } - public static final DatabaseTableConfig CONFIG; + public static final DatabaseTableConfig CONFIG; static { List databaseFieldConfigs = new ArrayList(); @@ -33,6 +33,6 @@ private NamedTableWithSpecifiedForeignCollectionField_TableConfig() { databaseFieldConfig.setForeignCollectionForeignFieldName("foreign_field"); databaseFieldConfigs.add(databaseFieldConfig); } - CONFIG = new DatabaseTableConfig(inputs.NamedTableWithSpecifiedForeignCollectionField.class, "table", databaseFieldConfigs); + CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedForeignCollectionField.class, "table", databaseFieldConfigs); } } diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java index 5df41c09..9a761da0 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java @@ -15,11 +15,11 @@ private UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(inputs.UnnamedTableWithDefaultDatabaseField_TableConfig.CONFIG); + tableConfigs.add(com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultDatabaseField_TableConfig.CONFIG); DaoManager.addCachedDatabaseConfigs(tableConfigs); } public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, inputs.UnnamedTableWithDefaultDatabaseField.class); + TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultDatabaseField.class); } } diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java index 217b4b29..5fe2b629 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java @@ -10,7 +10,7 @@ public final class UnnamedTableWithDefaultDatabaseField_TableConfig { private UnnamedTableWithDefaultDatabaseField_TableConfig() { } - public static final DatabaseTableConfig CONFIG; + public static final DatabaseTableConfig CONFIG; static { List databaseFieldConfigs = new ArrayList(); @@ -18,6 +18,6 @@ private UnnamedTableWithDefaultDatabaseField_TableConfig() { DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); databaseFieldConfigs.add(databaseFieldConfig); } - CONFIG = new DatabaseTableConfig(inputs.UnnamedTableWithDefaultDatabaseField.class, "unnamedtablewithdefaultdatabasefield", databaseFieldConfigs); + CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultDatabaseField.class, "unnamedtablewithdefaultdatabasefield", databaseFieldConfigs); } } diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java index 3fd630da..fd6443c4 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java @@ -15,11 +15,11 @@ private UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(inputs.UnnamedTableWithDefaultForeignCollectionField_TableConfig.CONFIG); + tableConfigs.add(com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultForeignCollectionField_TableConfig.CONFIG); DaoManager.addCachedDatabaseConfigs(tableConfigs); } public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, inputs.UnnamedTableWithDefaultForeignCollectionField.class); + TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultForeignCollectionField.class); } } diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java index a6103627..ca3244de 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java @@ -10,7 +10,7 @@ public final class UnnamedTableWithDefaultForeignCollectionField_TableConfig { private UnnamedTableWithDefaultForeignCollectionField_TableConfig() { } - public static final DatabaseTableConfig CONFIG; + public static final DatabaseTableConfig CONFIG; static { List databaseFieldConfigs = new ArrayList(); @@ -19,6 +19,6 @@ private UnnamedTableWithDefaultForeignCollectionField_TableConfig() { databaseFieldConfig.setForeignCollection(true); databaseFieldConfigs.add(databaseFieldConfig); } - CONFIG = new DatabaseTableConfig(inputs.UnnamedTableWithDefaultForeignCollectionField.class, "unnamedtablewithdefaultforeigncollectionfield", databaseFieldConfigs); + CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultForeignCollectionField.class, "unnamedtablewithdefaultforeigncollectionfield", databaseFieldConfigs); } } From 5d2186c1466c94889eec5d69a8f19d8d0af5db21 Mon Sep 17 00:00:00 2001 From: Nathan Crouther Date: Tue, 12 May 2015 18:56:14 -0700 Subject: [PATCH 26/26] Use JavaPoet to create source files --- pom.xml | 32 + .../android/processor/FieldBindings.java | 27 +- .../processor/OrmLiteAnnotationProcessor.java | 606 +++++++++--------- .../android/processor/ParsedClassName.java | 10 +- .../android/processor/SetterBindings.java | 19 + .../android/processor/TableBindings.java | 12 +- ...nnerClassTable_InnerClass_TableConfig.java | 21 +- ...nnerClassTable_OpenHelper_TableConfig.java | 23 +- ...lassTable_OtherInnerClass_TableConfig.java | 21 +- ...dDatabaseField_OpenHelper_TableConfig.java | 18 +- ...ithSpecifiedDatabaseField_TableConfig.java | 80 +-- ...ollectionField_OpenHelper_TableConfig.java | 19 +- ...iedForeignCollectionField_TableConfig.java | 53 +- ...tDatabaseField_OpenHelper_TableConfig.java | 18 +- ...eWithDefaultDatabaseField_TableConfig.java | 21 +- ...ollectionField_OpenHelper_TableConfig.java | 19 +- ...ultForeignCollectionField_TableConfig.java | 25 +- 17 files changed, 522 insertions(+), 502 deletions(-) create mode 100644 src/main/java/com/j256/ormlite/android/processor/SetterBindings.java diff --git a/pom.xml b/pom.xml index 751c51e6..062ed078 100644 --- a/pom.xml +++ b/pom.xml @@ -266,6 +266,33 @@ $1${version}$2
+ + org.apache.maven.plugins + maven-shade-plugin + 2.3 + + + package + + shade + + + + + com.squareup:javapoet + + + true + + + com.squareup.javapoet + com.j256.ormlite.android.processor.javapoet + + + + + + @@ -348,6 +375,11 @@ ${android-support-version} true + + com.squareup + javapoet + 1.0.0 + diff --git a/src/main/java/com/j256/ormlite/android/processor/FieldBindings.java b/src/main/java/com/j256/ormlite/android/processor/FieldBindings.java index 70c99da2..6a99b4df 100644 --- a/src/main/java/com/j256/ormlite/android/processor/FieldBindings.java +++ b/src/main/java/com/j256/ormlite/android/processor/FieldBindings.java @@ -1,36 +1,21 @@ package com.j256.ormlite.android.processor; -import com.j256.ormlite.field.DatabaseField; -import com.j256.ormlite.field.ForeignCollectionField; +import java.util.List; class FieldBindings { - private final String fullyQualifiedTypeName; private final String fieldName; - private final DatabaseField databaseFieldAnnotation; - private final ForeignCollectionField foreignCollectionFieldAnnotation; + private final List setters; - FieldBindings(String fullyQualifiedTypeName, String fieldName, - DatabaseField databaseFieldAnnotation, - ForeignCollectionField foreignCollectionFieldAnnotation) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; + FieldBindings(String fieldName, List setters) { this.fieldName = fieldName; - this.databaseFieldAnnotation = databaseFieldAnnotation; - this.foreignCollectionFieldAnnotation = foreignCollectionFieldAnnotation; - } - - String getFullyQualifiedTypeName() { - return fullyQualifiedTypeName; + this.setters = setters; } String getFieldName() { return fieldName; } - DatabaseField getDatabaseFieldAnnotation() { - return databaseFieldAnnotation; - } - - ForeignCollectionField getForeignCollectionFieldAnnotation() { - return foreignCollectionFieldAnnotation; + List getSetters() { + return setters; } } diff --git a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java index f1a2cd4f..e6918adb 100644 --- a/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java +++ b/src/main/java/com/j256/ormlite/android/processor/OrmLiteAnnotationProcessor.java @@ -1,9 +1,22 @@ package com.j256.ormlite.android.processor; import com.j256.ormlite.android.annotations.Database; +import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.field.ForeignCollectionField; +import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTable; +import com.j256.ormlite.table.DatabaseTableConfig; +import com.j256.ormlite.table.TableUtils; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import com.squareup.javapoet.WildcardTypeName; import java.io.IOException; import java.io.ObjectInputStream; @@ -11,6 +24,7 @@ import java.io.Writer; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -24,6 +38,7 @@ import javax.annotation.processing.FilerException; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; +import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.SourceVersion; import javax.lang.model.type.MirroredTypeException; @@ -75,7 +90,9 @@ public boolean process(Set elements, RoundEnvironment env) { for (Element element : env .getElementsAnnotatedWith(DatabaseTable.class)) { - if (element.getAnnotation(DatabaseTable.class) == null) { + DatabaseTable annotation = element + .getAnnotation(DatabaseTable.class); + if (annotation == null) { continue; } @@ -83,9 +100,17 @@ public boolean process(Set elements, DatabaseTable.class.getSimpleName(), ((TypeElement) element).getQualifiedName())); - TableBindings table = new TableBindings( - new ParsedClassName(element), - element.getAnnotation(DatabaseTable.class)); + ParsedClassName parsedClassName = new ParsedClassName(element); + + String tableName; + if (annotation.tableName() != null + && annotation.tableName().length() > 0) { + tableName = annotation.tableName(); + } else { + tableName = element.getSimpleName().toString().toLowerCase(); + } + + TableBindings table = new TableBindings(parsedClassName, tableName); // get all fields from this and all parents until we hit Object TypeElement tableClassElement = (TypeElement) element; @@ -97,13 +122,29 @@ public boolean process(Set elements, .getAnnotation(DatabaseField.class); ForeignCollectionField foreignCollectionField = child .getAnnotation(ForeignCollectionField.class); - if (databaseField != null - || foreignCollectionField != null) { - FieldBindings field = new FieldBindings(child - .asType().toString(), child.getSimpleName() - .toString(), databaseField, - foreignCollectionField); - table.addField(field); + + if (databaseField != null) { + if (databaseField.persisted()) { + table.addField(new FieldBindings(child + .getSimpleName().toString(), + getSettersForDatabaseField( + databaseField, child.asType() + .toString()))); + } + if (foreignCollectionField != null) { + raiseError( + String.format( + "Fields cannot be annotated with both %s and %s", + DatabaseField.class + .getSimpleName(), + ForeignCollectionField.class + .getSimpleName()), + child); + } + } else if (foreignCollectionField != null) { + table.addField(new FieldBindings( + child.getSimpleName().toString(), + getSettersForForeignCollectionField(foreignCollectionField))); } if (databaseField != null @@ -339,10 +380,10 @@ public boolean process(Set elements, return true; } - private void createDatabaseConfigSourceFile(TypeElement openHelperClass, - List tableClasses) { + private void createDatabaseConfigSourceFile( + TypeElement openHelperClassElement, List tableClasses) { ParsedClassName openHelperClassName = new ParsedClassName( - openHelperClass); + openHelperClassElement); try { JavaFileObject javaFileObject = processingEnv @@ -350,52 +391,66 @@ private void createDatabaseConfigSourceFile(TypeElement openHelperClass, .createSourceFile( openHelperClassName .getGeneratedFullyQualifiedClassName(), - openHelperClass); + openHelperClassElement); Writer writer = javaFileObject.openWriter(); + try { - writer.write("package " + openHelperClassName.getPackageName() - + ";\n"); - writer.write("\n"); - writer.write("import java.sql.SQLException;\n"); - writer.write("import java.util.ArrayList;\n"); - writer.write("import java.util.List;\n"); - writer.write("\n"); - writer.write("import com.j256.ormlite.dao.DaoManager;\n"); - writer.write("import com.j256.ormlite.support.ConnectionSource;\n"); - writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); - writer.write("import com.j256.ormlite.table.TableUtils;\n"); - writer.write("\n"); - writer.write("public final class " - + openHelperClassName.getGeneratedClassName() + " {\n"); - writer.write("\tprivate " - + openHelperClassName.getGeneratedClassName() - + "() {\n"); - writer.write("\t}\n"); - writer.write("\n"); - writer.write("\tpublic static void cacheTableConfigurations() {\n"); - writer.write("\t\tList> tableConfigs = new ArrayList>();\n"); + MethodSpec.Builder constructor = MethodSpec + .constructorBuilder().addModifiers(Modifier.PRIVATE); + + MethodSpec.Builder cacheTableConfigurations = MethodSpec + .methodBuilder("cacheTableConfigurations") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC); + cacheTableConfigurations.addStatement( + "$T tableConfigs = new $T()", + ParameterizedTypeName.get(ClassName.get(List.class), + ParameterizedTypeName.get(ClassName + .get(DatabaseTableConfig.class), + WildcardTypeName + .subtypeOf(Object.class))), + ParameterizedTypeName.get(ClassName + .get(ArrayList.class), ParameterizedTypeName + .get(ClassName.get(DatabaseTableConfig.class), + WildcardTypeName + .subtypeOf(Object.class)))); for (TypeElement tableClass : tableClasses) { ParsedClassName tableClassName = new ParsedClassName( tableClass); - writer.write("\t\ttableConfigs.add(" - + tableClassName - .getGeneratedFullyQualifiedClassName() - + ".CONFIG);\n"); + cacheTableConfigurations.addStatement( + "tableConfigs.add($T.createConfig())", ClassName + .get(tableClassName.getPackageName(), + tableClassName + .getGeneratedClassName())); } - writer.write("\t\tDaoManager.addCachedDatabaseConfigs(tableConfigs);\n"); - writer.write("\t}\n"); - writer.write("\n"); - writer.write("\tpublic static void createTables(ConnectionSource connectionSource) throws SQLException {\n"); + cacheTableConfigurations.addStatement( + "$T.addCachedDatabaseConfigs(tableConfigs)", + DaoManager.class); + + MethodSpec.Builder createTables = MethodSpec + .methodBuilder("createTables") + .addParameter(ConnectionSource.class, + "connectionSource") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .addException(SQLException.class); for (TypeElement tableClass : tableClasses) { - ParsedClassName tableClassName = new ParsedClassName( - tableClass); - writer.write("\t\tTableUtils.createTable(connectionSource, " - + tableClassName.getInputFullyQualifiedClassName() - + ".class);\n"); + createTables.addStatement( + "$T.createTable(connectionSource, $T.class)", + TableUtils.class, tableClass.asType()); } - writer.write("\t}\n"); - writer.write("}\n"); + + TypeSpec.Builder openHelperClass = TypeSpec + .classBuilder( + openHelperClassName.getGeneratedClassName()) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addMethod(constructor.build()) + .addMethod(cacheTableConfigurations.build()) + .addMethod(createTables.build()); + + JavaFile openHelperFile = JavaFile.builder( + openHelperClassName.getPackageName(), + openHelperClass.build()).build(); + openHelperFile.writeTo(writer); } finally { writer.close(); } @@ -415,267 +470,121 @@ private void createDatabaseConfigSourceFile(TypeElement openHelperClass, } } - private void createTableConfigSourceFile(TableBindings table, - Element tableClassElement) { - try { - JavaFileObject javaFileObject = processingEnv.getFiler() - .createSourceFile( - table.getParsedClassName() - .getGeneratedFullyQualifiedClassName(), - tableClassElement); - - Writer writer = javaFileObject.openWriter(); - try { - writeTable(writer, table); - } finally { - writer.close(); - } - } catch (FilerException e) { - // if multiple classes are in the same file (e.g. inner/nested - // classes), eclipse will do an incremental compilation for all of - // them. The unchanged ones' generated files will not be deleted, so - // we can ignore this benign error. - raiseNote(String - .format("Skipping file generation for %s since file already exists", - table.getParsedClassName() - .getGeneratedFullyQualifiedClassName())); - } catch (IOException e) { - // We should always be able to generate the source files and if we - // can't we should bail out - throw new RuntimeException(e); - } + private List getSettersForDatabaseField( + DatabaseField annotation, String fullyQualifiedFieldType) { + List output = new ArrayList(); + addSetterIfNotDefault(annotation, "columnName", "setColumnName($S)", + output); + addSetterIfNotDefault(annotation, "dataType", + "setDataType(com.j256.ormlite.field.DataType.$L)", output); + addSetterIfNotDefault(annotation, "defaultValue", + "setDefaultValue($S)", output); + addSetterIfNotDefault(annotation, "width", "setWidth($L)", output); + addSetterIfNotDefault(annotation, "canBeNull", "setCanBeNull($L)", + output); + addSetterIfNotDefault(annotation, "id", "setId($L)", output); + addSetterIfNotDefault(annotation, "generatedId", "setGeneratedId($L)", + output); + addSetterIfNotDefault(annotation, "generatedIdSequence", + "setGeneratedIdSequence($S)", output); + addSetterIfNotDefault(annotation, "foreign", "setForeign($L)", output); + addSetterIfNotDefault(annotation, "useGetSet", "setUseGetSet($L)", + output); + addSetterIfNotDefault(annotation, "unknownEnumName", + "setUnknownEnumValue(" + fullyQualifiedFieldType + ".$L)", + output); + addSetterIfNotDefault(annotation, "throwIfNull", "setThrowIfNull($L)", + output); + addSetterIfNotDefault(annotation, "format", "setFormat($S)", output); + addSetterIfNotDefault(annotation, "unique", "setUnique($L)", output); + addSetterIfNotDefault(annotation, "uniqueCombo", "setUniqueCombo($L)", + output); + addSetterIfNotDefault(annotation, "index", "setIndex($L)", output); + addSetterIfNotDefault(annotation, "uniqueIndex", "setUniqueIndex($L)", + output); + addSetterIfNotDefault(annotation, "indexName", "setIndexName($S)", + output); + addSetterIfNotDefault(annotation, "uniqueIndexName", + "setUniqueIndexName($S)", output); + addSetterIfNotDefault(annotation, "foreignAutoRefresh", + "setForeignAutoRefresh($L)", output); + addSetterIfNotDefault(annotation, "maxForeignAutoRefreshLevel", + "setMaxForeignAutoRefreshLevel($L)", output); + addSetterIfNotDefault(annotation, "persisterClass", + "setPersisterClass($T.class)", output); + addSetterIfNotDefault(annotation, "allowGeneratedIdInsert", + "setAllowGeneratedIdInsert($L)", output); + addSetterIfNotDefault(annotation, "columnDefinition", + "setColumnDefinition($S)", output); + addSetterIfNotDefault(annotation, "foreignAutoCreate", + "setForeignAutoCreate($L)", output); + addSetterIfNotDefault(annotation, "version", "setVersion($L)", output); + addSetterIfNotDefault(annotation, "foreignColumnName", + "setForeignColumnName($S)", output); + addSetterIfNotDefault(annotation, "readOnly", "setReadOnly($L)", output); + return output; } - private void writeTable(Writer writer, TableBindings table) - throws IOException { - if (!table.getParsedClassName().getPackageName().isEmpty()) { - writer.write("package " - + table.getParsedClassName().getPackageName() + ";\n"); - writer.write("\n"); - } - writer.write("import java.util.ArrayList;\n"); - writer.write("import java.util.List;\n"); - writer.write("\n"); - writer.write("import com.j256.ormlite.field.DatabaseFieldConfig;\n"); - writer.write("import com.j256.ormlite.table.DatabaseTableConfig;\n"); - writer.write("\n"); - writer.write("public final class " - + table.getParsedClassName().getGeneratedClassName() + " {\n"); - writer.write("\tprivate " - + table.getParsedClassName().getGeneratedClassName() + "() {\n"); - writer.write("\t}\n"); - writer.write("\n"); - writer.write("\tpublic static final DatabaseTableConfig<" - + table.getParsedClassName().getInputFullyQualifiedClassName() - + "> CONFIG;\n"); - writer.write("\n"); - writer.write("\tstatic {\n"); - writer.write("\t\tList databaseFieldConfigs = new ArrayList();\n"); - for (FieldBindings field : table.getFields()) { - - if (field.getDatabaseFieldAnnotation() != null - && !field.getDatabaseFieldAnnotation().persisted()) { - continue; - } - - writer.write("\t\t{\n"); - writer.write(String - .format("\t\t\tDatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig(\"%s\");\n", - field.getFieldName())); - - if (field.getDatabaseFieldAnnotation() != null) { - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "columnName", "setColumnName(\"%s\")", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "dataType", - "setDataType(com.j256.ormlite.field.DataType.%s)", - writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "defaultValue", "setDefaultValue(\"%s\")", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "width", "setWidth(%d)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "canBeNull", "setCanBeNull(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "id", "setId(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "generatedId", "setGeneratedId(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "generatedIdSequence", - "setGeneratedIdSequence(\"%s\")", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "foreign", "setForeign(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "useGetSet", "setUseGetSet(%b)", writer); - - writeSetterIfNotDefault( - field.getDatabaseFieldAnnotation(), - "unknownEnumName", - "setUnknownEnumValue(" - + field.getFullyQualifiedTypeName() + ".%s)", - writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "throwIfNull", "setThrowIfNull(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "format", "setFormat(\"%s\")", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "unique", "setUnique(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "uniqueCombo", "setUniqueCombo(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "index", "setIndex(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "uniqueIndex", "setUniqueIndex(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "indexName", "setIndexName(\"%s\")", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "uniqueIndexName", "setUniqueIndexName(\"%s\")", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "foreignAutoRefresh", "setForeignAutoRefresh(%b)", - writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "maxForeignAutoRefreshLevel", - "setMaxForeignAutoRefreshLevel(%d)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "persisterClass", "setPersisterClass(%s.class)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "allowGeneratedIdInsert", - "setAllowGeneratedIdInsert(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "columnDefinition", "setColumnDefinition(\"%s\")", - writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "foreignAutoCreate", "setForeignAutoCreate(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "version", "setVersion(%b)", writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "foreignColumnName", "setForeignColumnName(\"%s\")", - writer); - - writeSetterIfNotDefault(field.getDatabaseFieldAnnotation(), - "readOnly", "setReadOnly(%b)", writer); - } + private List getSettersForForeignCollectionField( + ForeignCollectionField annotation) { + List output = new ArrayList(); + addSetterIfNotDefault(annotation, "columnName", "setColumnName($S)", + output); + addSetter("setForeignCollection($L)", true, output); + addSetterIfNotDefault(annotation, "eager", + "setForeignCollectionEager($L)", output); + addSetterIfNotDefault(annotation, "maxEagerLevel", + "maxEagerForeignCollectionLevel", + "setForeignCollectionMaxEagerLevel($L)", output); + addSetterIfNotDefault(annotation, "columnName", + "setForeignCollectionColumnName($S)", output); + addSetterIfNotDefault(annotation, "orderColumnName", + "setForeignCollectionOrderColumnName($S)", output); + addSetterIfNotDefault(annotation, "orderAscending", + "setForeignCollectionOrderAscending($L)", output); + addSetterIfNotDefault(annotation, "foreignFieldName", + "foreignColumnName", + "setForeignCollectionForeignFieldName($S)", output); + return output; + } - if (field.getForeignCollectionFieldAnnotation() != null) { - writeSetterIfNotDefault( - field.getForeignCollectionFieldAnnotation(), - "columnName", "setColumnName(\"%s\")", writer); - - writeSetter(true, "setForeignCollection(%b)", writer); - - writeSetterIfNotDefault( - field.getForeignCollectionFieldAnnotation(), "eager", - "setForeignCollectionEager(%b)", writer); - - if (!writeSetterIfNotDefault( - field.getForeignCollectionFieldAnnotation(), - "maxEagerLevel", - "setForeignCollectionMaxEagerLevel(%d)", writer)) { - writeSetterIfNotDefault( - field.getForeignCollectionFieldAnnotation(), - "maxEagerForeignCollectionLevel", - "setForeignCollectionMaxEagerLevel(%d)", writer); - } + private void addSetterIfNotDefault(Annotation annotation, String name, + String format, List output) { + addSetterIfNotDefault(annotation, name, null, format, output); + } - writeSetterIfNotDefault( - field.getForeignCollectionFieldAnnotation(), - "columnName", "setForeignCollectionColumnName(\"%s\")", - writer); - - writeSetterIfNotDefault( - field.getForeignCollectionFieldAnnotation(), - "orderColumnName", - "setForeignCollectionOrderColumnName(\"%s\")", writer); - - writeSetterIfNotDefault( - field.getForeignCollectionFieldAnnotation(), - "orderAscending", - "setForeignCollectionOrderAscending(%b)", writer); - - if (!writeSetterIfNotDefault( - field.getForeignCollectionFieldAnnotation(), - "foreignFieldName", - "setForeignCollectionForeignFieldName(\"%s\")", writer)) { - writeSetterIfNotDefault( - field.getForeignCollectionFieldAnnotation(), - "foreignColumnName", - "setForeignCollectionForeignFieldName(\"%s\")", - writer); - } + private void addSetterIfNotDefault(Annotation annotation, String name, + String fallbackName, String format, List output) { + Object value = getValueIfNotDefault(annotation, name); + if (value != null) { + addSetter(format, value, output); + } else if (fallbackName != null) { + value = getValueIfNotDefault(annotation, fallbackName); + if (value != null) { + addSetter(format, value, output); } - - writer.write("\t\t\tdatabaseFieldConfigs.add(databaseFieldConfig);\n"); - writer.write("\t\t}\n"); - } - - String tableName; - if (table.getAnnotation().tableName() != null - && table.getAnnotation().tableName().length() > 0) { - tableName = table.getAnnotation().tableName(); - } else { - tableName = table.getParsedClassName().getInputSimpleClassName() - .toLowerCase(); } + } - writer.write(String - .format("\t\tCONFIG = new DatabaseTableConfig<%s>(%s.class, \"%s\", databaseFieldConfigs);\n", - table.getParsedClassName() - .getInputFullyQualifiedClassName(), table - .getParsedClassName() - .getInputFullyQualifiedClassName(), tableName)); - writer.write("\t}\n"); - writer.write("}\n"); + private void addSetter(String format, Object value, + List output) { + output.add(new SetterBindings(format, value)); } /** * This function examines a single field in an annotation and if the current - * value doesn't match the default, outputs a setter call. It returns - * whether it output the setter call in case calling code needs to fall back - * on another field only if the primary field wasn't set (e.g. a deprecated - * field and its replacement). + * value doesn't match the default returns the current value. If the current + * value matches the default, it returns null. * * @param annotation * the annotation containing the field of interest - * @param annotationFieldName + * @param name * the name of the field in the annotation to read - * @param setterCall - * a format string describing the code that should be emitted to - * set this property in the table configuration - * @param writer - * the writer for the generated file - * @return true if the value was not the default and a setter was emitted, - * false if the field had the default value + * @return the current value if it is not the default, null otherwise */ - private boolean writeSetterIfNotDefault(Annotation annotation, - String annotationFieldName, String setterCall, Writer writer) { + private Object getValueIfNotDefault(Annotation annotation, String name) { try { - Method method = annotation.annotationType().getMethod( - annotationFieldName); + Method method = annotation.annotationType().getMethod(name); Object actualValue; Object defaultValue; @@ -697,8 +606,11 @@ private boolean writeSetterIfNotDefault(Annotation annotation, defaultValue = method.getDefaultValue(); } - return writeSetterIfNotEqual(actualValue, defaultValue, setterCall, - writer); + if (defaultValue.equals(actualValue)) { + return null; + } else { + return actualValue; + } } catch (Exception e) { // All possible annotation properties are unit tested, so it is not // possible to get an exception here @@ -706,16 +618,17 @@ private boolean writeSetterIfNotDefault(Annotation annotation, } } - private String getClassNameFromClassObject(Object object) { - return ((Class) object).getCanonicalName(); + private TypeName getClassNameFromClassObject(Object object) { + return TypeName.get((Class) object); } - private String getMirroredClassNameFromException(Exception ex) + private TypeName getMirroredClassNameFromException(Exception ex) throws Exception { Throwable t = ex; do { if (t instanceof MirroredTypeException) { - return ((MirroredTypeException) t).getTypeMirror().toString(); + return TypeName + .get(((MirroredTypeException) t).getTypeMirror()); } t = t.getCause(); } while (t != null); @@ -723,21 +636,90 @@ private String getMirroredClassNameFromException(Exception ex) throw ex; } - private boolean writeSetterIfNotEqual(Object actualValue, - Object defaultValue, String setterCall, Writer writer) - throws IOException { - if (!actualValue.equals(defaultValue)) { - writeSetter(actualValue, setterCall, writer); - return true; - } else { - return false; + private void createTableConfigSourceFile(TableBindings table, + Element tableClassElement) { + try { + JavaFileObject javaFileObject = processingEnv.getFiler() + .createSourceFile( + table.getParsedClassName() + .getGeneratedFullyQualifiedClassName(), + tableClassElement); + + Writer writer = javaFileObject.openWriter(); + try { + writeTable(writer, table); + } finally { + writer.close(); + } + } catch (FilerException e) { + // if multiple classes are in the same file (e.g. inner/nested + // classes), eclipse will do an incremental compilation for all of + // them. The unchanged ones' generated files will not be deleted, so + // we can ignore this benign error. + raiseNote(String + .format("Skipping file generation for %s since file already exists", + table.getParsedClassName() + .getGeneratedFullyQualifiedClassName())); + } catch (IOException e) { + // We should always be able to generate the source files and if we + // can't we should bail out + throw new RuntimeException(e); } } - private void writeSetter(Object value, String setterCall, Writer writer) + private void writeTable(Writer writer, TableBindings table) throws IOException { - writer.write(String.format("\t\t\tdatabaseFieldConfig." + setterCall - + ";\n", value)); + MethodSpec.Builder constructor = MethodSpec.constructorBuilder() + .addModifiers(Modifier.PRIVATE); + + MethodSpec.Builder createConfig = MethodSpec + .methodBuilder("createConfig") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns( + ParameterizedTypeName.get( + ClassName.get(DatabaseTableConfig.class), + WildcardTypeName.subtypeOf(Object.class))); + createConfig.addStatement("$T databaseFieldConfigs = new $T()", + ParameterizedTypeName.get(ClassName.get(List.class), + TypeName.get(DatabaseFieldConfig.class)), + ParameterizedTypeName.get(ClassName.get(ArrayList.class), + TypeName.get(DatabaseFieldConfig.class))); + + for (FieldBindings field : table.getFields()) { + createConfig.addStatement("$T $LFieldConfig = new $T($S)", + DatabaseFieldConfig.class, field.getFieldName(), + DatabaseFieldConfig.class, field.getFieldName()); + + for (SetterBindings setter : field.getSetters()) { + createConfig.addStatement( + "$LFieldConfig." + setter.getFormat(), + field.getFieldName(), setter.getParameter()); + } + + createConfig.addStatement( + "databaseFieldConfigs.add($LFieldConfig)", + field.getFieldName()); + } + + createConfig.addStatement( + "return new $T<$T>($T.class, $S, databaseFieldConfigs)", + DatabaseTableConfig.class, ClassName.get(table + .getParsedClassName().getPackageName(), table + .getParsedClassName().getInputClassName()), ClassName + .get(table.getParsedClassName().getPackageName(), table + .getParsedClassName().getInputClassName()), + table.getTableName()); + + TypeSpec.Builder tableConfigClass = TypeSpec + .classBuilder( + table.getParsedClassName().getGeneratedClassName()) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addMethod(constructor.build()).addMethod(createConfig.build()); + + JavaFile tableConfigFile = JavaFile.builder( + table.getParsedClassName().getPackageName(), + tableConfigClass.build()).build(); + tableConfigFile.writeTo(writer); } private void raiseNote(String message) { diff --git a/src/main/java/com/j256/ormlite/android/processor/ParsedClassName.java b/src/main/java/com/j256/ormlite/android/processor/ParsedClassName.java index 2e93e1aa..bc136c2e 100644 --- a/src/main/java/com/j256/ormlite/android/processor/ParsedClassName.java +++ b/src/main/java/com/j256/ormlite/android/processor/ParsedClassName.java @@ -39,6 +39,12 @@ String getInputFullyQualifiedClassName() { sb.append(packageName); sb.append('.'); } + sb.append(getInputClassName()); + return sb.toString(); + } + + String getInputClassName() { + StringBuilder sb = new StringBuilder(); for (int i = 0; i < nestedClasses.size(); ++i) { if (i != 0) { sb.append('.'); @@ -48,10 +54,6 @@ String getInputFullyQualifiedClassName() { return sb.toString(); } - String getInputSimpleClassName() { - return nestedClasses.get(nestedClasses.size() - 1); - } - String getGeneratedClassName() { final String SUFFIX = "_TableConfig"; diff --git a/src/main/java/com/j256/ormlite/android/processor/SetterBindings.java b/src/main/java/com/j256/ormlite/android/processor/SetterBindings.java new file mode 100644 index 00000000..0bf22b4e --- /dev/null +++ b/src/main/java/com/j256/ormlite/android/processor/SetterBindings.java @@ -0,0 +1,19 @@ +package com.j256.ormlite.android.processor; + +class SetterBindings { + private final String format; + private final Object parameter; + + SetterBindings(String format, Object parameter) { + this.format = format; + this.parameter = parameter; + } + + String getFormat() { + return format; + } + + Object getParameter() { + return parameter; + } +} diff --git a/src/main/java/com/j256/ormlite/android/processor/TableBindings.java b/src/main/java/com/j256/ormlite/android/processor/TableBindings.java index 1888d86f..5c98fb3b 100644 --- a/src/main/java/com/j256/ormlite/android/processor/TableBindings.java +++ b/src/main/java/com/j256/ormlite/android/processor/TableBindings.java @@ -3,16 +3,14 @@ import java.util.ArrayList; import java.util.List; -import com.j256.ormlite.table.DatabaseTable; - class TableBindings { private final ParsedClassName parsedClassName; - private final DatabaseTable annotation; + private final String tableName; private final List fields = new ArrayList(); - TableBindings(ParsedClassName parsedClassName, DatabaseTable annotation) { + TableBindings(ParsedClassName parsedClassName, String tableName) { this.parsedClassName = parsedClassName; - this.annotation = annotation; + this.tableName = tableName; } void addField(FieldBindings field) { @@ -23,8 +21,8 @@ ParsedClassName getParsedClassName() { return parsedClassName; } - DatabaseTable getAnnotation() { - return annotation; + String getTableName() { + return tableName; } List getFields() { diff --git a/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java b/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java index 318a9dac..9adc54bc 100644 --- a/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java +++ b/src/test/resources/outputs/InnerClassTable_InnerClass_TableConfig.java @@ -1,23 +1,20 @@ package com.j256.ormlite.android.processor.inputs; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import java.util.ArrayList; +import java.util.List; public final class InnerClassTable_InnerClass_TableConfig { private InnerClassTable_InnerClass_TableConfig() { } - public static final DatabaseTableConfig CONFIG; - - static { + public static DatabaseTableConfig createConfig() { List databaseFieldConfigs = new ArrayList(); - { - DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); - databaseFieldConfigs.add(databaseFieldConfig); - } - CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.InnerClassTable.InnerClass.class, "innerclass", databaseFieldConfigs); + DatabaseFieldConfig fieldFieldConfig = new DatabaseFieldConfig("field"); + databaseFieldConfigs.add(fieldFieldConfig); + return new DatabaseTableConfig( + InnerClassTable.InnerClass.class, "innerclass", + databaseFieldConfigs); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java b/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java index f82a80cd..f1e21202 100644 --- a/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/InnerClassTable_OpenHelper_TableConfig.java @@ -1,13 +1,12 @@ package com.j256.ormlite.android.processor.inputs; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTableConfig; import com.j256.ormlite.table.TableUtils; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; public final class InnerClassTable_OpenHelper_TableConfig { private InnerClassTable_OpenHelper_TableConfig() { @@ -15,13 +14,17 @@ private InnerClassTable_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(com.j256.ormlite.android.processor.inputs.InnerClassTable_InnerClass_TableConfig.CONFIG); - tableConfigs.add(com.j256.ormlite.android.processor.inputs.InnerClassTable_OtherInnerClass_TableConfig.CONFIG); + tableConfigs.add(InnerClassTable_InnerClass_TableConfig.createConfig()); + tableConfigs.add(InnerClassTable_OtherInnerClass_TableConfig + .createConfig()); DaoManager.addCachedDatabaseConfigs(tableConfigs); } - public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.InnerClassTable.InnerClass.class); - TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.InnerClassTable.OtherInnerClass.class); + public static void createTables(ConnectionSource connectionSource) + throws SQLException { + TableUtils.createTable(connectionSource, + InnerClassTable.InnerClass.class); + TableUtils.createTable(connectionSource, + InnerClassTable.OtherInnerClass.class); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java b/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java index 9cd8cd4c..da900b17 100644 --- a/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java +++ b/src/test/resources/outputs/InnerClassTable_OtherInnerClass_TableConfig.java @@ -1,23 +1,20 @@ package com.j256.ormlite.android.processor.inputs; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import java.util.ArrayList; +import java.util.List; public final class InnerClassTable_OtherInnerClass_TableConfig { private InnerClassTable_OtherInnerClass_TableConfig() { } - public static final DatabaseTableConfig CONFIG; - - static { + public static DatabaseTableConfig createConfig() { List databaseFieldConfigs = new ArrayList(); - { - DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); - databaseFieldConfigs.add(databaseFieldConfig); - } - CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.InnerClassTable.OtherInnerClass.class, "otherinnerclass", databaseFieldConfigs); + DatabaseFieldConfig fieldFieldConfig = new DatabaseFieldConfig("field"); + databaseFieldConfigs.add(fieldFieldConfig); + return new DatabaseTableConfig( + InnerClassTable.OtherInnerClass.class, "otherinnerclass", + databaseFieldConfigs); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java index 4f8bdc81..399d4612 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig.java @@ -1,13 +1,12 @@ package com.j256.ormlite.android.processor.inputs; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTableConfig; import com.j256.ormlite.table.TableUtils; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; public final class NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig { private NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig() { @@ -15,11 +14,14 @@ private NamedTableWithSpecifiedDatabaseField_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField_TableConfig.CONFIG); + tableConfigs.add(NamedTableWithSpecifiedDatabaseField_TableConfig + .createConfig()); DaoManager.addCachedDatabaseConfigs(tableConfigs); } - public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField.class); + public static void createTables(ConnectionSource connectionSource) + throws SQLException { + TableUtils.createTable(connectionSource, + NamedTableWithSpecifiedDatabaseField.class); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java index ad6bd949..95f86bec 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedDatabaseField_TableConfig.java @@ -1,51 +1,51 @@ package com.j256.ormlite.android.processor.inputs; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import java.util.ArrayList; +import java.util.List; public final class NamedTableWithSpecifiedDatabaseField_TableConfig { private NamedTableWithSpecifiedDatabaseField_TableConfig() { } - public static final DatabaseTableConfig CONFIG; - - static { + public static DatabaseTableConfig createConfig() { List databaseFieldConfigs = new ArrayList(); - { - DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); - databaseFieldConfig.setColumnName("column"); - databaseFieldConfig.setDataType(com.j256.ormlite.field.DataType.ENUM_INTEGER); - databaseFieldConfig.setDefaultValue("VALUE"); - databaseFieldConfig.setWidth(100); - databaseFieldConfig.setCanBeNull(false); - databaseFieldConfig.setId(true); - databaseFieldConfig.setGeneratedId(true); - databaseFieldConfig.setGeneratedIdSequence("id_sequence"); - databaseFieldConfig.setForeign(true); - databaseFieldConfig.setUseGetSet(true); - databaseFieldConfig.setUnknownEnumValue(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField.FieldTypeEnum.OTHER_VALUE); - databaseFieldConfig.setThrowIfNull(true); - databaseFieldConfig.setFormat("%f"); - databaseFieldConfig.setUnique(true); - databaseFieldConfig.setUniqueCombo(true); - databaseFieldConfig.setIndex(true); - databaseFieldConfig.setUniqueIndex(true); - databaseFieldConfig.setIndexName("index"); - databaseFieldConfig.setUniqueIndexName("unique_index"); - databaseFieldConfig.setForeignAutoRefresh(true); - databaseFieldConfig.setMaxForeignAutoRefreshLevel(5); - databaseFieldConfig.setPersisterClass(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField.CustomPersister.class); - databaseFieldConfig.setAllowGeneratedIdInsert(true); - databaseFieldConfig.setColumnDefinition("INT NOT NULL"); - databaseFieldConfig.setForeignAutoCreate(true); - databaseFieldConfig.setVersion(true); - databaseFieldConfig.setForeignColumnName("foreign"); - databaseFieldConfig.setReadOnly(true); - databaseFieldConfigs.add(databaseFieldConfig); - } - CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField.class, "table", databaseFieldConfigs); + DatabaseFieldConfig fieldFieldConfig = new DatabaseFieldConfig("field"); + fieldFieldConfig.setColumnName("column"); + fieldFieldConfig + .setDataType(com.j256.ormlite.field.DataType.ENUM_INTEGER); + fieldFieldConfig.setDefaultValue("VALUE"); + fieldFieldConfig.setWidth(100); + fieldFieldConfig.setCanBeNull(false); + fieldFieldConfig.setId(true); + fieldFieldConfig.setGeneratedId(true); + fieldFieldConfig.setGeneratedIdSequence("id_sequence"); + fieldFieldConfig.setForeign(true); + fieldFieldConfig.setUseGetSet(true); + fieldFieldConfig + .setUnknownEnumValue(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedDatabaseField.FieldTypeEnum.OTHER_VALUE); + fieldFieldConfig.setThrowIfNull(true); + fieldFieldConfig.setFormat("%f"); + fieldFieldConfig.setUnique(true); + fieldFieldConfig.setUniqueCombo(true); + fieldFieldConfig.setIndex(true); + fieldFieldConfig.setUniqueIndex(true); + fieldFieldConfig.setIndexName("index"); + fieldFieldConfig.setUniqueIndexName("unique_index"); + fieldFieldConfig.setForeignAutoRefresh(true); + fieldFieldConfig.setMaxForeignAutoRefreshLevel(5); + fieldFieldConfig + .setPersisterClass(NamedTableWithSpecifiedDatabaseField.CustomPersister.class); + fieldFieldConfig.setAllowGeneratedIdInsert(true); + fieldFieldConfig.setColumnDefinition("INT NOT NULL"); + fieldFieldConfig.setForeignAutoCreate(true); + fieldFieldConfig.setVersion(true); + fieldFieldConfig.setForeignColumnName("foreign"); + fieldFieldConfig.setReadOnly(true); + databaseFieldConfigs.add(fieldFieldConfig); + return new DatabaseTableConfig( + NamedTableWithSpecifiedDatabaseField.class, "table", + databaseFieldConfigs); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java index b212df61..2c74f06e 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig.java @@ -1,13 +1,12 @@ package com.j256.ormlite.android.processor.inputs; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTableConfig; import com.j256.ormlite.table.TableUtils; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; public final class NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig { private NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig() { @@ -15,11 +14,15 @@ private NamedTableWithSpecifiedForeignCollectionField_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedForeignCollectionField_TableConfig.CONFIG); + tableConfigs + .add(NamedTableWithSpecifiedForeignCollectionField_TableConfig + .createConfig()); DaoManager.addCachedDatabaseConfigs(tableConfigs); } - public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedForeignCollectionField.class); + public static void createTables(ConnectionSource connectionSource) + throws SQLException { + TableUtils.createTable(connectionSource, + NamedTableWithSpecifiedForeignCollectionField.class); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java index 98ae4a73..d2fc7447 100644 --- a/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java +++ b/src/test/resources/outputs/NamedTableWithSpecifiedForeignCollectionField_TableConfig.java @@ -1,38 +1,37 @@ package com.j256.ormlite.android.processor.inputs; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import java.util.ArrayList; +import java.util.List; public final class NamedTableWithSpecifiedForeignCollectionField_TableConfig { private NamedTableWithSpecifiedForeignCollectionField_TableConfig() { } - public static final DatabaseTableConfig CONFIG; - - static { + public static DatabaseTableConfig createConfig() { List databaseFieldConfigs = new ArrayList(); - { - DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("numbers"); - databaseFieldConfig.setColumnName("column"); - databaseFieldConfig.setForeignCollection(true); - databaseFieldConfig.setForeignCollectionEager(true); - databaseFieldConfig.setForeignCollectionMaxEagerLevel(5); - databaseFieldConfig.setForeignCollectionColumnName("column"); - databaseFieldConfig.setForeignCollectionOrderColumnName("order_column"); - databaseFieldConfig.setForeignCollectionOrderAscending(false); - databaseFieldConfig.setForeignCollectionForeignFieldName("foreign_field"); - databaseFieldConfigs.add(databaseFieldConfig); - } - { - DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("numbers_deprecated"); - databaseFieldConfig.setForeignCollection(true); - databaseFieldConfig.setForeignCollectionMaxEagerLevel(5); - databaseFieldConfig.setForeignCollectionForeignFieldName("foreign_field"); - databaseFieldConfigs.add(databaseFieldConfig); - } - CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.NamedTableWithSpecifiedForeignCollectionField.class, "table", databaseFieldConfigs); + DatabaseFieldConfig numbersFieldConfig = new DatabaseFieldConfig( + "numbers"); + numbersFieldConfig.setColumnName("column"); + numbersFieldConfig.setForeignCollection(true); + numbersFieldConfig.setForeignCollectionEager(true); + numbersFieldConfig.setForeignCollectionMaxEagerLevel(5); + numbersFieldConfig.setForeignCollectionColumnName("column"); + numbersFieldConfig.setForeignCollectionOrderColumnName("order_column"); + numbersFieldConfig.setForeignCollectionOrderAscending(false); + numbersFieldConfig + .setForeignCollectionForeignFieldName("foreign_field"); + databaseFieldConfigs.add(numbersFieldConfig); + DatabaseFieldConfig numbers_deprecatedFieldConfig = new DatabaseFieldConfig( + "numbers_deprecated"); + numbers_deprecatedFieldConfig.setForeignCollection(true); + numbers_deprecatedFieldConfig.setForeignCollectionMaxEagerLevel(5); + numbers_deprecatedFieldConfig + .setForeignCollectionForeignFieldName("foreign_field"); + databaseFieldConfigs.add(numbers_deprecatedFieldConfig); + return new DatabaseTableConfig( + NamedTableWithSpecifiedForeignCollectionField.class, "table", + databaseFieldConfigs); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java index 9a761da0..c847816d 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig.java @@ -1,13 +1,12 @@ package com.j256.ormlite.android.processor.inputs; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTableConfig; import com.j256.ormlite.table.TableUtils; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; public final class UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig { private UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig() { @@ -15,11 +14,14 @@ private UnnamedTableWithDefaultDatabaseField_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultDatabaseField_TableConfig.CONFIG); + tableConfigs.add(UnnamedTableWithDefaultDatabaseField_TableConfig + .createConfig()); DaoManager.addCachedDatabaseConfigs(tableConfigs); } - public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultDatabaseField.class); + public static void createTables(ConnectionSource connectionSource) + throws SQLException { + TableUtils.createTable(connectionSource, + UnnamedTableWithDefaultDatabaseField.class); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java index 5fe2b629..fa5836f4 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultDatabaseField_TableConfig.java @@ -1,23 +1,20 @@ package com.j256.ormlite.android.processor.inputs; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import java.util.ArrayList; +import java.util.List; public final class UnnamedTableWithDefaultDatabaseField_TableConfig { private UnnamedTableWithDefaultDatabaseField_TableConfig() { } - public static final DatabaseTableConfig CONFIG; - - static { + public static DatabaseTableConfig createConfig() { List databaseFieldConfigs = new ArrayList(); - { - DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("field"); - databaseFieldConfigs.add(databaseFieldConfig); - } - CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultDatabaseField.class, "unnamedtablewithdefaultdatabasefield", databaseFieldConfigs); + DatabaseFieldConfig fieldFieldConfig = new DatabaseFieldConfig("field"); + databaseFieldConfigs.add(fieldFieldConfig); + return new DatabaseTableConfig( + UnnamedTableWithDefaultDatabaseField.class, + "unnamedtablewithdefaultdatabasefield", databaseFieldConfigs); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java index fd6443c4..c0a61c6a 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig.java @@ -1,13 +1,12 @@ package com.j256.ormlite.android.processor.inputs; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.DatabaseTableConfig; import com.j256.ormlite.table.TableUtils; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; public final class UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig { private UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig() { @@ -15,11 +14,15 @@ private UnnamedTableWithDefaultForeignCollectionField_OpenHelper_TableConfig() { public static void cacheTableConfigurations() { List> tableConfigs = new ArrayList>(); - tableConfigs.add(com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultForeignCollectionField_TableConfig.CONFIG); + tableConfigs + .add(UnnamedTableWithDefaultForeignCollectionField_TableConfig + .createConfig()); DaoManager.addCachedDatabaseConfigs(tableConfigs); } - public static void createTables(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTable(connectionSource, com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultForeignCollectionField.class); + public static void createTables(ConnectionSource connectionSource) + throws SQLException { + TableUtils.createTable(connectionSource, + UnnamedTableWithDefaultForeignCollectionField.class); } -} +} \ No newline at end of file diff --git a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java index ca3244de..c58675df 100644 --- a/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java +++ b/src/test/resources/outputs/UnnamedTableWithDefaultForeignCollectionField_TableConfig.java @@ -1,24 +1,23 @@ package com.j256.ormlite.android.processor.inputs; -import java.util.ArrayList; -import java.util.List; - import com.j256.ormlite.field.DatabaseFieldConfig; import com.j256.ormlite.table.DatabaseTableConfig; +import java.util.ArrayList; +import java.util.List; public final class UnnamedTableWithDefaultForeignCollectionField_TableConfig { private UnnamedTableWithDefaultForeignCollectionField_TableConfig() { } - public static final DatabaseTableConfig CONFIG; - - static { + public static DatabaseTableConfig createConfig() { List databaseFieldConfigs = new ArrayList(); - { - DatabaseFieldConfig databaseFieldConfig = new DatabaseFieldConfig("numbers"); - databaseFieldConfig.setForeignCollection(true); - databaseFieldConfigs.add(databaseFieldConfig); - } - CONFIG = new DatabaseTableConfig(com.j256.ormlite.android.processor.inputs.UnnamedTableWithDefaultForeignCollectionField.class, "unnamedtablewithdefaultforeigncollectionfield", databaseFieldConfigs); + DatabaseFieldConfig numbersFieldConfig = new DatabaseFieldConfig( + "numbers"); + numbersFieldConfig.setForeignCollection(true); + databaseFieldConfigs.add(numbersFieldConfig); + return new DatabaseTableConfig( + UnnamedTableWithDefaultForeignCollectionField.class, + "unnamedtablewithdefaultforeigncollectionfield", + databaseFieldConfigs); } -} +} \ No newline at end of file