diff --git a/pom.xml b/pom.xml index cc87439f7..862022012 100644 --- a/pom.xml +++ b/pom.xml @@ -182,7 +182,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.2 1.6 1.6 diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index 64bdcbed2..e730a4b35 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -457,6 +457,30 @@ public interface EbeanServer { * Execute the query visiting the results. This is similar to findIterate in * that not all the result beans need to be held in memory at the same time * and as such is go for processing large queries. + * + * @see Query#findEach(QueryEachConsumer) + */ + public void findEach(Query query, QueryEachConsumer consumer, Transaction transaction); + + /** + * Execute the query visiting the results. This is similar to findIterate in + * that not all the result beans need to be held in memory at the same time + * and as such is go for processing large queries. + * + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + public void findEachWhile(Query query, QueryEachWhileConsumer consumer, Transaction transaction); + + /** + * Deprecated in favor of #findEachWhile which is functionally exactly the same + * but has a much better name. + *

+ * Execute the query visiting the results. This is similar to findIterate in + * that not all the result beans need to be held in memory at the same time + * and as such is go for processing large queries. + *

+ * + * @deprecated */ public void findVisit(Query query, QueryResultVisitor visitor, Transaction transaction); diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index dee737d88..b991e3553 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -102,9 +102,25 @@ public interface ExpressionList extends Serializable { public QueryIterator findIterate(); /** - * Execute the query visiting the results. - * - * @see Query#findVisit(QueryResultVisitor) + * Execute the query process the beans one at a time. + * + * @see Query#findEach(QueryEachConsumer) + */ + public void findEach(QueryEachConsumer consumer); + + /** + * Execute the query processing the beans one at a time with the ability to + * stop processing before reading all the beans. + * + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + public void findEachWhile(QueryEachWhileConsumer consumer); + + /** + * Deprecated in favor of #findEachWhile which is functionally exactly the same + * but has a much better name. + * + * @deprecated */ public void findVisit(QueryResultVisitor visitor); diff --git a/src/main/java/com/avaje/ebean/Model.java b/src/main/java/com/avaje/ebean/Model.java index d57311474..0dfc9d44f 100644 --- a/src/main/java/com/avaje/ebean/Model.java +++ b/src/main/java/com/avaje/ebean/Model.java @@ -328,6 +328,37 @@ public abstract class Model { return query().findIds(); } + /** + * Execute the query consuming each bean one at a time. + *

+ * This is generally used to process large queries where unlike findList + * you do not want to hold all the results in memory at once but instead + * process them one at a time (requiring far less memory). + *

+ * Equivalent to {@link Query#findEach(QueryEachConsumer)} + */ + public void findEach(QueryEachConsumer consumer) { + query().findEach(consumer); + } + + /** + * Execute the query consuming each bean one at a time. + *

+ * This is similar to #findEach except that you return boolean + * true to continue processing beans and return false to stop + * processing early. + *

+ *

+ * This is generally used to process large queries where unlike findList + * you do not want to hold all the results in memory at once but instead + * process them one at a time (requiring far less memory). + *

+ * Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)} + */ + public void findEachWhile(QueryEachWhileConsumer consumer) { + query().findEachWhile(consumer); + } + /** * Retrieves all entities of the given type. *

diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 8110ac2cc..96fb71093 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -446,37 +446,89 @@ public interface Query extends Serializable { */ public QueryIterator findIterate(); + /** + * This is deprecated in favor of #findEachWhile. + *

+ * This is functionally exactly the same as #findEachWhile. It is + * replaced by findEachWhile because the method name is much better. + *

+ * + * @param visitor + * the visitor used to process the queried beans. + * + * @deprecated + */ + public void findVisit(QueryResultVisitor visitor); + + /** + * Execute the query processing the beans one at a time. + *

+ * This method is appropriate to process very large query results as the + * beans are consumed one at a time and do not need to be held in memory + * (unlike #findList #findSet etc) + *

+ *

+ * Compared with #findEachWhile this will always process all the beans where as + * #findEachWhile provides a way to stop processing the query result early before + * all the beans have been read. + *

+ *

+ * This method is functionally equivalent to findIterate() but instead of using an + * iterator uses the QueryEachConsumer (SAM) interface which is better suited to use + * with Java8 closures. + *

+ * + *
+   *
+   * Query<Customer> query = server.find(Customer.class)
+   *     .where().gt("id", 0)
+   *     .orderBy("id")
+   *     .setMaxRows(2);
+   *
+   * query.findVisit((Customer customer) -> {
+   *
+   *     // do something with customer
+   *     System.out.println("-- visit " + customer);
+   * });
+   * 
+ * + * @param consumer + * the consumer used to process the queried beans. + */ + public void findEach(QueryEachConsumer consumer); + /** * Execute the query using callbacks to a visitor to process the resulting * beans one at a time. *

- * Similar to findIterate() this query method does not require all the result - * beans to be all held in memory at once and as such is useful for processing - * large queries. + * This method is functionally equivalent to findIterate() but instead of using an + * iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use + * with Java8 closures. *

- * + + * *
-   * 
+   *
    * Query<Customer> query = server.find(Customer.class)
    *     .fetch("contacts", new FetchConfig().query(2))
    *     .where().gt("id", 0)
    *     .orderBy("id")
    *     .setMaxRows(2);
-   * 
-   * query.findVisit(new QueryResultVisitor<Customer>() {
-   * 
-   *   public boolean accept(Customer customer) {
+   *
+   * query.findEachWhile((Customer customer) -> {
+   *
    *     // do something with customer
    *     System.out.println("-- visit " + customer);
-   *     return true;
-   *   }
+   *
+   *     // return true to continue processing or false to stop
+   *     return (customer.getId() < 40);
    * });
    * 
- * - * @param visitor - * the visitor used to process the queried beans. + * + * @param consumer + * the consumer used to process the queried beans. */ - public void findVisit(QueryResultVisitor visitor); + public void findEachWhile(QueryEachWhileConsumer consumer); /** * Execute the query returning the list of objects. diff --git a/src/main/java/com/avaje/ebean/QueryEachConsumer.java b/src/main/java/com/avaje/ebean/QueryEachConsumer.java new file mode 100644 index 000000000..7e9761426 --- /dev/null +++ b/src/main/java/com/avaje/ebean/QueryEachConsumer.java @@ -0,0 +1,41 @@ +package com.avaje.ebean; + +/** + * Used to process a query result one bean at a time via a callback to this + * visitor. + *

+ * If you wish to stop further processing return false from the accept method. + *

+ *

+ * Unlike findList() and findSet() using a QueryResultVisitor does not require + * all the beans in the query result to be held in memory at once. This makes + * QueryResultVisitor useful for processing large queries. + *

+ * + *
+ *
+ * Query<Customer> query = server.find(Customer.class)
+ *     .where().gt("id", 0)
+ *     .orderBy("id")
+ *     .setMaxRows(2);
+ *
+ * query.findVisit((Customer customer) -> {
+ *
+ *     // do something with customer
+ *     System.out.println("-- visit " + customer);
+ * });
+ * 
+ * + * @param + * the type of entity bean being queried. + */ +public interface QueryEachConsumer { + + /** + * Process the bean. + * + * @param bean + * the entity bean to process + */ + public void accept(T bean); +} diff --git a/src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java b/src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java new file mode 100644 index 000000000..1b503099c --- /dev/null +++ b/src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java @@ -0,0 +1,45 @@ +package com.avaje.ebean; + +/** + * Used to process a query result one bean at a time via a callback to this + * visitor. + *

+ * If you wish to stop further processing return false from the accept method. + *

+ *

+ * Unlike findList() and findSet() using a QueryResultVisitor does not require + * all the beans in the query result to be held in memory at once. This makes + * QueryResultVisitor useful for processing large queries. + *

+ *

+ *

+ *
+ * Query<Customer> query = server.find(Customer.class)
+ *     .fetch("contacts", new FetchConfig().query(2))
+ *     .where().gt("id", 0)
+ *     .orderBy("id")
+ *     .setMaxRows(2);
+ *
+ * query.findEachWhile((Customer customer) -> {
+ *
+ *     // do something with customer
+ *     System.out.println("-- visit " + customer);
+ *
+ *     // return true to continue processing or false to stop
+ *     return (customer.getId() < 40);
+ * });
+ * 
+ * + * @param the type of entity bean being queried. + */ +public interface QueryEachWhileConsumer { + + /** + * Process the bean and return true if you want to continue processing more + * beans. Return false if you want to stop processing further. + * + * @param bean the entity bean to process + * @return true to continue processing more beans or false to stop. + */ + public boolean accept(T bean); +} diff --git a/src/main/java/com/avaje/ebean/config/JsonConfig.java b/src/main/java/com/avaje/ebean/config/JsonConfig.java new file mode 100644 index 000000000..a813be3fe --- /dev/null +++ b/src/main/java/com/avaje/ebean/config/JsonConfig.java @@ -0,0 +1,29 @@ +package com.avaje.ebean.config; + +/** + * Configuration for JSON features. + */ +public abstract class JsonConfig { + + /** + * Defined the format used for DateTime types. + */ + public enum DateTime { + + /** + * Format as epoch millis. + */ + MILLIS, + + /** + * Format as epoch with nanos. + */ + NANOS, + + /** + * Format as ISO-8601 date format. + */ + ISO8601 + } + +} diff --git a/src/main/java/com/avaje/ebean/config/ServerConfig.java b/src/main/java/com/avaje/ebean/config/ServerConfig.java index 5618389c3..88a45be1e 100644 --- a/src/main/java/com/avaje/ebean/config/ServerConfig.java +++ b/src/main/java/com/avaje/ebean/config/ServerConfig.java @@ -121,6 +121,11 @@ public class ServerConfig { */ private AutofetchConfig autofetchConfig = new AutofetchConfig(); + /** + * The JSON format used for DateTime types. Default to millis. + */ + private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.MILLIS; + /** * The database platform name. Used to imply a DatabasePlatform to use. */ @@ -217,7 +222,7 @@ public class ServerConfig { * Setting to indicate if UUID should be stored as binary(16) or varchar(40). */ private boolean uuidStoreAsBinary; - + private List persistControllers = new ArrayList(); private List> persistListeners = new ArrayList>(); @@ -241,9 +246,13 @@ public class ServerConfig { private boolean collectQueryStatsByNode; private boolean collectQueryOrigins; - + private JsonFactory jsonFactory; + private boolean localTimeWithNanos; + + private boolean durationWithNanos; + /** * Construct a Server Configuration for programmatically creating an * EbeanServer. @@ -270,6 +279,20 @@ public class ServerConfig { this.jsonFactory = jsonFactory; } + /** + * Return the JSON format used for DateTime types. + */ + public JsonConfig.DateTime getJsonDateTime() { + return jsonDateTime; + } + + /** + * Set the JSON format to use for DateTime types. + */ + public void setJsonDateTime(JsonConfig.DateTime jsonDateTime) { + this.jsonDateTime = jsonDateTime; + } + /** * Return the name of the EbeanServer. */ @@ -859,6 +882,43 @@ public class ServerConfig { this.uuidStoreAsBinary = uuidStoreAsBinary; } + /** + * Return true if LocalTime should be persisted with nanos precision. + */ + public boolean isLocalTimeWithNanos() { + return localTimeWithNanos; + } + + /** + * Set to true if LocalTime should be persisted with nanos precision. + *

+ * Otherwise it is persisted using java.sql.Time which is seconds precision. + *

+ */ + public void setLocalTimeWithNanos(boolean localTimeWithNanos) { + this.localTimeWithNanos = localTimeWithNanos; + } + + /** + * Return true if Duration should be persisted with nanos precision (SQL DECIMAL). + *

+ * Otherwise it is persisted with second precision (SQL INTEGER). + *

+ */ + public boolean isDurationWithNanos() { + return durationWithNanos; + } + + /** + * Set to true if Duration should be persisted with nanos precision (SQL DECIMAL). + *

+ * Otherwise it is persisted with second precision (SQL INTEGER). + *

+ */ + public void setDurationWithNanos(boolean durationWithNanos) { + this.durationWithNanos = durationWithNanos; + } + /** * Set to true to run the DDL generation on startup. */ @@ -1364,10 +1424,18 @@ public class ServerConfig { databaseBooleanFalse = p.get("databaseBooleanFalse", null); databasePlatformName = p.get("databasePlatformName", null); uuidStoreAsBinary = p.getBoolean("uuidStoreAsBinary", false); + localTimeWithNanos = p.getBoolean("localTimeWithNanos", false); lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", 1); queryBatchSize = p.getInt("queryBatchSize", DEFAULT_QUERY_BATCH_SIZE); + String jsonDateTimeFormat = p.get("jsonDateTime", null); + if (jsonDateTimeFormat != null) { + jsonDateTime = JsonConfig.DateTime.valueOf(jsonDateTimeFormat); + } else { + jsonDateTime = JsonConfig.DateTime.MILLIS; + } + ddlGenerate = p.getBoolean("ddl.generate", false); ddlRun = p.getBoolean("ddl.run", false); diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index b3810aaa5..03172c75d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -17,36 +17,10 @@ import javax.management.MBeanServer; import javax.management.ObjectName; import javax.persistence.PersistenceException; +import com.avaje.ebean.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.avaje.ebean.AdminAutofetch; -import com.avaje.ebean.BackgroundExecutor; -import com.avaje.ebean.BeanState; -import com.avaje.ebean.CallableSql; -import com.avaje.ebean.Ebean; -import com.avaje.ebean.ExpressionFactory; -import com.avaje.ebean.Filter; -import com.avaje.ebean.FutureIds; -import com.avaje.ebean.FutureList; -import com.avaje.ebean.FutureRowCount; -import com.avaje.ebean.PagedList; -import com.avaje.ebean.PagingList; -import com.avaje.ebean.Query; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; -import com.avaje.ebean.SqlFutureList; -import com.avaje.ebean.SqlQuery; -import com.avaje.ebean.SqlRow; -import com.avaje.ebean.SqlUpdate; -import com.avaje.ebean.Transaction; -import com.avaje.ebean.TxCallable; -import com.avaje.ebean.TxIsolation; -import com.avaje.ebean.TxRunnable; -import com.avaje.ebean.TxScope; -import com.avaje.ebean.TxType; -import com.avaje.ebean.Update; -import com.avaje.ebean.ValuePair; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.CallStack; import com.avaje.ebean.bean.EntityBean; @@ -273,17 +247,14 @@ public final class DefaultServer implements SpiEbeanServer { List spiPlugins = new ArrayList(); - final Iterator plugins = ServiceLoader.load(SpiEbeanPlugin.class).iterator(); - - while (plugins.hasNext()) { - SpiEbeanPlugin plugin = plugins.next(); + for (SpiEbeanPlugin plugin : ServiceLoader.load(SpiEbeanPlugin.class)) { spiPlugins.add(plugin); plugin.setup(this, this.getDatabasePlatform(), config.getServerConfig()); if (plugin instanceof DdlGenerator) { // backwards compatible - ddlGenerator = (DdlGenerator)plugin; - } + ddlGenerator = (DdlGenerator) plugin; + } } if (ddlGenerator == null) { @@ -1413,12 +1384,27 @@ public final class DefaultServer implements SpiEbeanServer { SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); - try { - request.initTransIfRequired(); - request.findVisit(visitor); - } finally { - // do nothing - findVisit garuntee's cleanup of the transaction if required - } + request.initTransIfRequired(); + request.findVisit(visitor); + // no try finally - findVisit guarantee's cleanup of the transaction if required + } + + public void findEach(Query query, QueryEachConsumer consumer, Transaction t) { + + SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + + request.initTransIfRequired(); + request.findEach(consumer); + // no try finally - findVisit guarantee's cleanup of the transaction if required + } + + public void findEachWhile(Query query, QueryEachWhileConsumer consumer, Transaction t) { + + SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + + request.initTransIfRequired(); + request.findEachWhile(consumer); + // no try finally - findVisit guarantee's cleanup of the transaction if required } public QueryIterator findIterate(Query query, Transaction t) { @@ -1542,7 +1528,7 @@ public final class DefaultServer implements SpiEbeanServer { @Override public void markAsDirty(Object bean) { - if (bean instanceof EntityBean == false) { + if (!(bean instanceof EntityBean)) { throw new IllegalArgumentException("This bean is not an EntityBean?"); } // mark the bean as dirty (so that an update will not get skipped) @@ -1650,7 +1636,7 @@ public final class DefaultServer implements SpiEbeanServer { if (bean == null) { throw new IllegalArgumentException(Message.msg("bean.isnull")); } - if (bean instanceof EntityBean == false) { + if (!(bean instanceof EntityBean)) { throw new IllegalArgumentException("Was expecting an EntityBean but got a "+bean.getClass()); } return (EntityBean)bean; @@ -1959,10 +1945,7 @@ public final class DefaultServer implements SpiEbeanServer { public boolean isSupportedType(java.lang.reflect.Type genericType) { TypeInfo typeInfo = ParamTypeHelper.getTypeInfo(genericType); - if (typeInfo == null) { - return false; - } - return getBeanDescriptor(typeInfo.getBeanType()) != null; + return typeInfo != null && getBeanDescriptor(typeInfo.getBeanType()) != null; } public Object getBeanId(Object bean) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java index e64eacd8d..b3b701f38 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java @@ -6,9 +6,7 @@ import java.util.Set; import javax.persistence.PersistenceException; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; -import com.avaje.ebean.RawSql; +import com.avaje.ebean.*; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.PersistenceContext; import com.avaje.ebean.event.BeanFinder; @@ -234,6 +232,30 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe return idList.getIdList(); } + public void findEach(QueryEachConsumer consumer) { + QueryIterator it = queryEngine.findIterate(this); + try { + while (it.hasNext()) { + consumer.accept(it.next()); + } + } finally { + it.close(); + } + } + + public void findEachWhile(QueryEachWhileConsumer consumer) { + QueryIterator it = queryEngine.findIterate(this); + try { + while (it.hasNext()) { + if (!consumer.accept(it.next())) { + break; + } + } + } finally { + it.close(); + } + } + public void findVisit(QueryResultVisitor visitor) { QueryIterator it = queryEngine.findIterate(this); try { diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java index 8837a516d..52c5e1508 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java @@ -4,6 +4,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.avaje.ebean.QueryEachConsumer; +import com.avaje.ebean.QueryEachWhileConsumer; import com.avaje.ebean.QueryIterator; import com.avaje.ebean.QueryResultVisitor; import com.avaje.ebean.bean.BeanCollection; @@ -65,7 +67,17 @@ public interface SpiOrmQueryRequest { */ public void findVisit(QueryResultVisitor visitor); - /** + /** + * Execute the find returning a QueryIterator and visitor pattern. + */ + public void findEach(QueryEachConsumer consumer); + + /** + * Execute the find returning a QueryIterator and visitor pattern. + */ + public void findEachWhile(QueryEachWhileConsumer consumer); + + /** * Execute the find returning a QueryIterator. */ public QueryIterator findIterate(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorManager.java index 8cd02444b..8370f33d6 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -62,10 +62,10 @@ import com.avaje.ebeaninternal.server.deploy.parse.ReadAnnotations; import com.avaje.ebeaninternal.server.deploy.parse.TransientProperties; import com.avaje.ebeaninternal.server.idgen.UuidIdGenerator; import com.avaje.ebeaninternal.server.lib.util.Dnode; -import com.avaje.ebeaninternal.server.reflect.BeanReflect; -import com.avaje.ebeaninternal.server.reflect.BeanReflectFactory; -import com.avaje.ebeaninternal.server.reflect.BeanReflectProperties; -import com.avaje.ebeaninternal.server.reflect.EnhanceBeanReflectFactory; +import com.avaje.ebeaninternal.server.properties.BeanPropertyInfo; +import com.avaje.ebeaninternal.server.properties.BeanPropertyInfoFactory; +import com.avaje.ebeaninternal.server.properties.BeanPropertiesReader; +import com.avaje.ebeaninternal.server.properties.EnhanceBeanPropertyInfoFactory; import com.avaje.ebeaninternal.server.type.TypeManager; /** @@ -86,7 +86,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { */ private final DeployInherit deplyInherit; - private final BeanReflectFactory reflectFactory; + private final BeanPropertyInfoFactory reflectFactory; private final DeployUtil deployUtil; @@ -1274,9 +1274,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } } - private BeanReflectFactory createReflectionFactory() { + private BeanPropertyInfoFactory createReflectionFactory() { - return new EnhanceBeanReflectFactory(); + return new EnhanceBeanPropertyInfoFactory(); } /** @@ -1295,9 +1295,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap { Class beanType = desc.getBeanType(); - BeanReflectProperties reflectProps = new BeanReflectProperties(beanType); + BeanPropertiesReader reflectProps = new BeanPropertiesReader(beanType); - BeanReflect beanReflect = reflectFactory.create(beanType); + BeanPropertyInfo beanReflect = reflectFactory.create(beanType); desc.setBeanReflect(beanReflect); desc.setProperties(reflectProps.getProperties()); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java index 7b0d79fb5..6c0ec7c73 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java @@ -27,8 +27,8 @@ import com.avaje.ebeaninternal.server.el.ElPropertyValue; import com.avaje.ebeaninternal.server.lib.util.StringHelper; import com.avaje.ebeaninternal.server.query.SqlBeanLoad; import com.avaje.ebeaninternal.server.query.SqlJoinType; -import com.avaje.ebeaninternal.server.reflect.BeanReflectGetter; -import com.avaje.ebeaninternal.server.reflect.BeanReflectSetter; +import com.avaje.ebeaninternal.server.properties.BeanPropertyGetter; +import com.avaje.ebeaninternal.server.properties.BeanPropertySetter; import com.avaje.ebeaninternal.server.text.json.WriteJson; import com.avaje.ebeaninternal.server.type.DataBind; import com.avaje.ebeaninternal.server.type.ScalarType; @@ -41,29 +41,6 @@ import com.fasterxml.jackson.core.JsonToken; */ public class BeanProperty implements ElPropertyValue { - /** - * Advanced bean deployment. To exclude this property from update where - * clause. - */ - public static final String EXCLUDE_FROM_UPDATE_WHERE = "EXCLUDE_FROM_UPDATE_WHERE"; - - /** - * Advanced bean deployment. To exclude this property from delete where - * clause. - */ - public static final String EXCLUDE_FROM_DELETE_WHERE = "EXCLUDE_FROM_DELETE_WHERE"; - - /** - * Advanced bean deployment. To exclude this property from insert. - */ - public static final String EXCLUDE_FROM_INSERT = "EXCLUDE_FROM_INSERT"; - - /** - * Advanced bean deployment. To exclude this property from update set - * clause. - */ - public static final String EXCLUDE_FROM_UPDATE = "EXCLUDE_FROM_UPDATE"; - /** * Flag to mark this at part of the unique id. */ @@ -219,9 +196,9 @@ public class BeanProperty implements ElPropertyValue { */ final GeneratedProperty generatedProperty; - final BeanReflectGetter getter; + final BeanPropertyGetter getter; - final BeanReflectSetter setter; + final BeanPropertySetter setter; final BeanDescriptor descriptor; @@ -488,15 +465,7 @@ public class BeanProperty implements ElPropertyValue { * Return true if the underlying type is mutable. */ public boolean isMutableScalarType() { - if (scalarType == null) { - return false; - } - return scalarType.isMutable(); - } - - public void copyProperty(EntityBean sourceBean, EntityBean destBean) { - Object value = getValue(sourceBean); - setValue(destBean, value); + return scalarType != null && scalarType.isMutable(); } /** @@ -506,10 +475,6 @@ public class BeanProperty implements ElPropertyValue { return descriptor.getEncryptKey(this); } - public String getDecryptProperty() { - return dbEncryptFunction.getDecryptSql(this.getName()); - } - public String getDecryptProperty(String propertyName) { return dbEncryptFunction.getDecryptSql(propertyName); } @@ -575,24 +540,6 @@ public class BeanProperty implements ElPropertyValue { return owningType.isAssignableFrom(type); } - public Object readSetOwning(DbReadContext ctx, EntityBean bean, Class type) throws SQLException { - - try { - Object value = scalarType.read(ctx.getDataReader()); - if (value == null || bean == null) { - // not setting the value... - } else { - if (owningType.equals(type)) { - setValue(bean, value); - } - } - return value; - } catch (Exception e) { - String msg = "Error readSet on " + descriptor + "." + name; - throw new PersistenceException(msg, e); - } - } - public void loadIgnore(DbReadContext ctx) { scalarType.loadIgnore(ctx.getDataReader()); } @@ -616,16 +563,13 @@ public class BeanProperty implements ElPropertyValue { public Object readSet(DbReadContext ctx, EntityBean bean, Class type) throws SQLException { try { - Object value = scalarType.read(ctx.getDataReader()); - if (bean == null || (type != null && !owningType.isAssignableFrom(type))) { - // not setting the value... - } else { - setValue(bean, value); - } - return value; + Object value = scalarType.read(ctx.getDataReader()); + if (bean != null && ((type == null || owningType.isAssignableFrom(type)))) { + setValue(bean, value); + } + return value; } catch (Exception e) { - String msg = "Error readSet on " + descriptor + "." + name; - throw new PersistenceException(msg, e); + throw new PersistenceException("Error readSet on " + descriptor + "." + name, e); } } @@ -653,21 +597,6 @@ public class BeanProperty implements ElPropertyValue { return scalarType.readData(dataInput); } - public boolean isCascadeValidate() { - return cascadeValidate; - } - - /** - * Checks to see if a bean is a reference (will be lazy loaded) or a - * BeanCollection that has not yet been populated. - *

- * For base types this returns true. - *

- */ - public boolean isValueLoaded(Object value) { - return true; - } - public BeanProperty getBeanProperty() { return this; } @@ -737,16 +666,21 @@ public class BeanProperty implements ElPropertyValue { } } - private static Object[] NO_ARGS = new Object[0]; - public Object getCacheDataValue(EntityBean bean) { return getValue(bean); - } + } public void setCacheDataValue(EntityBean bean, Object cacheData) { setValue(bean, cacheData); } - + + /** + * Get the property value from a compound value type. + */ + public Object getValueObject(Object bean) { + throw new RuntimeException("Expected to be called only on BeanPropertyCompoundScalar"); + } + /** * Return the value of the property method. */ @@ -759,19 +693,6 @@ public class BeanProperty implements ElPropertyValue { throw new RuntimeException(msg, ex); } } - - /** - * Explicitly use reflection to get value. - */ - public Object getValueViaReflection(Object bean) { - try { - return readMethod.invoke(bean, NO_ARGS); - } catch (Exception ex) { - String beanType = bean == null ? "null" : bean.getClass().getName(); - String msg = "get " + name + " on [" + descriptor + "] type[" + beanType + "] threw error."; - throw new RuntimeException(msg, ex); - } - } public Object getValueIntercept(EntityBean bean) { try { @@ -826,13 +747,6 @@ public class BeanProperty implements ElPropertyValue { return name; } - /** - * This is a full ElGetValue. - */ - public boolean isDeployOnly() { - return false; - } - @Override public boolean containsFormulaWithJoin() { return formula && sqlFormulaJoin != null; @@ -902,7 +816,7 @@ public class BeanProperty implements ElPropertyValue { /** * Return the scalarType. */ - public ScalarType getScalarType() { + public ScalarType getScalarType() { return scalarType; } @@ -923,7 +837,7 @@ public class BeanProperty implements ElPropertyValue { } public Object parseDateTime(long systemTimeMillis) { - return scalarType.parseDateTime(systemTimeMillis); + return scalarType.convertFromMillis(systemTimeMillis); } /** @@ -1031,10 +945,6 @@ public class BeanProperty implements ElPropertyValue { return version; } - public String getDeployProperty() { - return dbColumn; - } - /** * The database column name this is mapped to. */ @@ -1168,13 +1078,6 @@ public class BeanProperty implements ElPropertyValue { return embedded; } - /** - * Return an extra attribute set on this property. - */ - public String getExtraAttribute(String key) { - return extraAttributeMap.get(key); - } - /** * Return the default value. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 0745915b7..2d8d42c55 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -385,12 +385,6 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { return null; } - - @Override - public boolean isValueLoaded(Object value) { - return !(value instanceof BeanCollection) || ((BeanCollection) value).isPopulated(); - } - public void add(BeanCollection collection, EntityBean bean) { help.add(collection, bean); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 997b04659..2a463971b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -265,14 +265,6 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { } } - @Override - public boolean isValueLoaded(Object value) { - if (value instanceof EntityBean) { - return ((EntityBean) value)._ebean_getIntercept().isLoaded(); - } - return true; - } - /** * Return meta data for the deployment of the embedded bean specific to this * property. diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java index 4621cef24..a080a8035 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompound.java @@ -89,19 +89,6 @@ public class BeanPropertyCompound extends BeanProperty { } } - /** - * Get the underlying compound type. - */ - @SuppressWarnings("unchecked") - public Object getValueUnderlying(EntityBean bean) { - - Object value = getValue(bean); - if (typeConverter != null){ - value = typeConverter.unwrapValue(value); - } - return value; - } - public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) { if (chain == null) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundRoot.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundRoot.java index 064a862ec..018feedd0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundRoot.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundRoot.java @@ -7,7 +7,7 @@ import java.util.List; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty; -import com.avaje.ebeaninternal.server.reflect.BeanReflectSetter; +import com.avaje.ebeaninternal.server.properties.BeanPropertySetter; import com.avaje.ebeaninternal.server.type.CtCompoundProperty; /** @@ -22,7 +22,7 @@ import com.avaje.ebeaninternal.server.type.CtCompoundProperty; */ public class BeanPropertyCompoundRoot { - private final BeanReflectSetter setter; + private final BeanPropertySetter setter; /** * The method used to write the property. diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundScalar.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundScalar.java index d05cf0e89..d794e306c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundScalar.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyCompoundScalar.java @@ -6,93 +6,100 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty; import com.avaje.ebeaninternal.server.type.CtCompoundProperty; /** - * A BeanProperty owned by a Compound value object that maps to + * A BeanProperty owned by a Compound value object that maps to * a real scalar type. - * - * @author rbygrave */ public class BeanPropertyCompoundScalar extends BeanProperty { - private final BeanPropertyCompoundRoot rootProperty; - - private final CtCompoundProperty ctProperty; - - @SuppressWarnings("rawtypes") - private final ScalarTypeConverter typeConverter; - - public BeanPropertyCompoundScalar(BeanPropertyCompoundRoot rootProperty, DeployBeanProperty scalarDeploy, - CtCompoundProperty ctProperty, ScalarTypeConverter typeConverter) { - - super(scalarDeploy); - this.rootProperty = rootProperty; - this.ctProperty = ctProperty; - this.typeConverter = typeConverter; - } + private final BeanPropertyCompoundRoot rootProperty; - @SuppressWarnings("unchecked") - @Override - public Object getValue(EntityBean valueObject) { - Object val = valueObject; - if (typeConverter != null){ - val = typeConverter.unwrapValue(val); - } - return ctProperty.getValue(val); - } + private final CtCompoundProperty ctProperty; - @Override - public void setValue(EntityBean bean, Object value) { - setValueInCompound(bean, value, false); - } - - @SuppressWarnings("unchecked") - public void setValueInCompound(EntityBean bean, Object value, boolean intercept) { - - Object compoundValue = ctProperty.setValue(bean, value); - - if (compoundValue != null){ - if (typeConverter != null){ - compoundValue = typeConverter.wrapValue(compoundValue); - } - // we are at the top level and we have a compound value - // that we can set using the root property - if (intercept){ - rootProperty.setRootValueIntercept(bean, compoundValue); - } else { - rootProperty.setRootValue(bean, compoundValue); - } - } - } + @SuppressWarnings("rawtypes") + private final ScalarTypeConverter typeConverter; - /** - * No interception on embedded scalar values inside a CVO. - */ - @Override - public void setValueIntercept(EntityBean bean, Object value) { - setValueInCompound(bean, value, true); - } + public BeanPropertyCompoundScalar(BeanPropertyCompoundRoot rootProperty, DeployBeanProperty scalarDeploy, + CtCompoundProperty ctProperty, ScalarTypeConverter typeConverter) { - /** - * No interception on embedded scalar values inside a CVO. - */ - @Override - public Object getValueIntercept(EntityBean bean) { - return getValue(bean); - } + super(scalarDeploy); + this.rootProperty = rootProperty; + this.ctProperty = ctProperty; + this.typeConverter = typeConverter; + } - @Override - public Object elGetReference(EntityBean bean) { - return getValue(bean); + /** + * Return one of the scalar values from a compound type. + */ + public Object getValueObject(Object compoundValue) { + if (typeConverter != null) { + compoundValue = typeConverter.unwrapValue(compoundValue); } + return ctProperty.getValue(compoundValue); + } - @Override - public Object elGetValue(EntityBean bean) { - return getValue(bean); + @SuppressWarnings("unchecked") + @Override + public Object getValue(EntityBean valueObject) { + Object val = valueObject; + if (typeConverter != null) { + val = typeConverter.unwrapValue(val); } + return ctProperty.getValue(val); + } - @Override - public void elSetValue(EntityBean bean, Object value, boolean populate) {//, boolean reference) { - super.elSetValue(bean, value, populate); + @Override + public void setValue(EntityBean bean, Object value) { + setValueInCompound(bean, value, false); + } + + @SuppressWarnings("unchecked") + public void setValueInCompound(EntityBean bean, Object value, boolean intercept) { + + Object compoundValue = ctProperty.setValue(bean, value); + + if (compoundValue != null) { + if (typeConverter != null) { + compoundValue = typeConverter.wrapValue(compoundValue); + } + // we are at the top level and we have a compound value + // that we can set using the root property + if (intercept) { + rootProperty.setRootValueIntercept(bean, compoundValue); + } else { + rootProperty.setRootValue(bean, compoundValue); + } } + } + + /** + * No interception on embedded scalar values inside a CVO. + */ + @Override + public void setValueIntercept(EntityBean bean, Object value) { + setValueInCompound(bean, value, true); + } + + /** + * No interception on embedded scalar values inside a CVO. + */ + @Override + public Object getValueIntercept(EntityBean bean) { + return getValue(bean); + } + + @Override + public Object elGetReference(EntityBean bean) { + return getValue(bean); + } + + @Override + public Object elGetValue(EntityBean bean) { + return getValue(bean); + } + + @Override + public void elSetValue(EntityBean bean, Object value, boolean populate) {//, boolean reference) { + super.elSetValue(bean, value, populate); + } - } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index d2be5227a..920bade18 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -36,7 +36,7 @@ import com.avaje.ebeaninternal.server.deploy.DRawSqlMeta; import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery; import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate; import com.avaje.ebeaninternal.server.deploy.InheritInfo; -import com.avaje.ebeaninternal.server.reflect.BeanReflect; +import com.avaje.ebeaninternal.server.properties.BeanPropertyInfo; /** * Describes Beans including their deployment information. @@ -127,7 +127,7 @@ public class DeployBeanDescriptor { * Used to provide mechanism to new EntityBean instances. Generated code * faster than reflection at this stage. */ - private BeanReflect beanReflect; + private BeanPropertyInfo beanReflect; private String[] properties; /** @@ -302,7 +302,7 @@ public class DeployBeanDescriptor { this.properties = props; } - public BeanReflect getBeanReflect() { + public BeanPropertyInfo getBeanReflect() { return beanReflect; } @@ -317,7 +317,7 @@ public class DeployBeanDescriptor { * Set the BeanReflect used to create new instances of an EntityBean. This * could use reflection or code generation to do this. */ - public void setBeanReflect(BeanReflect beanReflect) { + public void setBeanReflect(BeanPropertyInfo beanReflect) { this.beanReflect = beanReflect; } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index 277319337..39303268f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -20,8 +20,8 @@ import com.avaje.ebeaninternal.server.core.InternString; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType; import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; import com.avaje.ebeaninternal.server.el.ElPropertyValue; -import com.avaje.ebeaninternal.server.reflect.BeanReflectGetter; -import com.avaje.ebeaninternal.server.reflect.BeanReflectSetter; +import com.avaje.ebeaninternal.server.properties.BeanPropertyGetter; +import com.avaje.ebeaninternal.server.properties.BeanPropertySetter; import com.avaje.ebeaninternal.server.type.ScalarType; import com.avaje.ebeaninternal.server.type.ScalarTypeEnum; import com.avaje.ebeaninternal.server.type.ScalarTypeWrapper; @@ -202,9 +202,9 @@ public class DeployBeanProperty { private int propertyIndex; - private BeanReflectGetter getter; + private BeanPropertyGetter getter; - private BeanReflectSetter setter; + private BeanPropertySetter setter; /** * Generator for insert or update timestamp etc. @@ -414,7 +414,7 @@ public class DeployBeanProperty { ScalarTypeEnum etype = (ScalarTypeEnum) scalarType; // check dbColName IN ('A', 'I', 'D') - return "check (" + dbColumn + " in " + etype.getContraintInValues() + ")"; + return "check (" + dbColumn + " in " + etype.getConstraintInValues() + ")"; } return null; } @@ -439,11 +439,11 @@ public class DeployBeanProperty { this.propertyIndex = propertyIndex; } - public BeanReflectGetter getGetter() { + public BeanPropertyGetter getGetter() { return getter; } - public BeanReflectSetter getSetter() { + public BeanPropertySetter getSetter() { return setter; } @@ -482,14 +482,14 @@ public class DeployBeanProperty { /** * Set the getter used to read the property value from a bean. */ - public void setGetter(BeanReflectGetter getter) { + public void setGetter(BeanPropertyGetter getter) { this.getter = getter; } /** * Set the setter used to set the property value to a bean. */ - public void setSetter(BeanReflectSetter setter) { + public void setSetter(BeanPropertySetter setter) { this.setter = setter; } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyCompound.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyCompound.java index a14ddb2b0..ebdd90acd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyCompound.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyCompound.java @@ -21,99 +21,99 @@ import com.avaje.ebeaninternal.server.type.ScalarType; */ public class DeployBeanPropertyCompound extends DeployBeanProperty { - final CtCompoundType compoundType; + final CtCompoundType compoundType; - final ScalarTypeConverter typeConverter; + final ScalarTypeConverter typeConverter; - DeployBeanEmbedded deployEmbedded; - - /** - * Create the property. - */ - public DeployBeanPropertyCompound(DeployBeanDescriptor desc, Class targetType, - CtCompoundType compoundType, ScalarTypeConverter typeConverter) { - - super(desc, targetType, null, null); - this.compoundType = compoundType; - this.typeConverter = typeConverter; - } + DeployBeanEmbedded deployEmbedded; - public BeanPropertyCompoundRoot getFlatProperties(BeanDescriptorMap owner, BeanDescriptor descriptor) { - - // get a 'flat' list of all the scalar types, their relative property names - // and also set their matching dbColumn - - // represents the root property - BeanPropertyCompoundRoot rootProperty = new BeanPropertyCompoundRoot(this); - - // Walk the tree of a compound type collecting the - // scalar types and non-scalar properties - CtCompoundTypeScalarList ctMeta = new CtCompoundTypeScalarList(); - - compoundType.accumulateScalarTypes(null, ctMeta); - - List beanPropertyList = new ArrayList(); - - - // for each of the scalar types inside a compound value object - // build a BeanPropertyCompoundScalar with appropriate deployment - // information. - - for (Entry> entry : ctMeta.entries()) { + /** + * Create the property. + */ + public DeployBeanPropertyCompound(DeployBeanDescriptor desc, Class targetType, + CtCompoundType compoundType, ScalarTypeConverter typeConverter) { - String relativePropertyName = entry.getKey(); - ScalarType scalarType = entry.getValue(); - - CtCompoundProperty ctProp = ctMeta.getCompoundType(relativePropertyName); - - - String dbColumn = relativePropertyName.replace(".", "_"); - dbColumn = getDbColumn(relativePropertyName, dbColumn); - - DeployBeanProperty deploy = new DeployBeanProperty(null, scalarType.getType(), scalarType, null); - deploy.setScalarType(scalarType); - deploy.setDbColumn(dbColumn); - deploy.setName(relativePropertyName); - deploy.setDbInsertable(true); - deploy.setDbUpdateable(true); - deploy.setDbRead(true); - - BeanPropertyCompoundScalar bp = new BeanPropertyCompoundScalar(rootProperty, deploy, ctProp, typeConverter); - beanPropertyList.add(bp); - - rootProperty.register(bp); - } - - rootProperty.setNonScalarProperties(ctMeta.getNonScalarProperties()); - return rootProperty; - } - - private String getDbColumn(String propName, String defaultDbColumn){ - if (deployEmbedded == null){ - return defaultDbColumn; - } - String dbColumn = deployEmbedded.getPropertyColumnMap().get(propName); - return dbColumn == null ? defaultDbColumn : dbColumn; - } - - /** - * Return the deploy information specifically for the deployment - * of Embedded beans. - */ - public DeployBeanEmbedded getDeployEmbedded() { - // deployment should be single threaded - if (deployEmbedded == null){ - deployEmbedded = new DeployBeanEmbedded(); - } - return deployEmbedded; - } + super(desc, targetType, null, null); + this.compoundType = compoundType; + this.typeConverter = typeConverter; + } - public ScalarTypeConverter getTypeConverter() { - return typeConverter; + public BeanPropertyCompoundRoot getFlatProperties(BeanDescriptorMap owner, BeanDescriptor descriptor) { + + // get a 'flat' list of all the scalar types, their relative property names + // and also set their matching dbColumn + + // represents the root property + BeanPropertyCompoundRoot rootProperty = new BeanPropertyCompoundRoot(this); + + // Walk the tree of a compound type collecting the + // scalar types and non-scalar properties + CtCompoundTypeScalarList ctMeta = new CtCompoundTypeScalarList(); + + compoundType.accumulateScalarTypes(null, ctMeta); + + List beanPropertyList = new ArrayList(); + + + // for each of the scalar types inside a compound value object + // build a BeanPropertyCompoundScalar with appropriate deployment + // information. + + for (Entry> entry : ctMeta.entries()) { + + String relativePropertyName = entry.getKey(); + ScalarType scalarType = entry.getValue(); + + CtCompoundProperty ctProp = ctMeta.getCompoundType(relativePropertyName); + + + String dbColumn = (getName() + "." + relativePropertyName).replace(".", "_"); + dbColumn = getDbColumn(relativePropertyName, dbColumn); + + DeployBeanProperty deploy = new DeployBeanProperty(null, scalarType.getType(), scalarType, null); + deploy.setScalarType(scalarType); + deploy.setDbColumn(dbColumn); + deploy.setName(relativePropertyName); + deploy.setDbInsertable(true); + deploy.setDbUpdateable(true); + deploy.setDbRead(true); + + BeanPropertyCompoundScalar bp = new BeanPropertyCompoundScalar(rootProperty, deploy, ctProp, typeConverter); + beanPropertyList.add(bp); + + rootProperty.register(bp); } - public CtCompoundType getCompoundType() { - return compoundType; + rootProperty.setNonScalarProperties(ctMeta.getNonScalarProperties()); + return rootProperty; + } + + private String getDbColumn(String propName, String defaultDbColumn) { + if (deployEmbedded == null) { + return defaultDbColumn; } + String dbColumn = deployEmbedded.getPropertyColumnMap().get(propName); + return dbColumn == null ? defaultDbColumn : dbColumn; + } + + /** + * Return the deploy information specifically for the deployment + * of Embedded beans. + */ + public DeployBeanEmbedded getDeployEmbedded() { + // deployment should be single threaded + if (deployEmbedded == null) { + deployEmbedded = new DeployBeanEmbedded(); + } + return deployEmbedded; + } + + public ScalarTypeConverter getTypeConverter() { + return typeConverter; + } + + public CtCompoundType getCompoundType() { + return compoundType; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployCreateProperties.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployCreateProperties.java index ed0527964..024f2bf66 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployCreateProperties.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployCreateProperties.java @@ -93,7 +93,7 @@ public class DeployCreateProperties { } /** - * reflect the bean properties from Class. Some of these properties may not map to database + * properties the bean properties from Class. Some of these properties may not map to database * columns. */ private void createProperties(DeployBeanDescriptor desc, Class beanType, int level) { @@ -125,7 +125,7 @@ public class DeployCreateProperties { Method getter = findGetter(field, initFieldName, declaredMethods, scalaObject); Method setter = findSetter(field, initFieldName, declaredMethods, scalaObject); - DeployBeanProperty prop = createProp(level, desc, field, beanType, getter, setter); + DeployBeanProperty prop = createProp(desc, field, beanType, getter, setter); if (prop == null) { // transient annotation on unsupported type @@ -152,7 +152,7 @@ public class DeployCreateProperties { Class superClass = beanType.getSuperclass(); if (!superClass.equals(Object.class)) { - // recursively add any properties in the inheritance heirarchy + // recursively add any properties in the inheritance hierarchy // up to the Object.class level... createProperties(desc, superClass, level + 1); } @@ -361,7 +361,7 @@ public class DeployCreateProperties { if (field.getAnnotation(ColumnHstore.class) != null) { return ScalarTypePostgresHstore.KEY; - }; + } return null; } @@ -372,7 +372,7 @@ public class DeployCreateProperties { return (t != null); } - private DeployBeanProperty createProp(int level, DeployBeanDescriptor desc, Field field, Class beanType, + private DeployBeanProperty createProp(DeployBeanDescriptor desc, Field field, Class beanType, Method getter, Method setter) { DeployBeanProperty prop = createProp(desc, field); diff --git a/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java b/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java index c23dc7465..af9db6390 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java +++ b/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java @@ -215,7 +215,7 @@ public class ElPropertyChain implements ElPropertyValue { } public Object parseDateTime(long systemTimeMillis) { - return scalarType.parseDateTime(systemTimeMillis); + return scalarType.convertFromMillis(systemTimeMillis); } public StringParser getStringParser() { diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 6bb654df3..4edaca7b9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -218,6 +218,16 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr return exprList.findIds(); } + @Override + public void findEach(QueryEachConsumer consumer) { + exprList.findEach(consumer); + } + + @Override + public void findEachWhile(QueryEachWhileConsumer consumer) { + exprList.findEachWhile(consumer); + } + public void findVisit(QueryResultVisitor visitor) { exprList.findVisit(visitor); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableCompound.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableCompound.java index f11467f16..a70604b29 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableCompound.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableCompound.java @@ -14,40 +14,41 @@ import com.avaje.ebeaninternal.server.persist.dml.GenerateDmlRequest; */ public class BindableCompound implements Bindable { - private final Bindable[] items; + private final BindableProperty[] items; - private final BeanPropertyCompound compound; + private final BeanPropertyCompound compound; - public BindableCompound(BeanPropertyCompound embProp, List list) { - this.compound = embProp; - this.items = list.toArray(new Bindable[list.size()]); + public BindableCompound(BeanPropertyCompound embProp, List list) { + this.compound = embProp; + this.items = list.toArray(new BindableProperty[list.size()]); + } + + public String toString() { + return "BindableCompound " + compound + " items:" + Arrays.toString(items); + } + + public void dmlAppend(GenerateDmlRequest request) { + + for (int i = 0; i < items.length; i++) { + items[i].dmlAppend(request); } + } - public String toString() { - return "BindableCompound " + compound + " items:" + Arrays.toString(items); + public void addToUpdate(PersistRequestBean request, List list) { + if (request.isAddToUpdate(compound)) { + list.add(this); } + } - public void dmlAppend(GenerateDmlRequest request) { + public void dmlBind(BindableRequest bindRequest, EntityBean bean) throws SQLException { - for (int i = 0; i < items.length; i++) { - items[i].dmlAppend(request); - } - } + // get the compound type value + Object valueObject = compound.getValue(bean); - public void addToUpdate(PersistRequestBean request, List list) { - if (request.isAddToUpdate(compound)) { - list.add(this); - } - } - - public void dmlBind(BindableRequest bindRequest, EntityBean bean) throws SQLException { - - throw new RuntimeException("This is broken, need to break out the scalar values!!"); - - //Object valueObject = compound.getValue(bean); - //for (int i = 0; i < items.length; i++) { - // items[i].dmlBind(bindRequest, valueObject); - //} + // bind each of the underlying scalar values for this compound type + for (int i = 0; i < items.length; i++) { + items[i].dmlBindObject(bindRequest, valueObject); } + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableProperty.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableProperty.java index 56f709ffc..3b84078d0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableProperty.java @@ -13,33 +13,47 @@ import com.avaje.ebeaninternal.server.persist.dml.GenerateDmlRequest; */ public class BindableProperty implements Bindable { - protected final BeanProperty prop; + protected final BeanProperty prop; - public BindableProperty(BeanProperty prop) { - this.prop = prop; + public BindableProperty(BeanProperty prop) { + this.prop = prop; + } + + public String toString() { + return prop.toString(); + } + + public void addToUpdate(PersistRequestBean request, List list) { + if (request.isAddToUpdate(prop)) { + list.add(this); } + } - public String toString() { - return prop.toString(); + public void dmlAppend(GenerateDmlRequest request) { + request.appendColumn(prop.getDbColumn()); + } + + /** + * Normal binding of a property value from the bean. + */ + public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException { + + Object value = null; + if (bean != null) { + value = prop.getValue(bean); } + request.bind(value, prop, prop.getName()); + } - public void addToUpdate(PersistRequestBean request, List list) { - if (request.isAddToUpdate(prop)) { - list.add(this); - } - } + /** + * For compound types bind one of the underlying scalar values for a compound type. + */ + public void dmlBindObject(BindableRequest request, Object bean) throws SQLException { - public void dmlAppend(GenerateDmlRequest request) { - request.appendColumn(prop.getDbColumn()); - } - - public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException { - - Object value = null; - if (bean != null) { - value = prop.getValue(bean); - } - // value = prop.getDefaultValue(); - request.bind(value, prop, prop.getName()); + Object value = null; + if (bean != null) { + value = prop.getValueObject(bean); } + request.bind(value, prop, prop.getName()); + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/FactoryBaseProperties.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/FactoryBaseProperties.java index 4b3614979..69de1e8f1 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/FactoryBaseProperties.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/FactoryBaseProperties.java @@ -16,49 +16,52 @@ import com.avaje.ebeaninternal.server.persist.dml.DmlMode; */ public class FactoryBaseProperties { - private final FactoryProperty factoryProperty; - - - public FactoryBaseProperties(boolean bindEncryptDataFirst) { - factoryProperty = new FactoryProperty(bindEncryptDataFirst); - } + private final FactoryProperty factoryProperty; - /** - * Add Bindable for the base properties to the list. - */ - public void create(List list, BeanDescriptor desc, DmlMode mode, boolean withLobs) { - add(desc.propertiesBaseScalar(), list, desc, mode, withLobs); + public FactoryBaseProperties(boolean bindEncryptDataFirst) { + factoryProperty = new FactoryProperty(bindEncryptDataFirst); + } - BeanPropertyCompound[] compoundProps = desc.propertiesBaseCompound(); - for (int i = 0; i < compoundProps.length; i++) { - BeanProperty[] props = compoundProps[i].getScalarProperties(); + /** + * Add Bindable for the base properties to the list. + */ + public void create(List list, BeanDescriptor desc, DmlMode mode, boolean withLobs) { - ArrayList newList = new ArrayList(props.length); - add(props, newList, desc, mode, withLobs); - - BindableCompound compoundBindable = new BindableCompound(compoundProps[i], newList); + add(desc.propertiesBaseScalar(), list, desc, mode, withLobs); - list.add(compoundBindable); - } - } + BeanPropertyCompound[] compoundProps = desc.propertiesBaseCompound(); + for (int i = 0; i < compoundProps.length; i++) { + BeanProperty[] props = compoundProps[i].getScalarProperties(); - private void add(BeanProperty[] props, List list, BeanDescriptor desc, DmlMode mode, boolean withLobs) { + List newList = new ArrayList(props.length); + addCompound(props, newList, desc, mode, withLobs); - for (int i = 0; i < props.length; i++) { + BindableCompound compoundBindable = new BindableCompound(compoundProps[i], newList); -// if(DmlMode.WHERE.equals(mode) && !withLobs && !props[i].isDbUpdatable()) { -// // skip non-updatable column from where clause -// } else { - Bindable item = factoryProperty.create(props[i], mode, withLobs); - if (item != null) { - list.add(item); - } else { - // null where readOnly (Secondary tables) or Lob exclusion - } -// } - } + list.add(compoundBindable); + } + } + private void add(BeanProperty[] props, List list, BeanDescriptor desc, DmlMode mode, boolean withLobs) { + + for (int i = 0; i < props.length; i++) { + Bindable item = factoryProperty.create(props[i], mode, withLobs); + if (item != null) { + list.add(item); + } + } + } + + private void addCompound(BeanProperty[] props, List list, BeanDescriptor desc, DmlMode mode, boolean withLobs) { + + for (int i = 0; i < props.length; i++) { + BindableProperty item = (BindableProperty) factoryProperty.create(props[i], mode, withLobs); + if (item != null) { + list.add(item); + } } + } + } diff --git a/src/main/java/com/avaje/ebeaninternal/server/reflect/BeanReflectProperties.java b/src/main/java/com/avaje/ebeaninternal/server/properties/BeanPropertiesReader.java similarity index 82% rename from src/main/java/com/avaje/ebeaninternal/server/reflect/BeanReflectProperties.java rename to src/main/java/com/avaje/ebeaninternal/server/properties/BeanPropertiesReader.java index ac0fa94cd..abda15c40 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/reflect/BeanReflectProperties.java +++ b/src/main/java/com/avaje/ebeaninternal/server/properties/BeanPropertiesReader.java @@ -1,17 +1,20 @@ -package com.avaje.ebeaninternal.server.reflect; +package com.avaje.ebeaninternal.server.properties; import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; import java.util.Map; -public class BeanReflectProperties { +/** + * Determines the properties on a given bean. + */ +public class BeanPropertiesReader { private final Map propertyIndexMap = new HashMap(); private final String[] props; - public BeanReflectProperties(Class clazz) { + public BeanPropertiesReader(Class clazz) { this.props = getProperties(clazz); for (int i=0; i */ -public interface BeanReflect { +public interface BeanPropertyInfo { /** * Create an EntityBean for this type. @@ -17,10 +17,10 @@ public interface BeanReflect { /** * Return the getter for a given bean property. */ - public BeanReflectGetter getGetter(String name, int position); + public BeanPropertyGetter getGetter(String name, int position); /** * Return the setter for a given bean property. */ - public BeanReflectSetter getSetter(String name, int position); + public BeanPropertySetter getSetter(String name, int position); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/reflect/BeanReflectFactory.java b/src/main/java/com/avaje/ebeaninternal/server/properties/BeanPropertyInfoFactory.java similarity index 54% rename from src/main/java/com/avaje/ebeaninternal/server/reflect/BeanReflectFactory.java rename to src/main/java/com/avaje/ebeaninternal/server/properties/BeanPropertyInfoFactory.java index 1b897032a..76ecc9e5f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/reflect/BeanReflectFactory.java +++ b/src/main/java/com/avaje/ebeaninternal/server/properties/BeanPropertyInfoFactory.java @@ -1,14 +1,14 @@ -package com.avaje.ebeaninternal.server.reflect; +package com.avaje.ebeaninternal.server.properties; /** * Creates BeanReflect object used to provide getter setter and construction * for the beans. */ -public interface BeanReflectFactory { +public interface BeanPropertyInfoFactory { /** * Create the BeanReflect for the given plain bean and its EntityBean equivalent. */ - public BeanReflect create(Class entityBeanType); + public BeanPropertyInfo create(Class entityBeanType); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/reflect/BeanReflectSetter.java b/src/main/java/com/avaje/ebeaninternal/server/properties/BeanPropertySetter.java similarity index 78% rename from src/main/java/com/avaje/ebeaninternal/server/reflect/BeanReflectSetter.java rename to src/main/java/com/avaje/ebeaninternal/server/properties/BeanPropertySetter.java index 614408a6e..9d93f6c7e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/reflect/BeanReflectSetter.java +++ b/src/main/java/com/avaje/ebeaninternal/server/properties/BeanPropertySetter.java @@ -1,11 +1,11 @@ -package com.avaje.ebeaninternal.server.reflect; +package com.avaje.ebeaninternal.server.properties; import com.avaje.ebean.bean.EntityBean; /** * The setter for a given bean property. */ -public interface BeanReflectSetter { +public interface BeanPropertySetter { /** * Set the property value of a bean. diff --git a/src/main/java/com/avaje/ebeaninternal/server/reflect/EnhanceBeanReflect.java b/src/main/java/com/avaje/ebeaninternal/server/properties/EnhanceBeanPropertyInfo.java similarity index 80% rename from src/main/java/com/avaje/ebeaninternal/server/reflect/EnhanceBeanReflect.java rename to src/main/java/com/avaje/ebeaninternal/server/properties/EnhanceBeanPropertyInfo.java index 3749431ee..4a0f6fc60 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/reflect/EnhanceBeanReflect.java +++ b/src/main/java/com/avaje/ebeaninternal/server/properties/EnhanceBeanPropertyInfo.java @@ -1,4 +1,4 @@ -package com.avaje.ebeaninternal.server.reflect; +package com.avaje.ebeaninternal.server.properties; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; @@ -11,13 +11,13 @@ import com.avaje.ebean.bean.EntityBean; * A BeanReflect implementation based on the enhancement that creates EntityBean * implementations. */ -public final class EnhanceBeanReflect implements BeanReflect { +public final class EnhanceBeanPropertyInfo implements BeanPropertyInfo { private static final Object[] constuctorArgs = new Object[0]; private final Constructor constructor; - public EnhanceBeanReflect(Class clazz) { + public EnhanceBeanPropertyInfo(Class clazz) { try { if (Modifier.isAbstract(clazz.getModifiers())) { this.constructor = null; @@ -47,15 +47,15 @@ public final class EnhanceBeanReflect implements BeanReflect { } } - public BeanReflectGetter getGetter(String name, int position) { + public BeanPropertyGetter getGetter(String name, int position) { return new Getter(position); } - public BeanReflectSetter getSetter(String name, int position) { + public BeanPropertySetter getSetter(String name, int position) { return new Setter(position); } - static final class Getter implements BeanReflectGetter { + static final class Getter implements BeanPropertyGetter { private final int fieldIndex; @@ -72,7 +72,7 @@ public final class EnhanceBeanReflect implements BeanReflect { } } - static final class Setter implements BeanReflectSetter { + static final class Setter implements BeanPropertySetter { private final int fieldIndex; diff --git a/src/main/java/com/avaje/ebeaninternal/server/properties/EnhanceBeanPropertyInfoFactory.java b/src/main/java/com/avaje/ebeaninternal/server/properties/EnhanceBeanPropertyInfoFactory.java new file mode 100644 index 000000000..d70911890 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/properties/EnhanceBeanPropertyInfoFactory.java @@ -0,0 +1,13 @@ +package com.avaje.ebeaninternal.server.properties; + +/** + * Creates a BeanReflectFactory based on the enhancement that + * creates EntityBean implementations. + */ +public final class EnhanceBeanPropertyInfoFactory implements BeanPropertyInfoFactory { + + public BeanPropertyInfo create(Class entityBeanType) { + return new EnhanceBeanPropertyInfo(entityBeanType); + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/reflect/package.html b/src/main/java/com/avaje/ebeaninternal/server/properties/package.html similarity index 100% rename from src/main/java/com/avaje/ebeaninternal/server/reflect/package.html rename to src/main/java/com/avaje/ebeaninternal/server/properties/package.html diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 607cdc0f5..de67a9949 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -8,22 +8,8 @@ import java.util.Set; import javax.persistence.PersistenceException; -import com.avaje.ebean.EbeanServer; -import com.avaje.ebean.Expression; -import com.avaje.ebean.ExpressionFactory; -import com.avaje.ebean.ExpressionList; -import com.avaje.ebean.FetchConfig; -import com.avaje.ebean.FutureIds; -import com.avaje.ebean.FutureList; -import com.avaje.ebean.FutureRowCount; -import com.avaje.ebean.OrderBy; +import com.avaje.ebean.*; import com.avaje.ebean.OrderBy.Property; -import com.avaje.ebean.PagedList; -import com.avaje.ebean.PagingList; -import com.avaje.ebean.Query; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; -import com.avaje.ebean.RawSql; import com.avaje.ebean.bean.BeanCollectionTouched; import com.avaje.ebean.bean.CallStack; import com.avaje.ebean.bean.EntityBean; @@ -911,6 +897,16 @@ public class DefaultOrmQuery implements SpiQuery { server.findVisit(this, visitor, null); } + @Override + public void findEachWhile(QueryEachWhileConsumer consumer) { + server.findEachWhile(this, consumer, null); + } + + @Override + public void findEach(QueryEachConsumer consumer) { + server.findEach(this, consumer, null); + } + public QueryIterator findIterate() { return server.findIterate(this, null); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/reflect/EnhanceBeanReflectFactory.java b/src/main/java/com/avaje/ebeaninternal/server/reflect/EnhanceBeanReflectFactory.java deleted file mode 100644 index 401d2b72c..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/reflect/EnhanceBeanReflectFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.avaje.ebeaninternal.server.reflect; - -/** - * Creates a BeanReflectFactory based on the enhancement that - * creates EntityBean implementations. - */ -public final class EnhanceBeanReflectFactory implements BeanReflectFactory { - - public BeanReflect create(Class entityBeanType) { - return new EnhanceBeanReflect(entityBeanType); - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/CompoundTypePeriod.java b/src/main/java/com/avaje/ebeaninternal/server/type/CompoundTypePeriod.java new file mode 100644 index 000000000..2209b470b --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/CompoundTypePeriod.java @@ -0,0 +1,81 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.config.CompoundType; +import com.avaje.ebean.config.CompoundTypeProperty; + +import java.time.Period; + +/** + * Compound type for Period value type. + *

+ * Persists the Period into 3 separate integer columns for years, months and days. + *

+ */ +public class CompoundTypePeriod implements CompoundType { + + CompoundTypeProperty[] properties = new CompoundTypeProperty[3]; + + public CompoundTypePeriod() { + properties[0] = new CTPeriodYear(); + properties[1] = new CTPeriodMonth(); + properties[2] = new CTPeriodDay(); + } + + @Override + public Period create(Object[] propertyValues) { + return Period.of((Integer)propertyValues[0], (Integer)propertyValues[1], (Integer)propertyValues[2]); + } + + @Override + public CompoundTypeProperty[] getProperties() { + return properties; + } + + static class CTPeriodYear implements CompoundTypeProperty { + + public String getName() { + return "years"; + } + + public Integer getValue(Period valueObject) { + return valueObject.getYears(); + } + + public int getDbType() { + return 0; + } + + } + + static class CTPeriodMonth implements CompoundTypeProperty { + + public String getName() { + return "months"; + } + + public Integer getValue(Period valueObject) { + return valueObject.getMonths(); + } + + public int getDbType() { + return 0; + } + + } + + static class CTPeriodDay implements CompoundTypeProperty { + + public String getName() { + return "days"; + } + + public Integer getValue(Period valueObject) { + return valueObject.getDays(); + } + + public int getDbType() { + return 0; + } + + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DateTimeJsonParser.java b/src/main/java/com/avaje/ebeaninternal/server/type/DateTimeJsonParser.java index decc9ccbd..df303c431 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/DateTimeJsonParser.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DateTimeJsonParser.java @@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.type; import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.TimeZone; public class DateTimeJsonParser { @@ -31,4 +32,7 @@ public class DateTimeJsonParser { } } + public String format(Date value) { + return dtFormat().format(value); + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DecimalUtils.java b/src/main/java/com/avaje/ebeaninternal/server/type/DecimalUtils.java new file mode 100644 index 000000000..e84fd7644 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DecimalUtils.java @@ -0,0 +1,89 @@ +package com.avaje.ebeaninternal.server.type; + +/* + * Copyright 2013 FasterXML.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.time.Duration; +import java.time.Instant; + +/** + * Utilities to aid in the translation of decimal types to/from multiple parts. + * + * @author Nick Williams + * @since 2.2.0 + */ +public final class DecimalUtils { + + private static final char[] ZEROES = new char[]{'0', '0', '0', '0', '0', '0', '0', '0', '0'}; + + private static final BigDecimal ONE_BILLION = new BigDecimal(1000000000L); + + private DecimalUtils() { + throw new RuntimeException("DecimalUtils cannot be instantiated."); + } + + public static Duration toDuration(BigDecimal value) { + + long seconds = value.longValue(); + int nanoseconds = extractNanosecondDecimal(value, seconds); + + return Duration.ofSeconds(seconds, nanoseconds); + } + + public static BigDecimal toDecimal(Duration instant) { + return new BigDecimal(toDecimal(instant.getSeconds(), instant.getNano())); + } + + public static Timestamp toTimestamp(BigDecimal value) { + + long seconds = value.longValue(); + int nanoseconds = extractNanosecondDecimal(value, seconds); + + Timestamp ts = new Timestamp(seconds * 1000); + ts.setNanos(nanoseconds); + return ts; + } + + public static BigDecimal toDecimal(Timestamp instant) { + long millis = instant.getTime(); + long secs = millis/1000; + return new BigDecimal(toDecimal(secs, instant.getNanos())); + } + + public static Instant toInstant(BigDecimal value) { + + long seconds = value.longValue(); + int nanoseconds = extractNanosecondDecimal(value, seconds); + return Instant.ofEpochSecond(seconds, nanoseconds); + } + + public static BigDecimal toDecimal(Instant instant) { + return new BigDecimal(toDecimal(instant.getEpochSecond(), instant.getNano())); + } + + public static String toDecimal(long seconds, int nanoseconds) { + StringBuilder string = new StringBuilder(Integer.toString(nanoseconds)); + if (string.length() < 9) + string.insert(0, ZEROES, 0, 9 - string.length()); + return seconds + "." + string; + } + + public static int extractNanosecondDecimal(BigDecimal value, long integer) { + return value.subtract(new BigDecimal(integer)).multiply(ONE_BILLION).intValue(); + } +} \ No newline at end of file diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeFactory.java b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeFactory.java index dab788a76..ffbd27410 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeFactory.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeFactory.java @@ -4,6 +4,7 @@ import java.math.BigInteger; import java.sql.Types; import java.util.Calendar; +import com.avaje.ebean.config.JsonConfig; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; @@ -80,27 +81,27 @@ public class DefaultTypeFactory { /** * Create the default ScalarType for java.util.Date. */ - public ScalarType createUtilDate() { + public ScalarType createUtilDate(JsonConfig.DateTime mode) { // by default map anonymous java.util.Date to java.sql.Timestamp. // String mapType = // properties.getProperty("type.mapping.java.util.Date","timestamp"); int utilDateType = getTemporalMapType("timestamp"); - return createUtilDate(utilDateType); + return createUtilDate(mode, utilDateType); } /** * Create a ScalarType for java.util.Date explicitly specifying the type to * map to. */ - public ScalarType createUtilDate(int utilDateType) { + public ScalarType createUtilDate(JsonConfig.DateTime mode, int utilDateType) { switch (utilDateType) { case Types.DATE: return new ScalarTypeUtilDate.DateType(); case Types.TIMESTAMP: - return new ScalarTypeUtilDate.TimestampType(); + return new ScalarTypeUtilDate.TimestampType(mode); default: throw new RuntimeException("Invalid type " + utilDateType); @@ -110,23 +111,19 @@ public class DefaultTypeFactory { /** * Create the default ScalarType for java.util.Calendar. */ - public ScalarType createCalendar() { - // by default map anonymous java.util.Calendar to java.sql.Timestamp. - // String mapType = - // properties.getProperty("type.mapping.java.util.Calendar", - // "timestamp"); - int jdbcType = getTemporalMapType("timestamp"); + public ScalarType createCalendar(JsonConfig.DateTime mode) { - return createCalendar(jdbcType); + int jdbcType = getTemporalMapType("timestamp"); + return createCalendar(mode, jdbcType); } /** * Create a ScalarType for java.util.Calendar explicitly specifying the type * to map to. */ - public ScalarType createCalendar(int jdbcType) { + public ScalarType createCalendar(JsonConfig.DateTime mode, int jdbcType) { - return new ScalarTypeCalendar(jdbcType); + return new ScalarTypeCalendar(mode, jdbcType); } private int getTemporalMapType(String mapType) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java index 9eed017de..8ef3780b5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java @@ -10,6 +10,7 @@ import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; +import java.time.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -22,6 +23,7 @@ import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import com.avaje.ebean.config.*; import org.joda.time.DateMidnight; import org.joda.time.DateTime; import org.joda.time.LocalDate; @@ -32,10 +34,6 @@ import org.slf4j.LoggerFactory; import com.avaje.ebean.annotation.EnumMapping; import com.avaje.ebean.annotation.EnumValue; -import com.avaje.ebean.config.CompoundType; -import com.avaje.ebean.config.CompoundTypeProperty; -import com.avaje.ebean.config.ScalarTypeConverter; -import com.avaje.ebean.config.ServerConfig; import com.avaje.ebeaninternal.api.ClassUtil; import com.avaje.ebeaninternal.server.core.BootupClasses; import com.avaje.ebeaninternal.server.lib.util.StringHelper; @@ -102,8 +100,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { private final ScalarType dateType = new ScalarTypeDate(); - private final ScalarType timestampType = new ScalarTypeTimestamp(); - private final ScalarType inetAddressType = new ScalarTypeInetAddress(); private final ScalarType urlType = new ScalarTypeURL(); private final ScalarType uriType = new ScalarTypeURI(); @@ -115,7 +111,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { private final ScalarType classType = new ScalarTypeClass(); - private final ScalarTypeLongToTimestamp longToTimestamp = new ScalarTypeLongToTimestamp(); private final List> customScalarTypes = new ArrayList>(); @@ -125,6 +120,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { private final ReflectionBasedTypeBuilder reflectScalarBuilder; + private final JsonConfig.DateTime jsonDateTime; + /** * Create the DefaultTypeManager. */ @@ -133,6 +130,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { int clobType = config == null ? Types.CLOB : config.getDatabasePlatform().getClobDbType(); int blobType = config == null ? Types.BLOB : config.getDatabasePlatform().getBlobDbType(); + this.jsonDateTime = config.getJsonDateTime(); this.checkImmutable = new CheckImmutable(this); this.reflectScalarBuilder = new ReflectionBasedTypeBuilder(this); @@ -145,11 +143,12 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { this.extraTypeFactory = new DefaultTypeFactory(config); - initialiseStandard(clobType, blobType, config.isUuidStoreAsBinary()); - initialiseJodaTypes(); + initialiseStandard(jsonDateTime, clobType, blobType, config.isUuidStoreAsBinary()); + initialiseJavaTimeTypes(jsonDateTime, config); + initialiseJodaTypes(jsonDateTime); if (bootupClasses != null) { - initialiseCustomScalarTypes(bootupClasses); + initialiseCustomScalarTypes(jsonDateTime, bootupClasses); initialiseScalarConverters(bootupClasses); initialiseCompoundTypes(bootupClasses); } @@ -311,19 +310,15 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { if (jdbcType == 0 || scalarType.getJdbcType() == jdbcType) { // matching type return (ScalarType) scalarType; - } else { - // sometime like java.util.Date or java.util.Calendar - // that that does not map to the same jdbc type as the - // server wide settings. } } // a util Date with jdbcType not matching server wide settings if (type.equals(java.util.Date.class)) { - return (ScalarType) extraTypeFactory.createUtilDate(jdbcType); + return (ScalarType) extraTypeFactory.createUtilDate(jsonDateTime, jdbcType); } // a Calendar with jdbcType not matching server wide settings if (type.equals(java.util.Calendar.class)) { - return (ScalarType) extraTypeFactory.createCalendar(jdbcType); + return (ScalarType) extraTypeFactory.createCalendar(jsonDateTime, jdbcType); } String msg = "Unmatched ScalarType for " + type + " jdbcType:" + jdbcType; @@ -415,7 +410,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { public ScalarType createEnumScalarType(Class enumType) { // get the mapping information from EnumMapping - EnumMapping enumMapping = (EnumMapping) enumType.getAnnotation(EnumMapping.class); + EnumMapping enumMapping = enumType.getAnnotation(EnumMapping.class); if (enumMapping == null) { // look for EnumValue annotations instead return createEnumScalarType2(enumType); @@ -466,7 +461,9 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { * interface and register it with this TypeManager. *

*/ - protected void initialiseCustomScalarTypes(BootupClasses bootupClasses) { + protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses) { + + ScalarTypeLongToTimestamp longToTimestamp = new ScalarTypeLongToTimestamp(mode); customScalarTypes.add(longToTimestamp); @@ -602,20 +599,48 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { return propParamTypes[1]; } + protected void initialiseJavaTimeTypes(JsonConfig.DateTime mode, ServerConfig config) { + if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) { + logger.debug("Registering java.time data types"); + typeMap.put(java.time.LocalDate.class, new ScalarTypeLocalDate()); + typeMap.put(java.time.LocalDateTime.class, new ScalarTypeLocalDateTime(mode)); + typeMap.put(OffsetDateTime.class, new ScalarTypeOffsetDateTime(mode)); + typeMap.put(ZonedDateTime.class, new ScalarTypeZonedDateTime(mode)); + typeMap.put(Instant.class, new ScalarTypeInstant(mode)); + + typeMap.put(DayOfWeek.class, new ScalarTypeDayOfWeek()); + typeMap.put(Month.class, new ScalarTypeMonth()); + typeMap.put(Year.class, new ScalarTypeYear()); + typeMap.put(YearMonth.class, new ScalarTypeYearMonthDate()); + typeMap.put(MonthDay.class, new ScalarTypeMonthDay()); + typeMap.put(OffsetTime.class, new ScalarTypeOffsetTime()); + typeMap.put(ZoneId.class, new ScalarTypeZoneId()); + typeMap.put(ZoneOffset.class, new ScalarTypeZoneOffset()); + + createCompoundScalarDataReader(Period.class, new CompoundTypePeriod(), ""); + + boolean localTimeNanos = config.isLocalTimeWithNanos(); + typeMap.put(java.time.LocalTime.class, (localTimeNanos)? new ScalarTypeLocalTimeWithNanos() : new ScalarTypeLocalTime()); + + boolean durationNanos = config.isDurationWithNanos(); + typeMap.put(Duration.class, (durationNanos)? new ScalarTypeDurationWithNanos() : new ScalarTypeDuration()); + } + } + /** * Detect if Joda classes are in the classpath and if so register the Joda * data types. */ - protected void initialiseJodaTypes() { + protected void initialiseJodaTypes(JsonConfig.DateTime mode) { // detect if Joda classes are in the classpath if (ClassUtil.isPresent("org.joda.time.LocalDateTime", this.getClass())) { // Joda classes are in the classpath so register the types logger.debug("Registering Joda data types"); - typeMap.put(LocalDateTime.class, new ScalarTypeJodaLocalDateTime()); + typeMap.put(LocalDateTime.class, new ScalarTypeJodaLocalDateTime(mode)); + typeMap.put(DateTime.class, new ScalarTypeJodaDateTime(mode)); typeMap.put(LocalDate.class, new ScalarTypeJodaLocalDate()); typeMap.put(LocalTime.class, new ScalarTypeJodaLocalTime()); - typeMap.put(DateTime.class, new ScalarTypeJodaDateTime()); typeMap.put(DateMidnight.class, new ScalarTypeJodaDateMidnight()); } } @@ -624,12 +649,12 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { * Register all the standard types supported. This is the standard JDBC types * plus some other common types such as java.util.Date and java.util.Calendar. */ - protected void initialiseStandard(int platformClobType, int platformBlobType, boolean binaryUUID) { + protected void initialiseStandard(JsonConfig.DateTime mode, int platformClobType, int platformBlobType, boolean binaryUUID) { - ScalarType utilDateType = extraTypeFactory.createUtilDate(); + ScalarType utilDateType = extraTypeFactory.createUtilDate(mode); typeMap.put(java.util.Date.class, utilDateType); - ScalarType calType = extraTypeFactory.createCalendar(); + ScalarType calType = extraTypeFactory.createCalendar(mode); typeMap.put(Calendar.class, calType); ScalarType mathBigIntType = extraTypeFactory.createMathBigInteger(); @@ -644,8 +669,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { if (booleanType.getJdbcType() == Types.BIT) { // for MapBeans ... BIT types are assumed to be booleans nativeMap.put(Types.BIT, booleanType); - } else { - // boolean mapping to Types.Integer, Types.VARCHAR or Types.Boolean } // Store UUID as binary(16) or varchar(40) @@ -733,6 +756,9 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { nativeMap.put(Types.TIME, timeType); typeMap.put(Date.class, dateType); nativeMap.put(Types.DATE, dateType); + + ScalarType timestampType = new ScalarTypeTimestamp(mode); + typeMap.put(Timestamp.class, timestampType); nativeMap.put(Types.TIMESTAMP, timestampType); diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/EnumToDbIntegerMap.java b/src/main/java/com/avaje/ebeaninternal/server/type/EnumToDbIntegerMap.java index c4f0dbb20..432bfc0cd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/EnumToDbIntegerMap.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/EnumToDbIntegerMap.java @@ -15,7 +15,12 @@ public class EnumToDbIntegerMap extends EnumToDbValueMap { return Types.INTEGER; } - @Override + public EnumToDbIntegerMap add(Object beanValue, Integer dbValue) { + addInternal(beanValue, dbValue); + return this; + } + + @Override public EnumToDbIntegerMap add(Object beanValue, String stringDbValue) { try { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java index c49cfcb00..b59bb38f0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java @@ -162,19 +162,11 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData */ public T parse(String value); - /** - * Convert the systemTimeMillis into the appropriate java object. - *

- * For non dateTime types this will throw an exception. - *

- */ - public T parseDateTime(long dateTime); - /** * Return true if the type can accept long systemTimeMillis input. *

* This is used to determine if is is sensible to use the - * {@link #parseDateTime(long)} method. + * {@link #convertFromMillis(long)} method. *

*

* This includes the Date, Calendar, sql Date, Time, Timestamp, JODA types @@ -184,24 +176,32 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData */ public boolean isDateTimeCapable(); - /** + /** + * Convert the systemTimeMillis into the appropriate java object. + *

+ * For non dateTime types this will throw an exception. + *

+ */ + public T convertFromMillis(long dateTime); + + /** * Read the value from binary input. */ - public Object readData(DataInput dataInput) throws IOException; + public T readData(DataInput dataInput) throws IOException; /** * Write the value to binary output. */ - public void writeData(DataOutput dataOutput, Object v) throws IOException; + public void writeData(DataOutput dataOutput, T v) throws IOException; /** * Read the value from JsonParser. */ - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException; + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException; /** * Write the value to the JsonGenerator. */ - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException; + public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException; } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBase.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBase.java index fddfc4d25..97dcff747 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBase.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBase.java @@ -57,20 +57,6 @@ public abstract class ScalarTypeBase implements ScalarType { return formatValue((T) v); } - /** - * Return true if the value is null. - */ - public boolean isDbNull(Object value) { - return value == null; - } - - /** - * Returns the value that was passed in. - */ - public Object getDbNullValue(Object value) { - return value; - } - public void loadIgnore(DataReader dataReader) { dataReader.incrementPos(1); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java index 5d18df075..7e485192d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java @@ -23,7 +23,7 @@ public abstract class ScalarTypeBaseDate extends ScalarTypeBase { /** * Convert the target value to millis. */ - public abstract long convertToMillis(Object value); + public abstract long convertToMillis(T value); /** * Convert to java.sql.Date from the target Date type. @@ -39,19 +39,14 @@ public abstract class ScalarTypeBaseDate extends ScalarTypeBase { if (value == null) { b.setNull(Types.DATE); } else { - Date date = convertToDate(value); - b.setDate(date); + b.setDate(convertToDate(value)); } } public T read(DataReader dataReader) throws SQLException { Date ts = dataReader.getDate(); - if (ts == null) { - return null; - } else { - return convertFromDate(ts); - } + return ts == null ? null : convertFromDate(ts); } public String formatValue(T t) { @@ -64,7 +59,7 @@ public abstract class ScalarTypeBaseDate extends ScalarTypeBase { return convertFromDate(date); } - public T parseDateTime(long systemTimeMillis) { + public T convertFromMillis(long systemTimeMillis) { Date ts = new Date(systemTimeMillis); return convertFromDate(ts); } @@ -74,20 +69,20 @@ public abstract class ScalarTypeBaseDate extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException { if (JsonToken.VALUE_NUMBER_INT == event) { - return parseDateTime(ctx.getLongValue()); + return convertFromMillis(ctx.getLongValue()); } else { return convertFromDate(Date.valueOf(ctx.getText())); } } - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException { long millis = convertToMillis(value); ctx.writeNumberField(name, millis); } - public Object readData(DataInput dataInput) throws IOException { + public T readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -98,9 +93,8 @@ public abstract class ScalarTypeBaseDate extends ScalarTypeBase { } @SuppressWarnings("unchecked") - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, T value) throws IOException { - T value = (T) v; if (value == null) { dataOutput.writeBoolean(false); } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java index f3f53de1f..a4f02d489 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java @@ -1,39 +1,69 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.config.JsonConfig; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.math.BigDecimal; import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; +import java.time.Instant; /** * Base type for DateTime types. */ public abstract class ScalarTypeBaseDateTime extends ScalarTypeBase { - protected DateTimeJsonParser dateTimeParser = new DateTimeJsonParser(); - - public ScalarTypeBaseDateTime(Class type, boolean jdbcNative, int jdbcType) { + + protected final DateTimeJsonParser dateTimeParser = new DateTimeJsonParser(); + + protected final JsonConfig.DateTime mode; + + public ScalarTypeBaseDateTime(JsonConfig.DateTime mode, Class type, boolean jdbcNative, int jdbcType) { super(type, jdbcNative, jdbcType); + this.mode = mode; } - public abstract long convertToMillis(Object value); - + /** + * Convert the value to a Timestamp. + */ public abstract Timestamp convertToTimestamp(T t); + /** + * Convert to the value from a Timestamp. + */ public abstract T convertFromTimestamp(Timestamp ts); + /** + * Convert from epoch millis to the value. + */ + public abstract T convertFromMillis(long systemTimeMillis); + + /** + * Convert from the value to epoch millis. + */ + public abstract long convertToMillis(T value); + + /** + * Convert the value to time with nanos format. + */ + protected abstract String toJsonNanos(T value); + + /** + * Convert the value to ISO8601 format. + */ + protected abstract String toJsonISO8601(T value); + public void bind(DataBind b, T value) throws SQLException { if (value == null) { b.setNull(Types.TIMESTAMP); } else { - Timestamp ts = convertToTimestamp(value); - b.setTimestamp(ts); + b.setTimestamp(convertToTimestamp(value)); } } @@ -47,23 +77,50 @@ public abstract class ScalarTypeBaseDateTime extends ScalarTypeBase { } } + /** + * Helper method that given epoch seconds and nanos return a JSON nanos formatted string. + */ + protected String toJsonNanos(long epochSecs, int nanos) { + return DecimalUtils.toDecimal(epochSecs, nanos); + } + @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException { - if (JsonToken.VALUE_NUMBER_INT == event) { - long millis = ctx.getLongValue(); - return parseDateTime(millis); - - } else { - String jsonDateTime = ctx.getText(); - return convertFromTimestamp(dateTimeParser.parse(jsonDateTime)); + switch (event) { + case VALUE_NUMBER_INT: { + return convertFromMillis(ctx.getLongValue()); + } + case VALUE_NUMBER_FLOAT: { + BigDecimal value = ctx.getDecimalValue(); + Timestamp timestamp = DecimalUtils.toTimestamp(value); + return convertFromTimestamp(timestamp); + } + default: { + String jsonDateTime = ctx.getText(); + return convertFromTimestamp(dateTimeParser.parse(jsonDateTime)); + } } } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { - long millis = convertToMillis(value); - ctx.writeNumberField(name, millis); + public void jsonWrite(JsonGenerator generator, String name, T value) throws IOException { + + switch (mode) { + case ISO8601: { + generator.writeFieldName(name); + generator.writeString(toJsonISO8601(value)); + break; + } + case NANOS: { + generator.writeFieldName(name); + generator.writeNumber(toJsonNanos(value)); + break; + } + default: { + generator.writeNumberField(name, convertToMillis(value)); + } + } } public String formatValue(T t) { @@ -76,16 +133,12 @@ public abstract class ScalarTypeBaseDateTime extends ScalarTypeBase { return convertFromTimestamp(ts); } - public T parseDateTime(long systemTimeMillis) { - Timestamp ts = new Timestamp(systemTimeMillis); - return convertFromTimestamp(ts); - } public boolean isDateTimeCapable() { return true; } - public Object readData(DataInput dataInput) throws IOException { + public T readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -95,10 +148,8 @@ public abstract class ScalarTypeBaseDateTime extends ScalarTypeBase { } } - @SuppressWarnings("unchecked") - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, T value) throws IOException { - T value = (T) v; if (value == null) { dataOutput.writeBoolean(false); } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java index 0df4a1b06..750400b95 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java @@ -86,7 +86,7 @@ public abstract class ScalarTypeBaseVarchar extends ScalarTypeBase { } @Override - public T parseDateTime(long systemTimeMillis) { + public T convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -102,7 +102,7 @@ public abstract class ScalarTypeBaseVarchar extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public T readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -111,10 +111,8 @@ public abstract class ScalarTypeBaseVarchar extends ScalarTypeBase { } } - @SuppressWarnings("unchecked") - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, T value) throws IOException { - T value = (T) v; if (value == null) { dataOutput.writeBoolean(false); } else { @@ -125,12 +123,12 @@ public abstract class ScalarTypeBaseVarchar extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException { return parse(ctx.getValueAsString()); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException { ctx.writeStringField(name, format(value)); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java index 4aee53063..23d4fad29 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java @@ -17,75 +17,73 @@ import com.fasterxml.jackson.core.JsonToken; */ public class ScalarTypeBigDecimal extends ScalarTypeBase { - public ScalarTypeBigDecimal() { - super(BigDecimal.class, true, Types.DECIMAL); - } - - public Object readData(DataInput dataInput) throws IOException { - if (!dataInput.readBoolean()) { - return null; - } else { - double val = dataInput.readDouble(); - return new BigDecimal(val); - } + public ScalarTypeBigDecimal() { + super(BigDecimal.class, true, Types.DECIMAL); + } + + public BigDecimal readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + double val = dataInput.readDouble(); + return new BigDecimal(val); } + } - public void writeData(DataOutput dataOutput, Object v) throws IOException { - - BigDecimal b = (BigDecimal)v; - if (b == null){ - dataOutput.writeBoolean(false); - } else { - dataOutput.writeBoolean(true); - dataOutput.writeDouble(b.doubleValue()); - } + public void writeData(DataOutput dataOutput, BigDecimal b) throws IOException { + + if (b == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeDouble(b.doubleValue()); } - - public void bind(DataBind b, BigDecimal value) throws SQLException { - if (value == null){ - b.setNull(Types.DECIMAL); - } else { - b.setBigDecimal(value); - } - } + } - public BigDecimal read(DataReader dataReader) throws SQLException { - - return dataReader.getBigDecimal(); - } - - public Object toJdbcType(Object value) { - return BasicTypeConverter.toBigDecimal(value); - } - - public BigDecimal toBeanType(Object value) { - return BasicTypeConverter.toBigDecimal(value); - } - - public String formatValue(BigDecimal t) { - return t.toPlainString(); + public void bind(DataBind b, BigDecimal value) throws SQLException { + if (value == null) { + b.setNull(Types.DECIMAL); + } else { + b.setBigDecimal(value); } + } - public BigDecimal parse(String value) { - return new BigDecimal(value); - } + public BigDecimal read(DataReader dataReader) throws SQLException { - public BigDecimal parseDateTime(long systemTimeMillis) { - return BigDecimal.valueOf(systemTimeMillis); - } + return dataReader.getBigDecimal(); + } - public boolean isDateTimeCapable() { - return true; - } + public Object toJdbcType(Object value) { + return BasicTypeConverter.toBigDecimal(value); + } + + public BigDecimal toBeanType(Object value) { + return BasicTypeConverter.toBigDecimal(value); + } + + public String formatValue(BigDecimal t) { + return t.toPlainString(); + } + + public BigDecimal parse(String value) { + return new BigDecimal(value); + } + + public BigDecimal convertFromMillis(long systemTimeMillis) { + return BigDecimal.valueOf(systemTimeMillis); + } + + public boolean isDateTimeCapable() { + return true; + } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public BigDecimal jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getDecimalValue(); } - - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { - ctx.writeNumberField(name, (BigDecimal)value); + + public void jsonWrite(JsonGenerator ctx, String name, BigDecimal value) throws IOException { + ctx.writeNumberField(name, (BigDecimal) value); } - } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java index 5a9db4c98..67780c3bb 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java @@ -261,7 +261,7 @@ public class ScalarTypeBoolean { return Boolean.valueOf(value); } - public Boolean parseDateTime(long systemTimeMillis) { + public Boolean convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -269,32 +269,30 @@ public class ScalarTypeBoolean { return false; } - public Object readData(DataInput dataInput) throws IOException { + public Boolean readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - boolean val = dataInput.readBoolean(); - return Boolean.valueOf(val); + return dataInput.readBoolean(); } } - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Boolean val) throws IOException { - Boolean val = (Boolean) v; if (val == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeBoolean(val.booleanValue()); + dataOutput.writeBoolean(val); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) { + public Boolean jsonRead(JsonParser ctx, JsonToken event) { return JsonToken.VALUE_TRUE == event ? Boolean.TRUE : Boolean.FALSE; } - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Boolean value) throws IOException { ctx.writeBooleanField(name, (Boolean) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java index f92cccf94..1ac6dfcf2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java @@ -42,12 +42,12 @@ public class ScalarTypeByte extends ScalarTypeBase { } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Byte value) throws IOException { throw new IOException("Not supported"); } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Byte jsonRead(JsonParser ctx, JsonToken event) throws IOException { throw new IOException("Not supported"); } @@ -59,7 +59,7 @@ public class ScalarTypeByte extends ScalarTypeBase { throw new TextException("Not supported"); } - public Byte parseDateTime(long systemTimeMillis) { + public Byte convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -67,18 +67,16 @@ public class ScalarTypeByte extends ScalarTypeBase { return false; } - public Object readData(DataInput dataInput) throws IOException { + public Byte readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - byte val = dataInput.readByte(); - return Byte.valueOf(val); + return dataInput.readByte(); } } - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Byte val) throws IOException { - Byte val = (Byte) v; if (val == null) { dataOutput.writeBoolean(false); } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java index 73d198fbc..2f03c15aa 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java @@ -45,12 +45,12 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, byte[] value) throws IOException { ctx.writeBinaryField(name, (byte[]) value); } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public byte[] jsonRead(JsonParser ctx, JsonToken event) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(500); ctx.readBinaryValue(out); return out.toByteArray(); @@ -64,7 +64,7 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { throw new TextException("Not supported"); } - public byte[] parseDateTime(long systemTimeMillis) { + public byte[] convertFromMillis(long systemTimeMillis) { throw new TextException("Not supported"); } @@ -72,7 +72,7 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { return false; } - public Object readData(DataInput dataInput) throws IOException { + public byte[] readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -83,10 +83,11 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { } } - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, byte[] v) throws IOException { if (v == null) { dataOutput.writeBoolean(false); } else { + dataOutput.writeBoolean(true); byte[] bytes = convertToBytes(v); dataOutput.writeInt(bytes.length); dataOutput.write(bytes); diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java index e2fe6aa48..4dfbc2b1f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java @@ -67,12 +67,12 @@ public class ScalarTypeBytesEncrypted implements ScalarType { } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, byte[] value) throws IOException { ctx.writeBinaryField(name, (byte[]) value); } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public byte[] jsonRead(JsonParser ctx, JsonToken event) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(500); ctx.readBinaryValue(out); return out.toByteArray(); @@ -90,8 +90,8 @@ public class ScalarTypeBytesEncrypted implements ScalarType { return baseType.parse(value); } - public byte[] parseDateTime(long systemTimeMillis) { - return baseType.parseDateTime(systemTimeMillis); + public byte[] convertFromMillis(long systemTimeMillis) { + return baseType.convertFromMillis(systemTimeMillis); } public byte[] read(DataReader dataReader) throws SQLException { @@ -113,17 +113,26 @@ public class ScalarTypeBytesEncrypted implements ScalarType { baseType.accumulateScalarTypes(propName, list); } - public Object readData(DataInput dataInput) throws IOException { - int len = dataInput.readInt(); - byte[] value = new byte[len]; - dataInput.readFully(value); - return value; + public byte[] readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + int len = dataInput.readInt(); + byte[] value = new byte[len]; + dataInput.readFully(value); + return value; + } } - public void writeData(DataOutput dataOutput, Object v) throws IOException { - byte[] value = (byte[]) v; - dataOutput.writeInt(value.length); - dataOutput.write(value); + public void writeData(DataOutput dataOutput, byte[] value) throws IOException { + + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeInt(value.length); + dataOutput.write(value); + } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCalendar.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCalendar.java index ed214945d..ee790cc87 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCalendar.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCalendar.java @@ -6,6 +6,7 @@ import java.sql.Timestamp; import java.sql.Types; import java.util.Calendar; +import com.avaje.ebean.config.JsonConfig; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; /** @@ -13,25 +14,32 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter; */ public class ScalarTypeCalendar extends ScalarTypeBaseDateTime { - public ScalarTypeCalendar(int jdbcType) { - super(Calendar.class, false, jdbcType); + public ScalarTypeCalendar(JsonConfig.DateTime mode, int jdbcType) { + super(mode, Calendar.class, false, jdbcType); } public void bind(DataBind b, Calendar value) throws SQLException { if (value == null) { b.setNull(Types.TIMESTAMP); } else { - Calendar date = (Calendar) value; + if (jdbcType == Types.TIMESTAMP) { - Timestamp timestamp = new Timestamp(date.getTimeInMillis()); + Timestamp timestamp = new Timestamp(value.getTimeInMillis()); b.setTimestamp(timestamp); } else { - Date d = new Date(date.getTimeInMillis()); + Date d = new Date(value.getTimeInMillis()); b.setDate(d); } } } + @Override + public Calendar convertFromMillis(long systemTimeMillis) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(systemTimeMillis); + return calendar; + } + @Override public Calendar convertFromTimestamp(Timestamp ts) { Calendar calendar = Calendar.getInstance(); @@ -40,8 +48,18 @@ public class ScalarTypeCalendar extends ScalarTypeBaseDateTime { } @Override - public long convertToMillis(Object value) { - return ((Calendar) value).getTimeInMillis(); + protected String toJsonNanos(Calendar value) { + return String.valueOf(value.getTime()); + } + + @Override + protected String toJsonISO8601(Calendar value) { + return dateTimeParser.format(value.getTime()); + } + + @Override + public long convertToMillis(Calendar value) { + return value.getTimeInMillis(); } @Override @@ -49,10 +67,12 @@ public class ScalarTypeCalendar extends ScalarTypeBaseDateTime { return new Timestamp(t.getTimeInMillis()); } + @Override public Object toJdbcType(Object value) { return BasicTypeConverter.convert(value, jdbcType); } + @Override public Calendar toBeanType(Object value) { return BasicTypeConverter.toCalendar(value); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCharArray.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCharArray.java index f9e96f15c..ec947202f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCharArray.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCharArray.java @@ -64,11 +64,11 @@ public class ScalarTypeCharArray extends ScalarTypeBaseVarchar { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public char[] jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getValueAsString().toCharArray(); } - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, char[] value) throws IOException { ctx.writeStringField(name, String.valueOf(value)); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDate.java index d9b10644f..21b373007 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDate.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDate.java @@ -16,8 +16,8 @@ public class ScalarTypeDate extends ScalarTypeBaseDate { } @Override - public long convertToMillis(Object value) { - return ((Date) value).getTime(); + public long convertToMillis(Date value) { + return value.getTime(); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDayOfWeek.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDayOfWeek.java new file mode 100644 index 000000000..d1eb890c2 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDayOfWeek.java @@ -0,0 +1,51 @@ +package com.avaje.ebeaninternal.server.type; + +import java.sql.SQLException; +import java.sql.Types; +import java.time.DayOfWeek; + +/** + * ScalarType mapping for Month enum. + */ +public class ScalarTypeDayOfWeek extends ScalarTypeEnumWithMapping { + + static final EnumToDbIntegerMap beanDbMap = new EnumToDbIntegerMap(); + + static { + DayOfWeek[] values = DayOfWeek.values(); + for (DayOfWeek value : values) { + beanDbMap.add(value, value.getValue()); + } + } + + public ScalarTypeDayOfWeek() { + super(beanDbMap, DayOfWeek.class, 1); + } + + /** + * Bind DayOfWeek enum using getValue(). + */ + @Override + public void bind(DataBind b, Object value) throws SQLException { + if (value == null) { + b.setNull(Types.INTEGER); + } else { + // avoiding the map lookup + b.setInt(((DayOfWeek)value).getValue()); + } + } + + /** + * Read DayOfWeek using int value. + */ + @Override + public Object read(DataReader dataReader) throws SQLException { + Integer i = dataReader.getInt(); + if (i == null) { + return null; + } else { + // avoiding the map lookup + return DayOfWeek.of(i); + } + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java index fa27077d4..10b5c97fe 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java @@ -55,7 +55,7 @@ public class ScalarTypeDouble extends ScalarTypeBase { } @Override - public Double parseDateTime(long systemTimeMillis) { + public Double convertFromMillis(long systemTimeMillis) { return Double.valueOf(systemTimeMillis); } @@ -65,34 +65,32 @@ public class ScalarTypeDouble extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public Double readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - double val = dataInput.readDouble(); - return Double.valueOf(val); + return dataInput.readDouble(); } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Double value) throws IOException { - Double value = (Double) v; if (value == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeDouble(value.doubleValue()); + dataOutput.writeDouble(value); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Double jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getDoubleValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { - ctx.writeNumberField(name, (Double) value); + public void jsonWrite(JsonGenerator ctx, String name, Double value) throws IOException { + ctx.writeNumberField(name, value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java new file mode 100644 index 000000000..7e5937b45 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java @@ -0,0 +1,113 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.text.TextException; +import com.avaje.ebeaninternal.server.core.BasicTypeConverter; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.SQLException; +import java.sql.Types; +import java.time.Duration; + +/** + * ScalarType for java.time.Duration (with seconds precision). + */ +public class ScalarTypeDuration extends ScalarTypeBase { + + public ScalarTypeDuration() { + super(Duration.class, false, Types.BIGINT); + } + + protected ScalarTypeDuration(int jdbcType) { + super(Duration.class, false, jdbcType); + } + + public BigDecimal convertToBigDecimal(Duration value) { + return (value == null) ? null : DecimalUtils.toDecimal(value); + } + + public Duration convertFromBigDecimal(BigDecimal value) { + return (value == null) ? null : DecimalUtils.toDuration(value); + } + + @Override + public void bind(DataBind bind, Duration value) throws SQLException { + if (value == null) { + bind.setNull(Types.BIGINT); + } else { + bind.setLong(value.getSeconds()); + } + } + + @Override + public Duration read(DataReader dataReader) throws SQLException { + Long value = dataReader.getLong(); + return (value == null) ? null : Duration.ofSeconds(value); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Long) return value; + return ((Duration)value).getSeconds(); + } + + @Override + public Duration toBeanType(Object value) { + if (value instanceof Duration) return (Duration) value; + return Duration.ofSeconds(BasicTypeConverter.toLong(value)); + } + + @Override + public Duration readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + return convertFromBigDecimal(new BigDecimal(dataInput.readUTF())); + } + } + + @Override + public void writeData(DataOutput dataOutput, Duration value) throws IOException { + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeUTF(convertToBigDecimal(value).toString()); + } + } + + @Override + public String formatValue(Duration v) { + return v.toString(); + } + + @Override + public Duration parse(String value) { + return Duration.parse(value); + } + + @Override + public boolean isDateTimeCapable() { + return false; + } + + @Override + public Duration convertFromMillis(long systemTimeMillis) { + throw new TextException("Not Supported"); + } + + @Override + public Duration jsonRead(JsonParser ctx, JsonToken event) throws IOException { + return Duration.parse(ctx.getValueAsString()); + } + + @Override + public void jsonWrite(JsonGenerator ctx, String name, Duration value) throws IOException { + ctx.writeStringField(name, value.toString()); + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDurationWithNanos.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDurationWithNanos.java new file mode 100644 index 000000000..1ff246375 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDurationWithNanos.java @@ -0,0 +1,55 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.text.TextException; +import com.avaje.ebeaninternal.server.core.BasicTypeConverter; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.SQLException; +import java.sql.Types; +import java.time.Duration; + +/** + * ScalarType for java.time.Duration (with Nanos precision). + *

+ * Stored in the DB as DECIMAL value. + *

+ */ +public class ScalarTypeDurationWithNanos extends ScalarTypeDuration { + + public ScalarTypeDurationWithNanos() { + super(Types.DECIMAL); + } + + @Override + public void bind(DataBind bind, Duration value) throws SQLException { + if (value == null) { + bind.setNull(Types.DECIMAL); + } else { + bind.setBigDecimal(convertToBigDecimal(value)); + } + } + + @Override + public Duration read(DataReader dataReader) throws SQLException { + return convertFromBigDecimal(dataReader.getBigDecimal()); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof BigDecimal) return value; + return convertToBigDecimal((Duration)value); + } + + @Override + public Duration toBeanType(Object value) { + if (value instanceof Duration) return (Duration) value; + return convertFromBigDecimal(BasicTypeConverter.toBigDecimal(value)); + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java index 9c3eeccdf..041fd9471 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java @@ -34,12 +34,12 @@ public class ScalarTypeEncryptedWrapper implements ScalarType { } @Override - public Object readData(DataInput dataInput) throws IOException { + public T readData(DataInput dataInput) throws IOException { return wrapped.readData(dataInput); } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, T v) throws IOException { wrapped.writeData(dataOutput, v); } @@ -113,8 +113,8 @@ public class ScalarTypeEncryptedWrapper implements ScalarType { } @Override - public T parseDateTime(long systemTimeMillis) { - return wrapped.parseDateTime(systemTimeMillis); + public T convertFromMillis(long systemTimeMillis) { + return wrapped.convertFromMillis(systemTimeMillis); } @Override @@ -133,12 +133,12 @@ public class ScalarTypeEncryptedWrapper implements ScalarType { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException { return wrapped.jsonRead(ctx, event); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException { wrapped.jsonWrite(ctx, name, value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnum.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnum.java index 1e279ee1d..f9479adcd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnum.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnum.java @@ -8,6 +8,6 @@ public interface ScalarTypeEnum { /** * Return the IN values for DB constraint construction. */ - public String getContraintInValues(); + public String getConstraintInValues(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java index 6fdfb1e72..b8e7014b5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java @@ -41,7 +41,7 @@ public class ScalarTypeEnumStandard { /** * Return the IN values for DB constraint construction. */ - public String getContraintInValues() { + public String getConstraintInValues() { StringBuilder sb = new StringBuilder(); @@ -101,7 +101,7 @@ public class ScalarTypeEnumStandard { if (beanValue == null) { return null; } - return ((Enum) beanValue).toString(); + return beanValue.toString(); } public Object toBeanType(Object dbValue) { @@ -129,7 +129,7 @@ public class ScalarTypeEnumStandard { /** * Return the IN values for DB constraint construction. */ - public String getContraintInValues() { + public String getConstraintInValues() { StringBuilder sb = new StringBuilder(); @@ -186,7 +186,7 @@ public class ScalarTypeEnumStandard { return dbValue; } - int ordinal = ((Integer) dbValue).intValue(); + int ordinal = (Integer) dbValue; if (ordinal < 0 || ordinal >= enumArray.length) { String m = "Unexpected ordinal [" + ordinal + "] out of range [" + enumArray.length + "]"; throw new IllegalStateException(m); @@ -222,7 +222,7 @@ public class ScalarTypeEnumStandard { } @Override - public Object parseDateTime(long systemTimeMillis) { + public Object convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java index dc97c9f56..a7f26f86e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java @@ -25,7 +25,7 @@ public class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase i /** * Return the IN values for DB constraint construction. */ - public String getContraintInValues() { + public String getConstraintInValues() { StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java index 7fee93bd7..96807eab4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java @@ -55,7 +55,7 @@ public class ScalarTypeFloat extends ScalarTypeBase { } @Override - public Float parseDateTime(long systemTimeMillis) { + public Float convertFromMillis(long systemTimeMillis) { return Float.valueOf(systemTimeMillis); } @@ -65,7 +65,7 @@ public class ScalarTypeFloat extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public Float readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -75,24 +75,23 @@ public class ScalarTypeFloat extends ScalarTypeBase { } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Float value) throws IOException { - Float value = (Float) v; if (value == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeFloat(value.floatValue()); + dataOutput.writeFloat(value); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Float jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getFloatValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Float value) throws IOException { ctx.writeNumberField(name, (Float) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInstant.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInstant.java new file mode 100644 index 000000000..00997022d --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInstant.java @@ -0,0 +1,59 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.config.JsonConfig; + +import java.sql.Timestamp; +import java.sql.Types; +import java.time.Instant; + +/** + * ScalarType for java.sql.Timestamp. + */ +public class ScalarTypeInstant extends ScalarTypeBaseDateTime { + + public ScalarTypeInstant(JsonConfig.DateTime mode) { + super(mode, Instant.class, true, Types.TIMESTAMP); + } + + @Override + protected String toJsonNanos(Instant value) { + return toJsonNanos(value.getEpochSecond(), value.getNano()); + } + + @Override + protected String toJsonISO8601(Instant value) { + return value.toString(); + } + + @Override + public long convertToMillis(Instant value) { + return value.toEpochMilli(); + } + + @Override + public Instant convertFromMillis(long systemTimeMillis) { + return Instant.ofEpochMilli(systemTimeMillis); + } + + @Override + public Instant convertFromTimestamp(Timestamp ts) { + return ts.toInstant(); + } + + @Override + public Timestamp convertToTimestamp(Instant t) { + return Timestamp.from(t); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Timestamp) return value; + return convertToTimestamp((Instant) value); + } + + @Override + public Instant toBeanType(Object value) { + if (value instanceof Instant) return (Instant) value; + return convertFromTimestamp((Timestamp) value); + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java index 101e84a6c..3199fb609 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java @@ -36,13 +36,22 @@ public class ScalarTypeInteger extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { - return Integer.valueOf(dataInput.readInt()); + public Integer readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + return Integer.valueOf(dataInput.readInt()); + } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { - dataOutput.writeInt((Integer) v); + public void writeData(DataOutput dataOutput, Integer value) throws IOException { + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeInt(value); + } } @Override @@ -66,7 +75,7 @@ public class ScalarTypeInteger extends ScalarTypeBase { } @Override - public Integer parseDateTime(long systemTimeMillis) { + public Integer convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -76,12 +85,12 @@ public class ScalarTypeInteger extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Integer jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getIntValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { - ctx.writeNumberField(name, (Integer) value); + public void jsonWrite(JsonGenerator ctx, String name, Integer value) throws IOException { + ctx.writeNumberField(name, value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateMidnight.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateMidnight.java index bc3514f4f..244b8c127 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateMidnight.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateMidnight.java @@ -20,8 +20,8 @@ public class ScalarTypeJodaDateMidnight extends ScalarTypeBaseDate } @Override - public long convertToMillis(Object value) { - return ((DateMidnight) value).getMillis(); + public long convertToMillis(DateMidnight value) { + return value.getMillis(); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateTime.java index 5df0cf9b4..9f0d5de86 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateTime.java @@ -3,22 +3,39 @@ package com.avaje.ebeaninternal.server.type; import java.sql.Timestamp; import java.sql.Types; +import com.avaje.ebean.config.JsonConfig; import org.joda.time.DateTime; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; +import org.joda.time.LocalDateTime; /** * ScalarType for Joda DateTime. This maps to a JDBC Timestamp. */ public class ScalarTypeJodaDateTime extends ScalarTypeBaseDateTime { - public ScalarTypeJodaDateTime() { - super(DateTime.class, false, Types.TIMESTAMP); + public ScalarTypeJodaDateTime(JsonConfig.DateTime mode) { + super(mode, DateTime.class, false, Types.TIMESTAMP); } @Override - public long convertToMillis(Object value) { - return ((DateTime) value).getMillis(); + public long convertToMillis(DateTime value) { + return value.getMillis(); + } + + @Override + protected String toJsonNanos(DateTime value) { + return String.valueOf(value.toDateTime().getMillis()); + } + + @Override + protected String toJsonISO8601(DateTime value) { + return value.toString(); + } + + @Override + public DateTime convertFromMillis(long systemTimeMillis) { + return new DateTime(systemTimeMillis); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java index 1fe6822dd..f06639ec4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java @@ -17,8 +17,8 @@ public class ScalarTypeJodaLocalDate extends ScalarTypeBaseDate { } @Override - public long convertToMillis(Object value) { - return ((LocalDate) value).toDateMidnight().getMillis(); + public long convertToMillis(LocalDate value) { + return value.toDateMidnight().getMillis(); } @Override @@ -48,7 +48,7 @@ public class ScalarTypeJodaLocalDate extends ScalarTypeBaseDate { } @Override - public LocalDate parseDateTime(long systemTimeMillis) { + public LocalDate convertFromMillis(long systemTimeMillis) { return new LocalDate(systemTimeMillis); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTime.java index d139a5da2..8f4c57745 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTime.java @@ -2,7 +2,9 @@ package com.avaje.ebeaninternal.server.type; import java.sql.Timestamp; import java.sql.Types; +import java.util.Date; +import com.avaje.ebean.config.JsonConfig; import org.joda.time.LocalDateTime; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; @@ -12,13 +14,29 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter; */ public class ScalarTypeJodaLocalDateTime extends ScalarTypeBaseDateTime { - public ScalarTypeJodaLocalDateTime() { - super(LocalDateTime.class, false, Types.TIMESTAMP); + public ScalarTypeJodaLocalDateTime(JsonConfig.DateTime mode) { + super(mode, LocalDateTime.class, false, Types.TIMESTAMP); } @Override - public long convertToMillis(Object value) { - return ((LocalDateTime) value).toDateTime().getMillis(); + protected String toJsonNanos(LocalDateTime value) { + return String.valueOf(value.toDateTime().getMillis()); + } + + @Override + protected String toJsonISO8601(LocalDateTime value) { + return value.toString(); + } + + @Override + public long convertToMillis(LocalDateTime value) { + return value.toDateTime().getMillis(); + } + + + @Override + public LocalDateTime convertFromMillis(long systemTimeMillis) { + return new LocalDateTime(systemTimeMillis); } @Override @@ -47,9 +65,4 @@ public class ScalarTypeJodaLocalDateTime extends ScalarTypeBaseDateTime { } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, LocalTime value) throws IOException { ctx.writeStringField(name, value.toString()); } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public LocalTime jsonRead(JsonParser ctx, JsonToken event) throws IOException { if (JsonToken.VALUE_NUMBER_INT == event) { long millis = ctx.getLongValue(); - return parseDateTime(millis); + return convertFromMillis(millis); } else { String string = ctx.getValueAsString(); throw new RuntimeException("convert " + string); @@ -88,7 +88,7 @@ public class ScalarTypeJodaLocalTime extends ScalarTypeBase { } @Override - public LocalTime parseDateTime(long systemTimeMillis) { + public LocalTime convertFromMillis(long systemTimeMillis) { return new LocalTime(systemTimeMillis); } @@ -98,7 +98,7 @@ public class ScalarTypeJodaLocalTime extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public LocalTime readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -108,9 +108,8 @@ public class ScalarTypeJodaLocalTime extends ScalarTypeBase { } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, LocalTime value) throws IOException { - Time value = (Time) v; if (value == null) { dataOutput.writeBoolean(false); } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java new file mode 100644 index 000000000..5ffef6b3f --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java @@ -0,0 +1,59 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebeaninternal.server.core.BasicTypeConverter; + +import java.sql.Date; +import java.sql.Timestamp; +import java.sql.Types; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +/** + * ScalarType for java.time.LocalDate. This maps to a JDBC Date. + */ +public class ScalarTypeLocalDate extends ScalarTypeBaseDate { + + public ScalarTypeLocalDate() { + super(LocalDate.class, false, Types.DATE); + } + + @Override + public long convertToMillis(LocalDate value) { + ZonedDateTime zonedDateTime = value.atStartOfDay(ZoneId.systemDefault()); + return zonedDateTime.toInstant().toEpochMilli(); + } + + @Override + public LocalDate convertFromDate(Date ts) { + return ts.toLocalDate(); + } + + @Override + public Date convertToDate(LocalDate t) { + return Date.valueOf(t); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof LocalDate) { + return Date.valueOf((LocalDate) value); + } + return BasicTypeConverter.toDate(value); + } + + @Override + public LocalDate toBeanType(Object value) { + if (value instanceof java.sql.Date) { + return ((java.sql.Date) value).toLocalDate(); + } + return (LocalDate) value; + } + + @Override + public LocalDate convertFromMillis(long systemTimeMillis) { + return new Timestamp(systemTimeMillis).toLocalDateTime().toLocalDate(); + } + + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java new file mode 100644 index 000000000..b0452f95e --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java @@ -0,0 +1,64 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.config.JsonConfig; + +import java.sql.Timestamp; +import java.sql.Types; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +/** + * ScalarType for java.sql.Timestamp. + */ +public class ScalarTypeLocalDateTime extends ScalarTypeBaseDateTime { + + public ScalarTypeLocalDateTime(JsonConfig.DateTime mode) { + super(mode, LocalDateTime.class, true, Types.TIMESTAMP); + } + + @Override + public LocalDateTime convertFromMillis(long systemTimeMillis) { + return new Timestamp(systemTimeMillis).toLocalDateTime(); + } + + @Override + public long convertToMillis(LocalDateTime value) { + return value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + } + + @Override + protected String toJsonNanos(LocalDateTime value) { + return String.valueOf(convertToMillis(value)); + } + + @Override + protected String toJsonISO8601(LocalDateTime value) { + return value.atZone(ZoneId.systemDefault()).toInstant().toString(); + } + + @Override + public LocalDateTime convertFromTimestamp(Timestamp ts) { + return ts.toLocalDateTime(); + } + + @Override + public Timestamp convertToTimestamp(LocalDateTime t) { + + ZonedDateTime zonedDateTime = t.atZone(ZoneId.systemDefault()); + return Timestamp.from(zonedDateTime.toInstant()); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Timestamp) return value; + return convertToTimestamp((LocalDateTime)value); + } + + @Override + public LocalDateTime toBeanType(Object value) { + if (value instanceof LocalDateTime) return (LocalDateTime)value; + return convertFromTimestamp((Timestamp)value); + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java new file mode 100644 index 000000000..40a45f0a3 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java @@ -0,0 +1,105 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.text.TextException; +import com.avaje.ebeaninternal.server.core.BasicTypeConverter; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Types; +import java.time.LocalTime; + +/** + * ScalarType for java.time.LocalTime stored as JDBC Time. + */ +public class ScalarTypeLocalTime extends ScalarTypeBase { + + public ScalarTypeLocalTime() { + super(LocalTime.class, false, Types.TIME); + } + + protected ScalarTypeLocalTime(int jdbcTtype) { + super(LocalTime.class, false, jdbcTtype); + } + + @Override + public void bind(DataBind bind, LocalTime value) throws SQLException { + if (value == null) { + bind.setNull(Types.TIME); + } else { + bind.setTime(Time.valueOf(value)); + } + } + + @Override + public LocalTime read(DataReader dataReader) throws SQLException { + Time time = dataReader.getTime(); + return (time == null) ? null : time.toLocalTime(); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Time) return value; + return Time.valueOf((LocalTime)value); + } + + @Override + public LocalTime toBeanType(Object value) { + if (value instanceof LocalTime) return (LocalTime) value; + return BasicTypeConverter.toTime(value).toLocalTime(); + } + + @Override + public LocalTime readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + return LocalTime.ofNanoOfDay(dataInput.readLong()); + } + } + + @Override + public void writeData(DataOutput dataOutput, LocalTime value) throws IOException { + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeLong(value.toNanoOfDay()); + } + } + + @Override + public String formatValue(LocalTime v) { + return v.toString(); + } + + @Override + public LocalTime parse(String value) { + return LocalTime.parse(value); + } + + @Override + public boolean isDateTimeCapable() { + return false; + } + + @Override + public LocalTime convertFromMillis(long systemTimeMillis) { + throw new TextException("Not Supported"); + } + + @Override + public LocalTime jsonRead(JsonParser ctx, JsonToken event) throws IOException { + return LocalTime.parse(ctx.getValueAsString()); + } + + @Override + public void jsonWrite(JsonGenerator ctx, String name, LocalTime value) throws IOException { + ctx.writeStringField(name, value.toString()); + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTimeWithNanos.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTimeWithNanos.java new file mode 100644 index 000000000..d72f36222 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTimeWithNanos.java @@ -0,0 +1,45 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebeaninternal.server.core.BasicTypeConverter; + +import java.sql.SQLException; +import java.sql.Types; +import java.time.LocalTime; + +/** + * ScalarType for java.time.LocalTime stored with Nanos as DB BIGINT type. + */ +public class ScalarTypeLocalTimeWithNanos extends ScalarTypeLocalTime { + + public ScalarTypeLocalTimeWithNanos() { + super(Types.BIGINT); + } + + @Override + public void bind(DataBind bind, LocalTime value) throws SQLException { + if (value == null) { + bind.setNull(Types.BIGINT); + } else { + bind.setLong(value.toNanoOfDay()); + } + } + + @Override + public LocalTime read(DataReader dataReader) throws SQLException { + Long value = dataReader.getLong(); + return (value == null) ? null : LocalTime.ofNanoOfDay(value); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Long) return value; + return ((LocalTime)value).toNanoOfDay(); + } + + @Override + public LocalTime toBeanType(Object value) { + if (value instanceof LocalTime) return (LocalTime) value; + return LocalTime.ofNanoOfDay(BasicTypeConverter.toLong(value)); + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java index 1427553b4..1bf541144 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java @@ -55,8 +55,8 @@ public class ScalarTypeLong extends ScalarTypeBase { } @Override - public Long parseDateTime(long systemTimeMillis) { - return Long.valueOf(systemTimeMillis); + public Long convertFromMillis(long systemTimeMillis) { + return systemTimeMillis; } @Override @@ -65,34 +65,32 @@ public class ScalarTypeLong extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public Long readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - long val = dataInput.readLong(); - return Long.valueOf(val); + return dataInput.readLong(); } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Long value) throws IOException { - Long value = (Long) v; if (value == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeLong(value.longValue()); + dataOutput.writeLong(value); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Long jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getLongValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Long value) throws IOException { ctx.writeNumberField(name, (Long) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLongToTimestamp.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLongToTimestamp.java index d01d67469..7a9b119d2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLongToTimestamp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLongToTimestamp.java @@ -1,10 +1,12 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.config.JsonConfig; + import java.sql.Timestamp; public class ScalarTypeLongToTimestamp extends ScalarTypeWrapper { - public ScalarTypeLongToTimestamp() { - super(Long.class, new ScalarTypeTimestamp(), new LongToTimestampConverter()); + public ScalarTypeLongToTimestamp(JsonConfig.DateTime mode) { + super(Long.class, new ScalarTypeTimestamp(mode), new LongToTimestampConverter()); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java index 1ea865e7a..521462b65 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java @@ -3,9 +3,11 @@ package com.avaje.ebeaninternal.server.type; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.math.BigDecimal; import java.math.BigInteger; import java.sql.SQLException; import java.sql.Types; +import java.time.Instant; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonGenerator; @@ -61,7 +63,7 @@ public class ScalarTypeMathBigInteger extends ScalarTypeBase { } @Override - public BigInteger parseDateTime(long systemTimeMillis) { + public BigInteger convertFromMillis(long systemTimeMillis) { return BigInteger.valueOf(systemTimeMillis); } @@ -71,19 +73,18 @@ public class ScalarTypeMathBigInteger extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public BigInteger readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { long val = dataInput.readLong(); - return Long.valueOf(val); + return BigInteger.valueOf(val); } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, BigInteger value) throws IOException { - Long value = (Long) v; if (value == null) { dataOutput.writeBoolean(false); } else { @@ -93,12 +94,12 @@ public class ScalarTypeMathBigInteger extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public BigInteger jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getDecimalValue().toBigInteger(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, BigInteger value) throws IOException { ctx.writeNumberField(name, ((BigInteger) value).longValue()); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonth.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonth.java new file mode 100644 index 000000000..e6f65417c --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonth.java @@ -0,0 +1,51 @@ +package com.avaje.ebeaninternal.server.type; + +import java.sql.SQLException; +import java.sql.Types; +import java.time.Month; + +/** + * ScalarType mapping for Month enum. + */ +public class ScalarTypeMonth extends ScalarTypeEnumWithMapping { + + static final EnumToDbIntegerMap beanDbMap = new EnumToDbIntegerMap(); + + static { + Month[] values = Month.values(); + for (Month value : values) { + beanDbMap.add(value, value.getValue()); + } + } + + public ScalarTypeMonth() { + super(beanDbMap, Month.class, 1); + } + + /** + * Bind Month enum value. + */ + @Override + public void bind(DataBind b, Object value) throws SQLException { + if (value == null) { + b.setNull(Types.INTEGER); + } else { + // avoiding the map lookup + b.setInt(((Month)value).getValue()); + } + } + + /** + * Read Month enum from integer. + */ + @Override + public Object read(DataReader dataReader) throws SQLException { + Integer i = dataReader.getInt(); + if (i == null) { + return null; + } else { + // avoiding the map lookup + return Month.of(i); + } + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonthDay.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonthDay.java new file mode 100644 index 000000000..417f80bc2 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMonthDay.java @@ -0,0 +1,132 @@ +package com.avaje.ebeaninternal.server.type; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.sql.Date; +import java.sql.SQLException; +import java.sql.Types; +import java.time.LocalDate; +import java.time.MonthDay; + +/** + * ScalarType for MonthDay stored as a SQL Date using a fixed year. + *

+ * Note that the year used should be a leap year. + *

+ */ +public class ScalarTypeMonthDay extends ScalarTypeBase { + + protected int year; + + /** + * Construct with a year of 2000 (which is a leap year). + */ + public ScalarTypeMonthDay() { + this(2000); // Year 2000 is a leap year + } + + /** + * Construct with a base year. The year should be a leap year to + * allow the 29th Feb value. + */ + public ScalarTypeMonthDay(int year) { + super(MonthDay.class, false, Types.DATE); + this.year = year; + } + + private MonthDay convertFromDate(Date ts) { + LocalDate localDate = ts.toLocalDate(); + return MonthDay.of(localDate.getMonthValue(), localDate.getDayOfMonth()); + } + + private Date convertToDate(MonthDay value) { + return Date.valueOf(LocalDate.of(2000, value.getMonthValue(), value.getDayOfMonth())); + } + + @Override + public MonthDay read(DataReader dataReader) throws SQLException { + Date ts = dataReader.getDate(); + return ts == null ? null : convertFromDate(ts); + } + + + @Override + public void bind(DataBind b, MonthDay value) throws SQLException { + if (value == null) { + b.setNull(Types.DATE); + } else { + b.setDate(convertToDate(value)); + } + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Date) return value; + return convertToDate((MonthDay) value); + } + + @Override + public MonthDay toBeanType(Object value) { + if (value instanceof MonthDay) return (MonthDay) value; + return convertFromDate((Date) value); + } + + @Override + public String formatValue(MonthDay value) { + return value.toString(); + } + + @Override + public MonthDay parse(String value) { + return MonthDay.parse(value); + } + + @Override + public boolean isDateTimeCapable() { + return false; + } + + @Override + public MonthDay convertFromMillis(long dateTime) { + throw new RuntimeException("Not supported on this type"); + } + + @Override + public MonthDay readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + int month = dataInput.readInt(); + int day = dataInput.readInt(); + return MonthDay.of(month, day); + } + } + + @Override + public void writeData(DataOutput dataOutput, MonthDay value) throws IOException { + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.write(value.getMonthValue()); + dataOutput.write(value.getDayOfMonth()); + } + } + + @Override + public MonthDay jsonRead(JsonParser ctx, JsonToken event) throws IOException { + return parse(ctx.getValueAsString()); + } + + @Override + public void jsonWrite(JsonGenerator ctx, String name, MonthDay value) throws IOException { + ctx.writeStringField(name, format(value)); + } + + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java new file mode 100644 index 000000000..7071f52cc --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java @@ -0,0 +1,61 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.config.JsonConfig; + +import java.sql.Timestamp; +import java.sql.Types; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; + +/** + * ScalarType for java.sql.Timestamp. + */ +public class ScalarTypeOffsetDateTime extends ScalarTypeBaseDateTime { + + public ScalarTypeOffsetDateTime(JsonConfig.DateTime mode) { + super(mode, OffsetDateTime.class, true, Types.TIMESTAMP); + } + + @Override + protected String toJsonNanos(OffsetDateTime value) { + return toJsonNanos(value.toEpochSecond(), value.getNano()); + } + + @Override + protected String toJsonISO8601(OffsetDateTime value) { + return value.toInstant().toString(); + } + + @Override + public long convertToMillis(OffsetDateTime value) { + return value.toInstant().toEpochMilli(); + } + + @Override + public OffsetDateTime convertFromMillis(long systemTimeMillis) { + return OffsetDateTime.ofInstant(Instant.ofEpochMilli(systemTimeMillis), ZoneId.systemDefault()); + } + + @Override + public OffsetDateTime convertFromTimestamp(Timestamp ts) { + return OffsetDateTime.ofInstant(ts.toInstant(), ZoneId.systemDefault()); + } + + @Override + public Timestamp convertToTimestamp(OffsetDateTime t) { + return Timestamp.from(t.toInstant()); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Timestamp) return value; + return convertToTimestamp((OffsetDateTime)value); + } + + @Override + public OffsetDateTime toBeanType(Object value) { + if (value instanceof OffsetDateTime) return (OffsetDateTime) value; + return convertFromTimestamp((Timestamp)value); + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetTime.java new file mode 100644 index 000000000..b36d8c553 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetTime.java @@ -0,0 +1,39 @@ +package com.avaje.ebeaninternal.server.type; + +import java.time.OffsetTime; + +/** + * ScalarType for java.time.OffsetTime stored as DB VARCHAR + */ +public class ScalarTypeOffsetTime extends ScalarTypeBaseVarchar { + + public ScalarTypeOffsetTime() { + super(OffsetTime.class); + } + + @Override + public int getLength() { + return 25; + } + + @Override + public String formatValue(OffsetTime v) { + return v.toString(); + } + + @Override + public OffsetTime parse(String value) { + return OffsetTime.parse(value); + } + + @Override + public OffsetTime convertFromDbString(String dbValue) { + return OffsetTime.parse(dbValue); + } + + @Override + public String convertToDbString(OffsetTime beanValue) { + return beanValue.toString(); + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java index 847f5fc4b..7b8a0e4c8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java @@ -88,7 +88,7 @@ public class ScalarTypePostgresHstore extends ScalarTypeBase { } @Override - public Map parseDateTime(long dateTime) { + public Map convertFromMillis(long dateTime) { throw new RuntimeException("Should never be called"); } @@ -98,19 +98,28 @@ public class ScalarTypePostgresHstore extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { - String json = dataInput.readUTF(); - return parse(json); + public Map readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + String json = dataInput.readUTF(); + return parse(json); + } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { - String json = format(v); - dataOutput.writeUTF(json); + public void writeData(DataOutput dataOutput, Map v) throws IOException { + if (v == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + String json = format(v); + dataOutput.writeUTF(json); + } } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Map value) throws IOException { // write the field name followed by the Map/JSON Object if (value == null) { ctx.writeNullField(name); @@ -121,7 +130,7 @@ public class ScalarTypePostgresHstore extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Map jsonRead(JsonParser ctx, JsonToken event) throws IOException { // at this point the BeanProperty has read the START_OBJECT token // to check for a null value. Pass the START_OBJECT token through to // the EJson parsing so that it knows the first token has been read diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java index 6d6245897..9c9871251 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java @@ -56,7 +56,7 @@ public class ScalarTypeShort extends ScalarTypeBase { } @Override - public Short parseDateTime(long systemTimeMillis) { + public Short convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -66,34 +66,32 @@ public class ScalarTypeShort extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public Short readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - short val = dataInput.readShort(); - return Short.valueOf(val); + return dataInput.readShort(); } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Short value) throws IOException { - Short value = (Short) v; if (value == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeShort(value.shortValue()); + dataOutput.writeShort(value); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Short jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getShortValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Short value) throws IOException { ctx.writeNumberField(name, (Short) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java index a66153e74..9584d26a7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java @@ -55,7 +55,7 @@ public class ScalarTypeString extends ScalarTypeBase { } @Override - public String parseDateTime(long systemTimeMillis) { + public String convertFromMillis(long systemTimeMillis) { return String.valueOf(systemTimeMillis); } @@ -65,7 +65,7 @@ public class ScalarTypeString extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public String readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -74,9 +74,8 @@ public class ScalarTypeString extends ScalarTypeBase { } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, String value) throws IOException { - String value = (String) v; if (value == null) { dataOutput.writeBoolean(false); } else { @@ -86,12 +85,12 @@ public class ScalarTypeString extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public String jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getValueAsString(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, String value) throws IOException { ctx.writeStringField(name, (String) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java index 5568ff179..955430f65 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java @@ -56,7 +56,7 @@ public class ScalarTypeTime extends ScalarTypeBase