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.51.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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends DataPersister> persisterClassDefault = (Class extends DataPersister>) 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 extends TypeElement> 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 extends DataPersister> persisterClassDefault = (Class extends DataPersister>) 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.51.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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> elements,
createSourceFile(table);
}
+ Set extends Element> 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 extends TypeElement> 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 extends Element> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> elements,
DatabaseTable.class.getSimpleName()), element);
}
- createSourceFile(table, element);
+ createTableConfigSourceFile(table, element);
}
Set extends Element> tablesCollectionElements = env
@@ -266,8 +282,7 @@ public boolean process(Set extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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 extends TypeElement> 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;
+ * }
+ * }
+ *