Browse Source

Add support for runtime Mode in the DataTypeAdapters

tags/v1.5.0
James Moger 9 years ago
parent
commit
c1d81bcdfc

+ 1
- 0
releases.moxie View File

@@ -14,6 +14,7 @@ r23: {
- Improved automatic date conversions
- Revised data type adapters to be specified separately with the @TypeAdapter annotation
additions:
- Add runtime mode support (DEV, TEST, & PROD)
- Add a DAO feature similar to JDBI
- Added Gson, XStream, and SnakeYaml type adapters
dependencyChanges: ~

+ 54
- 7
src/main/java/com/iciql/Db.java View File

@@ -41,6 +41,7 @@ import com.iciql.DbUpgrader.DefaultDbUpgrader;
import com.iciql.Iciql.IQTable;
import com.iciql.Iciql.IQVersion;
import com.iciql.Iciql.IQView;
import com.iciql.Iciql.Mode;
import com.iciql.util.IciqlLogger;
import com.iciql.util.JdbcUtils;
import com.iciql.util.StringUtils;
@@ -64,6 +65,7 @@ public class Db implements AutoCloseable {
private static final Map<String, Class<? extends SQLDialect>> DIALECTS;

private final Connection conn;
private final Mode mode;
private final Map<Class<?>, TableDefinition<?>> classMap = Collections
.synchronizedMap(new HashMap<Class<?>, TableDefinition<?>>());
private final SQLDialect dialect;
@@ -88,8 +90,9 @@ public class Db implements AutoCloseable {
DIALECTS.put("SQLite", SQLDialectSQLite.class);
}

private Db(Connection conn) {
private Db(Connection conn, Mode mode) {
this.conn = conn;
this.mode = mode;
String databaseName = null;
try {
DatabaseMetaData data = conn.getMetaData();
@@ -148,50 +151,81 @@ public class Db implements AutoCloseable {
}

public static Db open(String url) {
return open(url, Mode.PROD);
}

public static Db open(String url, Mode mode) {
try {
Connection conn = JdbcUtils.getConnection(null, url, null, null);
return new Db(conn);
return new Db(conn, mode);
} catch (SQLException e) {
throw new IciqlException(e);
}
}

public static Db open(String url, String user, String password) {
return open(url, user, password, Mode.PROD);
}

public static Db open(String url, String user, String password, Mode mode) {
try {
Connection conn = JdbcUtils.getConnection(null, url, user, password);
return new Db(conn);
return new Db(conn, mode);
} catch (SQLException e) {
throw new IciqlException(e);
}
}

public static Db open(String url, String user, char[] password) {
return open(url, user, password, Mode.PROD);
}

public static Db open(String url, String user, char[] password, Mode mode) {
try {
Connection conn = JdbcUtils.getConnection(null, url, user, password == null ? null : new String(password));
return new Db(conn);
return new Db(conn, mode);
} catch (SQLException e) {
throw new IciqlException(e);
}
}

public static Db open(DataSource ds) {
return open(ds, Mode.PROD);
}

/**
* Create a new database instance using a data source. This method is fast,
* so that you can always call open() / close() on usage.
*
* @param ds
* the data source
* @param mode
* the runtime mode
* @return the database instance.
*/
public static Db open(DataSource ds) {
public static Db open(DataSource ds, Mode mode) {
try {
return new Db(ds.getConnection());
return new Db(ds.getConnection(), mode);
} catch (SQLException e) {
throw new IciqlException(e);
}
}

public static Db open(Connection conn) {
return new Db(conn);
return open(conn, Mode.PROD);
}

public static Db open(Connection conn, Mode mode) {
return new Db(conn, mode);
}

/**
* Returns the Iciql runtime mode.
*
* @return the runtime mode
*/
public Mode getMode() {
return mode;
}

/**
@@ -806,4 +840,17 @@ public class Db implements AutoCloseable {
return this.autoSavePoint;
}

/**
*
* @author James Moger
*
*/
class NoExternalDaoStatements implements DaoStatementProvider {

@Override
public String getStatement(String idOrStatement) {
return idOrStatement;
}

}
}

+ 31
- 0
src/main/java/com/iciql/Iciql.java View File

@@ -726,6 +726,25 @@ public interface Iciql {
public @interface IQIgnore{
}
/**
* The runtime mode for Iciql.
*/
public static enum Mode {
DEV, TEST, PROD;
public static Mode fromValue(String value) {
for (Mode mode : values()) {
if (mode.name().equalsIgnoreCase(value)) {
return mode;
}
}
return PROD;
}
}
/**
* This method is called to let the table define the primary key, indexes,
* and the table name.
@@ -767,6 +786,18 @@ public interface Iciql {
*/
Class<T> getJavaType();
/**
* Set the runtime mode.
* <p>
* Allows type adapters to adapt type mappings based on the runtime
* mode.
* </p>
*
* @param mode
*/
void setMode(Mode mode);
/**
* Serializes your Java object into a JDBC object.
*

+ 17
- 12
src/main/java/com/iciql/SQLDialectDefault.java View File

@@ -29,6 +29,7 @@ import java.util.concurrent.ConcurrentHashMap;
import com.iciql.Iciql.ConstraintDeleteType;
import com.iciql.Iciql.ConstraintUpdateType;
import com.iciql.Iciql.DataTypeAdapter;
import com.iciql.Iciql.Mode;
import com.iciql.TableDefinition.ConstraintForeignKeyDefinition;
import com.iciql.TableDefinition.ConstraintUniqueDefinition;
import com.iciql.TableDefinition.FieldDefinition;
@@ -50,6 +51,7 @@ public class SQLDialectDefault implements SQLDialect {
int databaseMinorVersion;
String databaseName;
String productVersion;
Mode mode;
Map<Class<? extends DataTypeAdapter<?>>, DataTypeAdapter<?>> typeAdapters;

public SQLDialectDefault() {
@@ -76,6 +78,8 @@ public class SQLDialectDefault implements SQLDialect {
} catch (SQLException e) {
throw new IciqlException(e, "failed to retrieve database metadata!");
}

mode = db.getMode();
}

@Override
@@ -446,12 +450,13 @@ public class SQLDialectDefault implements SQLDialect {

@Override
public DataTypeAdapter<?> getAdapter(Class<? extends DataTypeAdapter<?>> typeAdapter) {
DataTypeAdapter<?> dtt = typeAdapters.get(typeAdapter);
if (dtt == null) {
dtt = Utils.newObject(typeAdapter);
typeAdapters.put(typeAdapter, dtt);
DataTypeAdapter<?> dta = typeAdapters.get(typeAdapter);
if (dta == null) {
dta = Utils.newObject(typeAdapter);
typeAdapters.put(typeAdapter, dta);
}
return dtt;
dta.setMode(mode);
return dta;
}

@SuppressWarnings("unchecked")
@@ -462,19 +467,19 @@ public class SQLDialectDefault implements SQLDialect {
return value;
}

DataTypeAdapter<T> dtt = (DataTypeAdapter<T>) getAdapter(typeAdapter);
return dtt.serialize(value);
DataTypeAdapter<T> dta = (DataTypeAdapter<T>) getAdapter(typeAdapter);
return dta.serialize(value);
}

@Override
public Object deserialize(Object value, Class<? extends DataTypeAdapter<?>> typeAdapter) {
DataTypeAdapter<?> dtt = typeAdapters.get(typeAdapter);
if (dtt == null) {
dtt = Utils.newObject(typeAdapter);
typeAdapters.put(typeAdapter, dtt);
if (typeAdapter == null) {
// pass-through
return value;
}

return dtt.deserialize(value);
DataTypeAdapter<?> dta = getAdapter(typeAdapter);
return dta.deserialize(value);
}

@Override

+ 8
- 0
src/main/java/com/iciql/adapter/GsonTypeAdapter.java View File

@@ -18,6 +18,7 @@ package com.iciql.adapter;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.iciql.Iciql.DataTypeAdapter;
import com.iciql.Iciql.Mode;

/**
* Base class for inserting/retrieving a Java Object (de)serialized as JSON
@@ -39,10 +40,17 @@ import com.iciql.Iciql.DataTypeAdapter;
*/
public abstract class GsonTypeAdapter<T> implements DataTypeAdapter<T> {

protected Mode mode;

protected Gson gson() {
return new GsonBuilder().create();
}

@Override
public void setMode(Mode mode) {
this.mode = mode;
}

@Override
public String getDataType() {
return "TEXT";

+ 9
- 2
src/main/java/com/iciql/adapter/JavaSerializationTypeAdapter.java View File

@@ -25,9 +25,9 @@ import java.io.ObjectOutputStream;
import java.sql.Blob;
import java.sql.SQLException;

import com.iciql.Iciql;
import com.iciql.IciqlException;
import com.iciql.Iciql.DataTypeAdapter;
import com.iciql.Iciql.Mode;
import com.iciql.IciqlException;

/**
* Base class for inserting/retrieving a Java Object as a BLOB field using Java Serialization.
@@ -44,6 +44,13 @@ import com.iciql.Iciql.DataTypeAdapter;
*/
public abstract class JavaSerializationTypeAdapter<T> implements DataTypeAdapter<T> {

protected Mode mode;

@Override
public void setMode(Mode mode) {
this.mode = mode;
}

@Override
public final String getDataType() {
return "BLOB";

+ 8
- 0
src/main/java/com/iciql/adapter/SnakeYamlTypeAdapter.java View File

@@ -21,16 +21,24 @@ import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;

import com.iciql.Iciql.DataTypeAdapter;
import com.iciql.Iciql.Mode;

/**
* Base class for inserting/retrieving a Java Object (de)serialized as YAML using SnakeYaml.
*/
public abstract class SnakeYamlTypeAdapter<T> implements DataTypeAdapter<T> {

protected Mode mode;

protected Yaml yaml() {
return new Yaml();
}

@Override
public void setMode(Mode mode) {
this.mode = mode;
}

@Override
public String getDataType() {
return "TEXT";

+ 8
- 0
src/main/java/com/iciql/adapter/XStreamTypeAdapter.java View File

@@ -17,6 +17,7 @@
package com.iciql.adapter;

import com.iciql.Iciql.DataTypeAdapter;
import com.iciql.Iciql.Mode;
import com.thoughtworks.xstream.XStream;

/**
@@ -24,10 +25,17 @@ import com.thoughtworks.xstream.XStream;
*/
public class XStreamTypeAdapter implements DataTypeAdapter<Object> {

protected Mode mode;

protected XStream xstream() {
return new XStream();
}

@Override
public void setMode(Mode mode) {
this.mode = mode;
}

@Override
public String getDataType() {
return "TEXT";

+ 8
- 0
src/main/java/com/iciql/adapter/postgresql/JsonStringAdapter.java View File

@@ -20,12 +20,20 @@ import java.sql.SQLException;
import org.postgresql.util.PGobject;

import com.iciql.Iciql.DataTypeAdapter;
import com.iciql.Iciql.Mode;

/**
* Handles transforming raw strings to/from the Postgres JSON data type.
*/
public class JsonStringAdapter implements DataTypeAdapter<String> {

protected Mode mode;

@Override
public void setMode(Mode mode) {
this.mode = mode;
}

@Override
public String getDataType() {
return "json";

+ 8
- 0
src/main/java/com/iciql/adapter/postgresql/JsonbStringAdapter.java View File

@@ -20,12 +20,20 @@ import java.sql.SQLException;
import org.postgresql.util.PGobject;

import com.iciql.Iciql.DataTypeAdapter;
import com.iciql.Iciql.Mode;

/**
* Handles transforming raw strings to/from the Postgres JSONB data type.
*/
public class JsonbStringAdapter implements DataTypeAdapter<String> {

protected Mode mode;

@Override
public void setMode(Mode mode) {
this.mode = mode;
}

@Override
public String getDataType() {
return "jsonb";

+ 8
- 0
src/main/java/com/iciql/adapter/postgresql/XmlStringAdapter.java View File

@@ -20,12 +20,20 @@ import java.sql.SQLException;
import org.postgresql.util.PGobject;

import com.iciql.Iciql.DataTypeAdapter;
import com.iciql.Iciql.Mode;

/**
* Handles transforming raw strings to/from the Postgres XML data type.
*/
public class XmlStringAdapter implements DataTypeAdapter<String> {

protected Mode mode;

@Override
public void setMode(Mode mode) {
this.mode = mode;
}

@Override
public String getDataType() {
return "xml";

+ 11
- 0
src/site/dta.mkd View File

@@ -35,6 +35,13 @@ Let's take a look at *InvoiceAdapterImpl*.
---JAVA---
public class InvoiceAdapterImpl implements DataTypeAdapter<Invoice> {
Mode mode;
@Override
public void setMode(Mode mode) {
this.mode = mode;
}
@Override
public String getDataType() {
return "jsonb";
@@ -76,6 +83,10 @@ public class InvoiceAdapterImpl implements DataTypeAdapter<Invoice> {
Here you can see how the *InvoiceTypeAdapter* defines a [Postgres JSONB data type](http://www.postgresql.org/docs/9.4/static/datatype-json.html) and automatically handles JSON (de)serialization with [Google Gson](https://code.google.com/p/google-gson) so that the database gets the content in a form that it requires but we can continue to work with objects in Java.
### Runtime Mode
Data type adapters can respond to the Iciql runtime mode (`DEV`, `TEST`, or `PROD`) allowing them to change their behavior. This is useful for targetting a data type that might be available in your production database but may not be available in your development or testing database.
### Custom annotations
It is a little verbose to repeat `@TypeAdapter(InvoiceAdapterImpl.class)` everywhere you want to use your adapter.

Loading…
Cancel
Save