Compare commits

...
Author SHA1 Message Date
rbygrave 5e68b1a25e [maven-release-plugin] prepare release avaje-ebeanorm-4.7.1 2015-06-17 23:18:36 +12:00
rbygrave 041324d177 #310 - Child bean with @Id long id = 0 ... when cascade saved from parent ... tries to update instead of insert resulting in OptimisticLockingException 2015-06-17 23:16:02 +12:00
rbygrave 7d02a42276 #309 - ScalarTypeConverters for Java8 time datatypes not working 2015-06-17 21:13:48 +12:00
rbygrave 2a900165f0 #305 - ENH: Add EbeanServerFactory.createWithContextClassLoader() to support OSGi 2015-06-03 20:47:58 +12:00
rbygrave e7c40e9552 No effective change - update javadoc on annotations 2015-06-01 12:26:59 +12:00
rbygrave 0d92807308 No effective change - change test code to use Long as @Version on BasicDomain 2015-06-01 12:14:20 +12:00
rbygrave 16f7de30c6 No effective change - format code 2015-06-01 12:11:53 +12:00
rbygrave 3d250b0eca No effective change - format code, tidy 2015-05-30 21:42:50 +12:00
rbygrave 8403adac90 #298 - JndiDataSourceLookup assumes java: prefix 2015-05-30 20:54:51 +12:00
rbygrave c006aa3f48 No effective change - inline String messages 2015-05-30 20:54:12 +12:00
rbygrave dcb7054248 #303 - Change beginTransaction() to use REQUIRED scope by default 2015-05-30 20:10:56 +12:00
rbygrave 12833bc918 Bump pom version to 4.7.1-SNAPSHOT 2015-05-30 19:43:15 +12:00
rbygrave 71d805bc17 #302 - Postgres specific - Rename @ColumnHstore to @DbHstore (deprecate @ColumnHstore ) 2015-05-30 19:41:54 +12:00
rbygrave ab8704e2c9 Bump version in README 2015-05-29 21:52:43 +12:00
rbygrave 327e2baae7 No effective change - format only 2015-05-29 21:52:00 +12:00
rbygrave 6e89c551d5 [maven-release-plugin] prepare for next development iteration 2015-05-29 21:17:29 +12:00
rbygrave 0a3941227f [maven-release-plugin] prepare release avaje-ebeanorm-4.6.3 2015-05-29 21:17:08 +12:00
rbygrave 0013cb1a76 #301 - MySQL specific issue - java.sql.SQLException: Streaming result set com.mysql.jdbc.RowDataDynamic@3ef4415f is still active. No statements may be issued when any streaming result sets a re open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries 2015-05-29 21:13:30 +12:00
rbygrave 8fe91f66c0 #300 - Stateless update with deleteMissingChildren and JDBC batched inserts on those children ... can delete newly inserted child 2015-05-29 20:51:23 +12:00
rbygrave 053fdf4abb No effective change - format and tidy 2015-05-29 20:49:55 +12:00
rbygrave 24be907dc5 No effective change - improved logging when PooledConnection.close() throws exception 2015-05-29 20:39:54 +12:00
rbygrave 6aa915b420 Fix test for cross database use 2015-05-29 20:38:38 +12:00
rbygrave 40d87af5b1 Fix test for cross database use 2015-05-29 20:38:07 +12:00
rbygrave 75082fe0c0 Fix test for cross database use 2015-05-29 20:37:12 +12:00
rbygrave 7d43f5a3d7 Fix test for cross database use 2015-05-29 20:36:51 +12:00
rbygrave 99203a35a2 No effective change - reformat and tidy 2015-05-29 00:40:47 +12:00
rbygrave 67f427b83e #299 - ENH: Add support for mapping Jackson JsonNode as JSON content to DB including Postgres JSON and JSON types 2015-05-28 22:54:32 +12:00
rbygrave f5a2cf8ff9 #297 - ENH: Add support for mapping Map<String,Object> as JSON content to DB including Postgres JSON and JSON types. 2015-05-28 00:02:57 +12:00
rbygrave 4e1cda691f No effective change - reformat and tidy 2015-05-19 01:35:27 +12:00
rbygrave 64b01324d1 No effective change - reformat and tidy 2015-05-19 01:25:51 +12:00
rbygrave 3cba238073 No effective change - reformat and tidy 2015-05-18 23:23:11 +12:00
rbygrave b5b4a4639f No effective change - reformat and tidy 2015-05-18 22:17:28 +12:00
rbygrave 2d0a179c3b No effective change - reformat and tidy 2015-05-15 00:09:19 +12:00
rbygrave 40f7a0088d No effective change - add tests for ConvertInetAddressesTest and DefaultTypeFactoryTest 2015-05-14 23:22:19 +12:00
rbygrave 6a02a8d69f No effective change - code format and tidy 2015-05-14 22:42:37 +12:00
rbygrave ed18cbcabf No effective change - add test for ConvertInetAddresses 2015-05-14 21:57:38 +12:00
Rob Bygrave 3ce4f2fb35 Merge pull request #294 from andersha/add_distinct_db2
add distinct to db2
2015-05-14 21:35:59 +12:00
Anders H. Abrahamsen 962a27f838 add distinct to db2 2015-05-13 15:52:50 +02:00
rbygrave 2b583cf707 Update README.md 2015-05-13 23:09:49 +12:00
rbygrave ef9ade4f5c [maven-release-plugin] prepare for next development iteration 2015-05-13 22:56:09 +12:00
167 changed files with 8021 additions and 5179 deletions
+7 -1
View File
@@ -12,5 +12,11 @@ Maven Dependency
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.5.5</version>
<version>4.6.3</version>
</dependency>
[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm")
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm")
+21 -12
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.6.2</version>
<version>4.7.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -55,12 +55,21 @@
<version>1.7.7</version>
</dependency>
<!-- provided scope for JsonNode support -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
<scope>provided</scope>
</dependency>
<!-- Jackson core used internally by Ebean -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
@@ -68,6 +77,7 @@
<scope>provided</scope>
</dependency>
<!-- provided scope to read validation annotations Size etc -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
@@ -89,6 +99,14 @@
<scope>provided</scope>
</dependency>
<!-- Provided scope for Postgres JSON/JSONB support -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
@@ -124,13 +142,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-701.jdbc4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
@@ -254,8 +265,6 @@
<configuration>
<doctitle>Ebean 4</doctitle>
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
<!-- <excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames> -->
<!--<additionalparam>-Xdoclint:none</additionalparam>-->
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
+4 -1
View File
@@ -315,7 +315,10 @@ public final class Ebean {
}
/**
* Start a new explicit transaction.
* Start a transaction with 'REQUIRED' semantics.
* <p>
* With REQUIRED semantics if an active transaction already exists that transaction will be used.
* </p>
* <p>
* The transaction is stored in a ThreadLocal variable and typically you only
* need to use the returned Transaction <em>IF</em> you wish to do things like
@@ -509,7 +509,10 @@ public interface EbeanServer {
Transaction createTransaction(TxIsolation isolation);
/**
* Start a new explicit transaction putting it into a ThreadLocal.
* Start a transaction with 'REQUIRED' semantics.
* <p>
* With REQUIRED semantics if an active transaction already exists that transaction will be used.
* </p>
* <p>
* The transaction is stored in a ThreadLocal variable and typically you only
* need to use the returned Transaction <em>IF</em> you wish to do things like
@@ -3,6 +3,7 @@ package com.avaje.ebean;
import com.avaje.ebean.common.SpiContainer;
import com.avaje.ebean.config.ContainerConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
import javax.persistence.PersistenceException;
import java.lang.reflect.Constructor;
@@ -75,6 +76,32 @@ public class EbeanServerFactory {
return server;
}
/**
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
*/
public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
return EbeanServerFactory.create(config);
} finally {
// set the currentContextLoader back
Thread.currentThread().setContextClassLoader(currentContextLoader);
}
}
/**
* Shutdown gracefully all EbeanServers cleaning up any resources as required.
* <p>
* This is typically invoked via JVM shutdown hook and not explicitly called.
* </p>
*/
public static synchronized void shutdown() {
ShutdownManager.shutdown();
}
private static EbeanServer createInternal(ServerConfig config) {
@@ -55,4 +55,4 @@ public @interface CacheStrategy {
*/
String warmingQuery() default "";
};
}
@@ -44,4 +44,4 @@ public @interface CacheTuning {
* </p>
*/
int maxSecsToLive() default 0;
};
}
@@ -6,8 +6,10 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* Deprecated - please use @DbHstore instead.
* @see DbHstore
*/
@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnHstore {
@@ -18,14 +18,17 @@ import java.lang.annotation.Target;
* timestamp value after the insert has occurred. You need to fetch the entity
* back to get the inserted timestamp if you want to used it.
* </p>
*
* <pre class="code">
* &#064;Column(insertable = false, updateable = false)
* Timestamp cretimestamp;
* </pre>
*
* <h3>Example:</h3>
* <pre>{@code
*
* @CreatedTimestamp
* Timestamp whenCreated;
*
* }</pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatedTimestamp {
};
}
@@ -0,0 +1,26 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used for mapping a Map<String,String> type property to Postgres HSTORE data type.
* <p>
* The Map property should have keys and values of type String.
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* @DbHstore
* Map<String, String> tags;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DbHstore {
}
@@ -0,0 +1,44 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify a property holding JSON content.
* <p>
* By default the content will be stored in a DB Clob except on Postgres where DB JSON type is used.
* </p>
* <h3>Example:</h3>
* <pre>{@code
*
* // Store as JSON on Postgres or Clob on other databases
* @DbJson
* Map<String,Object> content;
*
* }</pre>
*
* <h3>Example with JSONB storage</h3>
* <pre>{@code
*
* // Store as JSONB on Postgres or Clob on other databases
* @DbJson(storage = DbJsonType.JSONB)
* Map<String,Object> content;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DbJson {
/**
* Specify the database type used to store the JSON content.
*/
DbJsonType storage() default DbJsonType.JSON;
/**
* For VARCHAR storage specify the column length (defaults to 3000).
*/
int length() default 0;
}
@@ -0,0 +1,39 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify a property holding JSON content.
* <p>
* The content will be stored on Postgres using it's JSONB type and as Clob for other databases.
* </p>
* <p>
* This is equivalent to using <code>@DbJson(storage = DbJsonType.JSONB)</code>
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* // Store as JSONB on Postgres or Clob on other databases
* @DbJsonB
* Map<String,Object> content;
*
* }</pre>
*
* <h3>Equivalent to:</h3>
* <pre>{@code
*
* // Store as JSONB on Postgres or Clob on other databases
* @DbJson(storage = DbJsonType.JSONB)
* Map<String,Object> content;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DbJsonB {
}
@@ -0,0 +1,32 @@
package com.avaje.ebean.annotation;
/**
* Specify the DB storage type used to store JSON content.
*/
public enum DbJsonType {
/**
* Store as JSON on Postgres and for other databases store as CLOB.
*/
JSON,
/**
* Store as JSONB on Postgres and for other databases store as CLOB.
*/
JSONB,
/**
* Store as database VARCHAR.
*/
VARCHAR,
/**
* Store as database CLOB.
*/
CLOB,
/**
* Store as database BLOB.
*/
BLOB
}
@@ -28,4 +28,4 @@ public @interface EmbeddedColumns {
*/
String columns() default "";
};
}
@@ -21,4 +21,4 @@ public @interface Encrypted {
* Used to specify the DB column length.
*/
int dbLength() default 0;
};
}
@@ -87,4 +87,4 @@ public @interface EnumMapping {
* The length of DB column if mapping to string values.
*/
int length() default 0;
};
}
@@ -8,19 +8,21 @@ import java.lang.annotation.Target;
/**
* Enables you to specify a value to use to persist for an enum value.
*
* <pre class="code">
* <pre>{@code
*
* public enum Status {
* &#064;EnumValue(&quot;N&quot;)
*
* @EnumValue("N")
* NEW,
*
* &#064;EnumValue(&quot;A&quot;)
* @EnumValue("A")
* ACTIVE,
*
* &#064;EnumValue(&quot;I&quot;)
* @EnumValue("I")
* INACTIVE,
* }
*
* </pre>
* }</pre>
* <p>
* This is an alternative to using the JPA standard approach or Ebean's
* {@link EnumMapping} annotation.
@@ -43,4 +45,4 @@ public @interface EnumValue {
* </p>
*/
String value();
};
}
@@ -12,17 +12,17 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
public @interface Expose {
/**
* If {@code true}, the field marked with this annotation is written out in the JSON while
* serializing. If {@code false}, the field marked with this annotation is skipped from the
* serialized output. Defaults to {@code true}.
*/
public boolean serialize() default true;
/**
* If {@code true}, the field marked with this annotation is written out in the JSON while
* serializing. If {@code false}, the field marked with this annotation is skipped from the
* serialized output. Defaults to {@code true}.
*/
boolean serialize() default true;
/**
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
* If {@code false}, the field marked with this annotation is skipped during deserialization.
* Defaults to {@code true}.
*/
public boolean deserialize() default true;
/**
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
* If {@code false}, the field marked with this annotation is skipped during deserialization.
* Defaults to {@code true}.
*/
boolean deserialize() default true;
}
@@ -39,30 +39,31 @@ import com.avaje.ebean.Query;
* queries - it needs to be explicitly included.
* </p>
*
* <pre class="code">
* <pre>{@code
*
* // find by Id
* Order o1 = Ebean.find(Order.class)
* .select(&quot;id, totalAmount&quot;)
* .select("id, totalAmount")
* .setId(1).findUnique();
*
* // find list ... using totalAmount in the where clause
* List&lt;Order&gt; list = Ebean.find(Order.class)
* .select(&quot;id, totalAmount&quot;)
* List<Order> list = Ebean.find(Order.class)
* .select("id, totalAmount")
* .where()
* .eq(&quot;status&quot;, Order.Status.NEW)
* .gt(&quot;totalAmount&quot;, 10)
* .eq("status", Order.Status.NEW)
* .gt("totalAmount", 10)
* .findList();
*
* // as a join from customer
* List&lt;Customer&gt; l0 = Ebean.find(Customer.class)
* .select(&quot;id, name&quot;)
* .join(&quot;orders&quot;, &quot;status, totalAmount&quot;)
* List<Customer> l0 = Ebean.find(Customer.class)
* .select("id, name")
* .fetch("orders", "status, totalAmount")
* .where()
* .gt(&quot;id&quot;, 0)
* .gt(&quot;orders.totalAmount&quot;, 10)
* .gt("id", 0)
* .gt("orders.totalAmount", 10)
* .findList();
*
* </pre>
* }</pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@@ -94,10 +95,12 @@ public @interface Formula {
* user.
* </p>
*
* <pre class="code">
* <pre>{@code
*
* join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
* </pre>
*
* }</pre>
*/
String join() default "";
};
}
@@ -14,11 +14,11 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {
/**
* Name of the index
*
* @return index name
*/
String value() default "";
/**
* Name of the index
*
* @return index name
*/
String value() default "";
}
@@ -34,4 +34,4 @@ public @interface NamedUpdate {
*/
boolean notifyCache() default true;
};
}
@@ -17,4 +17,4 @@ public @interface NamedUpdates {
*/
NamedUpdate[] value();
};
}
@@ -31,4 +31,4 @@ public @interface PrivateOwned {
*/
boolean cascadeRemove() default true;
};
}
@@ -21,4 +21,4 @@ public @interface Sql {
*/
SqlSelect[] select() default { @SqlSelect };
};
}
@@ -295,4 +295,4 @@ public @interface SqlSelect {
* Set this to true to have debug output when Ebean parses the sql-select.
*/
boolean debug() default false;
};
}
@@ -125,4 +125,4 @@ public @interface Transactional {
*/
Class<? extends Throwable>[] noRollbackFor() default {};
};
}
@@ -31,4 +31,4 @@ public @interface UpdateMode {
*/
boolean updateChangesOnly() default true;
};
}
@@ -13,4 +13,4 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
public @interface UpdatedTimestamp {
};
}
@@ -9,26 +9,29 @@ import java.lang.annotation.Target;
* Add an Literal to add to the where clause when a many property (List, Set or
* Map) is loaded or refreshed.
*
* <pre class="code">
* <pre>{@code
*
* // on a OneToMany property...
*
* &#064;OneToMany
* &#064;Where(clause = &quot;deleted='y'&quot;)
* List&lt;Topic&gt; topics;
* </pre>
* @OneToMany
* @Where(clause = "deleted='y'")
* List<Topic> topics;
*
* }</pre>
*
* <p>
* Note that you can include "${ta}" as a place holder for the table alias if
* you need to include the table alias in the clause.
* </p>
*
* <pre class="code">
* <pre>{@code
* // ... including the ${ta} table alias placeholder...
*
* &#064;OneToMany
* &#064;Where(clause = &quot;${ta}.deleted='y'&quot;)
* List&lt;Topic&gt; topics;
* </pre>
* @OneToMany
* @Where(clause = "${ta}.deleted='y'")
* List<Topic> topics;
*
* }</pre>
*
* <p>
* This will be added to the where clause when lazy loading the OneToMany
@@ -48,4 +51,4 @@ public @interface Where {
*/
String clause();
};
}
@@ -291,6 +291,7 @@ public class ServerConfig {
private int queryCacheMaxSize = 1000;
private int queryCacheMaxIdleTime = 600;
private int queryCacheMaxTimeToLive = 60*60*6;
private Object objectMapper;
/**
* Construct a Server Configuration for programmatically creating an EbeanServer.
@@ -1864,4 +1865,12 @@ public class ServerConfig {
return databasePlatform.isDisallowBatchOnCascade() ? PersistBatch.NONE : persistBatchOnCascade;
}
public Object getObjectMapper() {
return objectMapper;
}
public void setObjectMapper(Object objectMapper) {
this.objectMapper = objectMapper;
}
}
@@ -39,6 +39,12 @@ public class DatabasePlatform {
COMMIT
}
/**
* Set to true for MySql, no other jdbc drivers need this workaround.
*/
protected boolean useExtraTransactionOnIterateSecondaryQueries;
/**
* The behaviour used when ending a read only transaction at read committed isolation level.
*/
@@ -153,6 +159,17 @@ public class DatabasePlatform {
return name;
}
/**
* Return true if the JDBC driver does not allow additional queries to execute
* when a resultSet is being 'streamed' as is the case with findEach() etc.
* <p>
* Honestly, this is a workaround for a stupid MySql JDBC driver limitation.
* </p>
*/
public boolean useExtraTransactionOnIterateSecondaryQueries() {
return useExtraTransactionOnIterateSecondaryQueries;
}
/**
* Return a DB Sequence based IdGenerator.
*
@@ -7,6 +7,9 @@ public class Db2SqlLimiter implements SqlLimiter {
StringBuilder sb = new StringBuilder(512);
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(request.getDbSql());
int maxRows = request.getMaxRows();
@@ -8,6 +8,36 @@ package com.avaje.ebean.config.dbplatform;
*/
public class DbType {
/**
* Type to map Map content to Postgres HSTORE.
*/
public static final int HSTORE = 5000;
/**
* Type to map JSON content to Clob or Postgres JSON type.
*/
public static final int JSON = 5001;
/**
* Type to map JSON content to Clob or Postgres JSONB type.
*/
public static final int JSONB = 5002;
/**
* Type to map JSON content to VARCHAR.
*/
public static final int JSONVarchar = 5003;
/**
* Type to map JSON content to Clob.
*/
public static final int JSONClob = 5004;
/**
* Type to map JSON content to Blob.
*/
public static final int JSONBlob = 5005;
/**
* The data type name (VARCHAR, INTEGER ...)
*/
@@ -36,6 +36,13 @@ public class DbTypeMap {
put(Types.BLOB, new DbType("blob"));
put(Types.CLOB, new DbType("clob"));
put(DbType.JSON, new DbType("clob")); // Postgres maps this to JSON
put(DbType.JSONB, new DbType("clob")); // Postgres maps this to JSONB
put(DbType.JSONClob, new DbType("clob"));
put(DbType.JSONBlob, new DbType("blob"));
put(DbType.JSONVarchar, new DbType("varchar", 1000));
put(Types.LONGVARBINARY, new DbType("longvarbinary"));
put(Types.LONGVARCHAR, new DbType("lonvarchar"));
put(Types.VARBINARY, new DbType("varbinary", 255));
@@ -20,6 +20,7 @@ public class MySqlPlatform extends DatabasePlatform {
public MySqlPlatform() {
super();
this.name = "mysql";
this.useExtraTransactionOnIterateSecondaryQueries = true;
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.dbEncrypt = new MySqlDbEncrypt();
@@ -13,11 +13,6 @@ import java.sql.Types;
*/
public class PostgresPlatform extends DatabasePlatform {
/**
* Unique jdbc type id defined for hstore type.
*/
public static final int TYPE_HSTORE = 4001;
public PostgresPlatform() {
super();
this.name = "postgres";
@@ -43,8 +38,10 @@ public class PostgresPlatform extends DatabasePlatform {
this.openQuote = "\"";
this.closeQuote = "\"";
dbTypeMap.put(TYPE_HSTORE, new DbType("hstore"));
dbTypeMap.put(DbType.HSTORE, new DbType("hstore"));
dbTypeMap.put(DbType.JSON, new DbType("json"));
dbTypeMap.put(DbType.JSONB, new DbType("jsonb"));
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
dbTypeMap.put(Types.DOUBLE, new DbType("float"));
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
@@ -35,14 +35,29 @@ public class EJson {
public static void write(Object object, JsonGenerator jsonGenerator) throws IOException {
EJsonWriter.write(object, jsonGenerator);
}
/**
* Parse the json and return as a Map additionally specifying if the returned map should
* be modify aware meaning that it can detect when it has been modified.
*/
public static Map<String,Object> parseObject(String json, boolean modifyAware) throws IOException {
return EJsonReader.parseObject(json, modifyAware);
}
/**
* Parse the json and return as a Map.
*/
public static Map<String,Object> parseObject(String json) throws IOException {
return EJsonReader.parseObject(json);
}
/**
* Parse the json and return as a Map taking a reader.
*/
public static Map<String,Object> parseObject(Reader reader, boolean modifyAware) throws IOException {
return EJsonReader.parseObject(reader, modifyAware);
}
/**
* Parse the json and return as a Map taking a reader.
*/
@@ -9,6 +9,10 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import com.avaje.ebeaninternal.server.type.ModifyAwareFlag;
import com.avaje.ebeaninternal.server.type.ModifyAwareList;
import com.avaje.ebeaninternal.server.type.ModifyAwareMap;
import com.avaje.ebeaninternal.server.type.ModifyAwareOwner;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
@@ -16,7 +20,12 @@ import com.fasterxml.jackson.core.JsonToken;
class EJsonReader {
static JsonFactory json = new JsonFactory();
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(String json, boolean modifyAware) throws IOException {
return (Map<String, Object>) parse(json, modifyAware);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(String json) throws IOException {
return (Map<String, Object>) parse(json);
@@ -26,7 +35,12 @@ class EJsonReader {
static Map<String, Object> parseObject(Reader reader) throws IOException {
return (Map<String, Object>) parse(reader);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(Reader reader, boolean modifyAware) throws IOException {
return (Map<String, Object>) parse(reader, modifyAware);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(JsonParser parser) throws IOException {
return (Map<String, Object>) parse(parser);
@@ -34,7 +48,7 @@ class EJsonReader {
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(JsonParser parser, JsonToken token) throws IOException {
return (Map<String, Object>)parse(parser, token);
return (Map<String, Object>)parse(parser, token, false);
}
@SuppressWarnings("unchecked")
@@ -56,40 +70,58 @@ class EJsonReader {
return parse(new StringReader(json));
}
static Object parse(String json, boolean modifyAware) throws IOException {
return parse(new StringReader(json), modifyAware);
}
static Object parse(Reader reader) throws IOException {
return parse(json.createParser(reader));
}
static Object parse(JsonParser parser) throws IOException {
return parse(parser, null);
static Object parse(Reader reader, boolean modifyAware) throws IOException {
return parse(json.createParser(reader), modifyAware);
}
static Object parse(JsonParser parser, JsonToken token) throws IOException {
return new EJsonReader(parser).parseJson(token);
static Object parse(JsonParser parser) throws IOException {
return parse(parser, null, false);
}
static Object parse(JsonParser parser, boolean modifyAware) throws IOException {
return parse(parser, null, modifyAware);
}
static Object parse(JsonParser parser, JsonToken token, boolean modifyAware) throws IOException {
return new EJsonReader(parser, modifyAware).parseJson(token);
}
private final JsonParser parser;
private final boolean modifyAware;
private final ModifyAwareFlag modifyAwareOwner;
private int depth;
private Stack stack;
private Context currentContext;
EJsonReader(JsonParser parser) {
EJsonReader(JsonParser parser, boolean modifyAware) {
this.parser = parser;
this.modifyAware = modifyAware;
this.modifyAwareOwner = (modifyAware) ? new ModifyAwareFlag() : null;
}
private void startArray() {
depth++;
stack.push(currentContext);
currentContext = new ArrayContext();
currentContext = modifyAware ? new ArrayContext(modifyAwareOwner) : new ArrayContext();
}
private void startObject() {
depth++;
stack.push(currentContext);
currentContext = new ObjectContext();
currentContext = modifyAware ? new ObjectContext(modifyAwareOwner) : new ObjectContext();
}
private void endArray() {
@@ -105,6 +137,9 @@ class EJsonReader {
if (!stack.isEmpty()) {
currentContext = stack.pop(currentContext);
}
if (modifyAwareOwner != null) {
modifyAwareOwner.resetMarkedDirty();
}
}
private void setValue(Object value) {
@@ -235,10 +270,18 @@ class EJsonReader {
private static class ObjectContext extends Context {
private final Map<String, Object> map = new LinkedHashMap<String, Object>();
private final Map<String, Object> map;
private String key;
ObjectContext() {
map = new LinkedHashMap<String, Object>();
}
ObjectContext(ModifyAwareOwner owner) {
map = new ModifyAwareMap<String, Object>(owner, new LinkedHashMap<String, Object>());
}
public void popContext(Context temp) {
setValue(temp.getValue());
}
@@ -262,7 +305,15 @@ class EJsonReader {
private static class ArrayContext extends Context {
private final List<Object> values = new ArrayList<Object>();
private final List<Object> values;
ArrayContext() {
values = new ArrayList<Object>();
}
ArrayContext(ModifyAwareOwner owner) {
values = new ModifyAwareList<Object>(owner, new ArrayList<Object>());
}
public void popContext(Context temp) {
values.add(temp.getValue());
@@ -48,4 +48,11 @@ public abstract class LoadRequest {
return transaction;
}
/**
* Return true if the parent query is a findIterate() type query.
* So one of - findIterate(), findEach(), findEachWhile() or findVisit().
*/
public boolean isParentFindIterate() {
return parentRequest != null && parentRequest.getQuery().getType() == SpiQuery.Type.ITERATE;
}
}
File diff suppressed because it is too large Load Diff
@@ -65,10 +65,10 @@ public class TransactionEvent implements Serializable {
}
/**
* For BeanListeners the requests they are interested in.
* Return the list of PersistRequestBean's for this transaction.
*/
public TransactionEventBeans getEventBeans() {
return eventBeans;
public List<PersistRequestBean<?>> getPersistRequestBeans() {
return (eventBeans == null) ? null : eventBeans.getRequests();
}
public TransactionEventTable getEventTables() {
@@ -5,6 +5,7 @@ import java.util.List;
import javax.persistence.EntityNotFoundException;
import com.avaje.ebeaninternal.api.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,11 +16,6 @@ import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.api.LoadBeanBuffer;
import com.avaje.ebeaninternal.api.LoadBeanRequest;
import com.avaje.ebeaninternal.api.LoadManyRequest;
import com.avaje.ebeaninternal.api.LoadManyBuffer;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
@@ -36,8 +32,11 @@ public class DefaultBeanLoader {
private final DefaultServer server;
private final boolean onIterateUseExtraTxn;
protected DefaultBeanLoader(DefaultServer server) {
this.server = server;
this.onIterateUseExtraTxn = server.getDatabasePlatform().useExtraTransactionOnIterateSecondaryQueries();
}
/**
@@ -143,7 +142,17 @@ public class DefaultBeanLoader {
query.select(many.getTargetIdProperty());
}
server.findList(query, loadRequest.getTransaction());
if (onIterateUseExtraTxn && loadRequest.isParentFindIterate()) {
// MySql - we need a different transaction to execute the secondary query
SpiTransaction extraTxn = server.createQueryTransaction();
try {
server.findList(query, extraTxn);
} finally {
extraTxn.end();
}
} else {
server.findList(query, loadRequest.getTransaction());
}
// check for BeanCollection's that where never processed
// in the +query or +lazy load due to no rows (predicates)
@@ -332,7 +341,18 @@ public class DefaultBeanLoader {
query.where().idIn(idList);
}
List<?> list = server.findList(query, loadRequest.getTransaction());
List<?> list;
if (onIterateUseExtraTxn && loadRequest.isParentFindIterate()) {
// MySql - we need a different transaction to execute the secondary query
SpiTransaction extraTxn = server.createQueryTransaction();
try {
list = server.findList(query, extraTxn);
} finally {
extraTxn.end();
}
} else {
list = server.findList(query, loadRequest.getTransaction());
}
if (loadRequest.isLoadCache()) {
for (int i = 0; i < list.size(); i++) {
@@ -300,8 +300,7 @@ public class DefaultContainer implements SpiContainer {
if (config.getDataSourceJndiName() != null) {
ds = jndiDataSourceFactory.lookup(config.getDataSourceJndiName());
if (ds == null) {
String m = "JNDI lookup for DataSource " + config.getDataSourceJndiName() + " returned null.";
throw new PersistenceException(m);
throw new PersistenceException("JNDI lookup for DataSource " + config.getDataSourceJndiName() + " returned null.");
} else {
return ds;
}
@@ -309,14 +308,13 @@ public class DefaultContainer implements SpiContainer {
DataSourceConfig dsConfig = config.getDataSourceConfig();
if (dsConfig == null) {
String m = "No DataSourceConfig definded for " + config.getName();
String m = "No DataSourceConfig defined for " + config.getName();
throw new PersistenceException(m);
}
if (dsConfig.isOffline()) {
if (config.getDatabasePlatformName() == null) {
String m = "You MUST specify a DatabasePlatformName on ServerConfig when offline";
throw new PersistenceException(m);
throw new PersistenceException("You MUST specify a DatabasePlatformName on ServerConfig when offline");
}
return null;
}
@@ -756,16 +756,16 @@ public final class DefaultServer implements SpiEbeanServer {
}
/**
* Start a transaction.
* Start a transaction with 'REQUIRED' semantics.
* <p>
* If a transaction already exists that transaction will be used.
* </p>
* <p>
* Note that the transaction is stored in a ThreadLocal variable.
* </p>
*/
public Transaction beginTransaction() {
// start an explicit transaction
SpiTransaction t = transactionManager.createTransaction(true, -1);
transactionScopeManager.set(t);
return t;
return beginTransaction(TxScope.required());
}
public Transaction beginTransaction(TxScope scope) {
@@ -1318,7 +1318,7 @@ public final class DefaultServer implements SpiEbeanServer {
public <T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
request.initTransIfRequired();
request.findVisit(visitor);
@@ -1327,7 +1327,7 @@ public final class DefaultServer implements SpiEbeanServer {
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
request.initTransIfRequired();
request.findEach(consumer);
@@ -1336,7 +1336,7 @@ public final class DefaultServer implements SpiEbeanServer {
public <T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
request.initTransIfRequired();
request.findEachWhile(consumer);
@@ -1345,7 +1345,7 @@ public final class DefaultServer implements SpiEbeanServer {
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
try {
request.initTransIfRequired();
@@ -11,34 +11,27 @@ import javax.sql.DataSource;
*/
public class JndiDataSourceLookup {
private static final String DEFAULT_PREFIX = "java:comp/env/jdbc/";
public JndiDataSourceLookup() {
}
public JndiDataSourceLookup() {
}
/**
* Return the DataSource by JNDI lookup.
* <p>
* If name is null the 'default' dataSource is returned.
* </p>
*/
public DataSource lookup(String jndiName) {
/**
* Return the DataSource by JNDI lookup.
* <p>
* If name is null the 'default' dataSource is returned.
* </p>
*/
public DataSource lookup(String jndiName) {
try {
if (!jndiName.startsWith("java:")){
jndiName = DEFAULT_PREFIX + jndiName;
}
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(jndiName);
if (ds == null) {
throw new PersistenceException("JNDI DataSource [" + jndiName + "] not found?");
}
return ds;
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(jndiName);
if (ds == null) {
throw new PersistenceException("JNDI DataSource [" + jndiName + "] not found?");
}
return ds;
} catch (NamingException ex) {
throw new PersistenceException(ex);
}
}
} catch (NamingException ex) {
throw new PersistenceException(ex);
}
}
}
@@ -28,6 +28,7 @@ import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyLists;
import com.avaje.ebeaninternal.server.el.*;
import com.avaje.ebeaninternal.server.persist.DmlUtil;
import com.avaje.ebeaninternal.server.query.CQueryPlan;
import com.avaje.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
import com.avaje.ebeaninternal.server.query.SplitName;
@@ -1714,7 +1715,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
// not using Id generator so just base on isLoaded()
return !ebi.isLoaded();
}
if (!hasIdProperty(ebi)) {
if (!hasIdValue(ebi.getOwner())) {
// No Id property means it must be an insert
return true;
}
@@ -1729,9 +1730,9 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
public boolean hasIdPropertyOnly(EntityBeanIntercept ebi) {
return ebi.hasIdOnly(idPropertyIndex);
}
public boolean hasIdProperty(EntityBeanIntercept ebi) {
return idPropertyIndex > -1 && ebi.isLoadedProperty(idPropertyIndex);
public boolean hasIdValue(EntityBean bean) {
return (idProperty != null && !DmlUtil.isNullOrZero(idProperty.getValue(bean)));
}
public boolean hasVersionProperty(EntityBeanIntercept ebi) {
File diff suppressed because it is too large Load Diff
@@ -74,7 +74,7 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty {
* Construct the property.
*/
public BeanPropertyAssoc(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertyAssoc<T> deploy) {
super(owner, descriptor, deploy);
super(descriptor, deploy);
this.extraWhere = InternString.intern(deploy.getExtraWhere());
this.isOuterJoin = deploy.isOuterJoin();
this.beanTable = deploy.getBeanTable();
@@ -28,171 +28,169 @@ import com.fasterxml.jackson.core.JsonParser;
*/
public class BeanPropertyCompound extends BeanProperty {
private final CtCompoundType<?> compoundType;
private final CtCompoundType<?> compoundType;
/**
* Type Converter for scala.Option and similar type wrapping.
*/
@SuppressWarnings("rawtypes")
private final ScalarTypeConverter typeConverter;
private final BeanProperty[] scalarProperties;
/**
* Type Converter for scala.Option and similar type wrapping.
*/
@SuppressWarnings("rawtypes")
private final ScalarTypeConverter typeConverter;
private final LinkedHashMap<String, BeanProperty> propertyMap = new LinkedHashMap<String, BeanProperty>();
private final BeanProperty[] scalarProperties;
private final LinkedHashMap<String, CtCompoundPropertyElAdapter> nonScalarMap = new LinkedHashMap<String, CtCompoundPropertyElAdapter>();
private final LinkedHashMap<String, BeanProperty> propertyMap = new LinkedHashMap<String, BeanProperty>();
private final BeanPropertyCompoundRoot root;
/**
* Create the property.
*/
public BeanPropertyCompound(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertyCompound deploy) {
private final LinkedHashMap<String, CtCompoundPropertyElAdapter> nonScalarMap = new LinkedHashMap<String, CtCompoundPropertyElAdapter>();
super(owner, descriptor, deploy);
/**
* Create the property.
*/
public BeanPropertyCompound(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertyCompound deploy) {
this.compoundType = deploy.getCompoundType();
this.typeConverter = deploy.getTypeConverter();
this.root = deploy.getFlatProperties(owner, descriptor);
super(descriptor, deploy);
this.scalarProperties = root.getScalarProperties();
this.compoundType = deploy.getCompoundType();
this.typeConverter = deploy.getTypeConverter();
for (int i = 0; i < scalarProperties.length; i++) {
propertyMap.put(scalarProperties[i].getName(), scalarProperties[i]);
}
BeanPropertyCompoundRoot root = deploy.getFlatProperties(owner, descriptor);
List<CtCompoundProperty> nonScalarPropsList = root.getNonScalarProperties();
for (int i = 0; i < nonScalarPropsList.size(); i++) {
CtCompoundProperty ctProp = nonScalarPropsList.get(i);
CtCompoundPropertyElAdapter adapter = new CtCompoundPropertyElAdapter(ctProp);
nonScalarMap.put(ctProp.getRelativeName(), adapter);
}
this.scalarProperties = root.getScalarProperties();
for (int i = 0; i < scalarProperties.length; i++) {
propertyMap.put(scalarProperties[i].getName(), scalarProperties[i]);
}
@Override
public void initialise() {
// do nothing for normal BeanProperty
if (!isTransient && compoundType == null) {
String msg = "No cvoInternalType assigned to " + descriptor.getFullName() + "." + getName();
throw new RuntimeException(msg);
}
List<CtCompoundProperty> nonScalarPropsList = root.getNonScalarProperties();
for (int i = 0; i < nonScalarPropsList.size(); i++) {
CtCompoundProperty ctProp = nonScalarPropsList.get(i);
CtCompoundPropertyElAdapter adapter = new CtCompoundPropertyElAdapter(ctProp);
nonScalarMap.put(ctProp.getRelativeName(), adapter);
}
@Override
public void setDeployOrder(int deployOrder) {
this.deployOrder = deployOrder;
for (CtCompoundPropertyElAdapter adapter : nonScalarMap.values()) {
adapter.setDeployOrder(deployOrder);
}
}
@Override
public void initialise() {
// do nothing for normal BeanProperty
if (!isTransient && compoundType == null) {
String msg = "No cvoInternalType assigned to " + descriptor.getFullName() + "." + getName();
throw new RuntimeException(msg);
}
}
@Override
public void setDeployOrder(int deployOrder) {
this.deployOrder = deployOrder;
for (CtCompoundPropertyElAdapter adapter : nonScalarMap.values()) {
adapter.setDeployOrder(deployOrder);
}
}
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
if (chain == null) {
chain = new ElPropertyChainBuilder(true, propName);
}
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
// first add this property
chain.add(this);
if (chain == null) {
chain = new ElPropertyChainBuilder(true, propName);
}
// first add this property
chain.add(this);
// handle all the rest of the chain handled by the
// BeanProperty (all depth for nested compound type)
BeanProperty p = propertyMap.get(remainder);
if (p != null) {
return chain.add(p).build();
}
CtCompoundPropertyElAdapter elAdapter = nonScalarMap.get(remainder);
if (elAdapter == null) {
throw new RuntimeException("property [" + remainder + "] not found in " + getFullBeanName());
}
return chain.add(elAdapter).build();
// handle all the rest of the chain handled by the
// BeanProperty (all depth for nested compound type)
BeanProperty p = propertyMap.get(remainder);
if (p != null) {
return chain.add(p).build();
}
@Override
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
if (!isTransient) {
for (int i = 0; i < scalarProperties.length; i++) {
scalarProperties[i].appendSelect(ctx, subQuery);
}
}
CtCompoundPropertyElAdapter elAdapter = nonScalarMap.get(remainder);
if (elAdapter == null) {
throw new RuntimeException("property [" + remainder + "] not found in " + getFullBeanName());
}
return chain.add(elAdapter).build();
}
public BeanProperty[] getScalarProperties() {
return scalarProperties;
}
@Override
public Object readSet(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
boolean assignable = (type == null || owningType.isAssignableFrom(type));
Object v = compoundType.read(ctx.getDataReader());
if (assignable) {
setValue(bean, v);
}
return v;
}
/**
* Read the data from the resultSet effectively ignoring it and returning
* null.
*/
@SuppressWarnings("unchecked")
@Override
public Object read(DbReadContext ctx) throws SQLException {
Object v = compoundType.read(ctx.getDataReader());
if (typeConverter != null){
v = typeConverter.wrapValue(v);
}
return v;
}
@Override
public void loadIgnore(DbReadContext ctx) {
compoundType.loadIgnore(ctx.getDataReader());
}
@Override
public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
sqlBeanLoad.load(this);
}
@Override
public Object elGetReference(EntityBean bean) {
return bean;
}
public void jsonWrite(WriteJson ctx, EntityBean bean) throws IOException {
if (!jsonSerialize) {
return;
}
Object value = getValueIntercept(bean);
if (value == null) {
ctx.writeNull(name);
} else {
compoundType.jsonWrite(ctx, value, name);
}
}
public void jsonRead(JsonParser ctx, EntityBean bean) throws IOException {
if (!jsonDeserialize) {
return;
}
Object value = EJson.parse(ctx);
if (value == null) {
setValue(bean, null);
} else {
@SuppressWarnings("unchecked")
Map<String,Object> map = (Map<String,Object>)value;
Object objValue = compoundType.jsonConvert(map);
setValue(bean, objValue);
@Override
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
if (!isTransient) {
for (int i = 0; i < scalarProperties.length; i++) {
scalarProperties[i].appendSelect(ctx, subQuery);
}
}
}
public BeanProperty[] getScalarProperties() {
return scalarProperties;
}
@Override
public Object readSet(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
boolean assignable = (type == null || owningType.isAssignableFrom(type));
Object v = compoundType.read(ctx.getDataReader());
if (assignable) {
setValue(bean, v);
}
return v;
}
/**
* Read the data from the resultSet effectively ignoring it and returning
* null.
*/
@SuppressWarnings("unchecked")
@Override
public Object read(DbReadContext ctx) throws SQLException {
Object v = compoundType.read(ctx.getDataReader());
if (typeConverter != null) {
v = typeConverter.wrapValue(v);
}
return v;
}
@Override
public void loadIgnore(DbReadContext ctx) {
compoundType.loadIgnore(ctx.getDataReader());
}
@Override
public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
sqlBeanLoad.load(this);
}
@Override
public Object elGetReference(EntityBean bean) {
return bean;
}
public void jsonWrite(WriteJson ctx, EntityBean bean) throws IOException {
if (!jsonSerialize) {
return;
}
Object value = getValueIntercept(bean);
if (value == null) {
ctx.writeNull(name);
} else {
compoundType.jsonWrite(ctx, value, name);
}
}
public void jsonRead(JsonParser ctx, EntityBean bean) throws IOException {
if (!jsonDeserialize) {
return;
}
Object value = EJson.parse(ctx);
if (value == null) {
setValue(bean, null);
} else {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) value;
Object objValue = compoundType.jsonConvert(map);
setValue(bean, objValue);
}
}
}
@@ -97,7 +97,7 @@ public class DeployBeanPropertyLists {
discDeployProp.setDbColumn(discriminatorColumn);
// create the discriminator BeanProperty and only register it in the propertyMap
BeanProperty dprop = new BeanProperty(owner, desc, discDeployProp);
BeanProperty dprop = new BeanProperty(desc, discDeployProp);
propertyMap.put(dprop.getName(), dprop);
}
@@ -188,11 +188,11 @@ public class DeployBeanPropertyLists {
* properties).
*/
public BeanProperty[] getBaseScalar() {
return (BeanProperty[]) baseScalar.toArray(new BeanProperty[baseScalar.size()]);
return baseScalar.toArray(new BeanProperty[baseScalar.size()]);
}
public BeanPropertyCompound[] getBaseCompound() {
return (BeanPropertyCompound[]) baseCompound.toArray(new BeanPropertyCompound[baseCompound.size()]);
return baseCompound.toArray(new BeanPropertyCompound[baseCompound.size()]);
}
public BeanProperty getId() {
@@ -208,11 +208,11 @@ public class DeployBeanPropertyLists {
}
public BeanProperty[] getNonTransients() {
return (BeanProperty[]) nonTransients.toArray(new BeanProperty[nonTransients.size()]);
return nonTransients.toArray(new BeanProperty[nonTransients.size()]);
}
public BeanProperty[] getTransients() {
return (BeanProperty[]) transients.toArray(new BeanProperty[transients.size()]);
return transients.toArray(new BeanProperty[transients.size()]);
}
public BeanProperty getVersionProperty() {
@@ -220,27 +220,27 @@ public class DeployBeanPropertyLists {
}
public BeanProperty[] getLocal() {
return (BeanProperty[]) local.toArray(new BeanProperty[local.size()]);
return local.toArray(new BeanProperty[local.size()]);
}
public BeanProperty[] getMutable() {
return (BeanProperty[]) mutable.toArray(new BeanProperty[mutable.size()]);
return mutable.toArray(new BeanProperty[mutable.size()]);
}
public BeanPropertyAssocOne<?>[] getEmbedded() {
return (BeanPropertyAssocOne[]) embedded.toArray(new BeanPropertyAssocOne[embedded.size()]);
return embedded.toArray(new BeanPropertyAssocOne[embedded.size()]);
}
public BeanPropertyAssocOne<?>[] getOneExported() {
return (BeanPropertyAssocOne[]) onesExported.toArray(new BeanPropertyAssocOne[onesExported.size()]);
return onesExported.toArray(new BeanPropertyAssocOne[onesExported.size()]);
}
public BeanPropertyAssocOne<?>[] getOneImported() {
return (BeanPropertyAssocOne[]) onesImported.toArray(new BeanPropertyAssocOne[onesImported.size()]);
return onesImported.toArray(new BeanPropertyAssocOne[onesImported.size()]);
}
public BeanPropertyAssocOne<?>[] getOnes() {
return (BeanPropertyAssocOne[]) ones.toArray(new BeanPropertyAssocOne[ones.size()]);
return ones.toArray(new BeanPropertyAssocOne[ones.size()]);
}
public BeanPropertyAssocOne<?>[] getOneExportedSave() {
@@ -260,11 +260,11 @@ public class DeployBeanPropertyLists {
}
public BeanProperty[] getNonMany() {
return (BeanProperty[]) nonManys.toArray(new BeanProperty[nonManys.size()]);
return nonManys.toArray(new BeanProperty[nonManys.size()]);
}
public BeanPropertyAssocMany<?>[] getMany() {
return (BeanPropertyAssocMany[]) manys.toArray(new BeanPropertyAssocMany[manys.size()]);
return manys.toArray(new BeanPropertyAssocMany[manys.size()]);
}
public BeanPropertyAssocMany<?>[] getManySave() {
@@ -283,7 +283,7 @@ public class DeployBeanPropertyLists {
* Mode used to determine which BeanPropertyAssoc to include.
*/
private enum Mode {
Save, Delete, Validate;
Save, Delete, Validate
}
private BeanPropertyAssocOne<?>[] getOne(boolean imported, Mode mode) {
@@ -382,6 +382,6 @@ public class DeployBeanPropertyLists {
return new BeanPropertyCompound(owner, desc, (DeployBeanPropertyCompound) deployProp);
}
return new BeanProperty(owner, desc, deployProp);
return new BeanProperty(desc, deployProp);
}
}
@@ -119,9 +119,9 @@ public class AnnotationFields extends AnnotationParser {
readGenValue(gen, prop);
}
Id id = (Id) get(prop, Id.class);
Id id = get(prop, Id.class);
if (id != null) {
readId(id, prop);
readId(prop);
}
// determine the JDBC type using Lob/Temporal
@@ -135,6 +135,21 @@ public class AnnotationFields extends AnnotationParser {
util.setLobType(prop);
}
DbJson dbJson = get(prop, DbJson.class);
if (dbJson != null) {
util.setDbJsonType(prop, dbJson);
} else {
if (get(prop, DbJsonB.class) != null) {
util.setDbJsonBType(prop);
}
}
if (get(prop, ColumnHstore.class) != null) {
util.setDbHstore(prop);
}
if (get(prop, DbHstore.class) != null) {
util.setDbHstore(prop);
}
Formula formula = get(prop, Formula.class);
if (formula != null) {
prop.setSqlFormula(formula.select(), formula.join());
@@ -202,8 +217,7 @@ public class AnnotationFields extends AnnotationParser {
}
} else {
throw new RuntimeException("Can't use EmbeddedColumns on ScalarType "
+ prop.getFullBeanName());
throw new RuntimeException("Can't use EmbeddedColumns on ScalarType " + prop.getFullBeanName());
}
}
@@ -219,8 +233,7 @@ public class AnnotationFields extends AnnotationParser {
if (!prop.isTransient()) {
EncryptDeploy encryptDeploy = util.getEncryptDeploy(info.getDescriptor().getBaseTableFull(),
prop.getDbColumn());
EncryptDeploy encryptDeploy = util.getEncryptDeploy(info.getDescriptor().getBaseTableFull(), prop.getDbColumn());
if (encryptDeploy == null || encryptDeploy.getMode().equals(Mode.MODE_ANNOTATION)) {
Encrypted encrypted = get(prop, Encrypted.class);
if (encrypted != null) {
@@ -233,7 +246,7 @@ public class AnnotationFields extends AnnotationParser {
Index index = get(prop, Index.class);
if (index != null) {
if(hasRelationshipItem(prop)) {
if (hasRelationshipItem(prop)) {
throw new RuntimeException("Can't use Index on foreign key relationships.");
}
prop.setIndexed(true);
@@ -243,8 +256,8 @@ public class AnnotationFields extends AnnotationParser {
private boolean hasRelationshipItem(DeployBeanProperty prop) {
return get(prop, OneToMany.class) != null ||
get(prop, ManyToOne.class) != null ||
get(prop, OneToOne.class) != null;
get(prop, ManyToOne.class) != null ||
get(prop, OneToOne.class) != null;
}
/**
@@ -252,13 +265,7 @@ public class AnnotationFields extends AnnotationParser {
* can be applied to DDL generation.
*/
private boolean isNotNullOnAllValidationGroups(Class<?>[] groups) {
if (groups.length == 0) {
return true;
}
if (groups.length == 1 && javax.validation.groups.Default.class.isAssignableFrom(groups[0])) {
return true;
}
return false;
return groups.length == 0 || groups.length == 1 && javax.validation.groups.Default.class.isAssignableFrom(groups[0]);
}
private void setEncryption(DeployBeanProperty prop, boolean dbEncString, int dbLen) {
@@ -324,7 +331,7 @@ public class AnnotationFields extends AnnotationParser {
return util.createDataEncryptSupport(table, column);
}
private void readId(Id id, DeployBeanProperty prop) {
private void readId(DeployBeanProperty prop) {
prop.setId(true);
prop.setNullable(false);
@@ -368,9 +375,6 @@ public class AnnotationFields extends AnnotationParser {
if (prop.getPropertyType().equals(UUID.class)) {
descriptor.setIdGeneratorName(UuidIdGenerator.AUTO_UUID);
descriptor.setIdType(IdType.GENERATOR);
} else {
// use DatabasePlatform defaults
}
}
}
@@ -414,13 +418,9 @@ public class AnnotationFields extends AnnotationParser {
String baseTable = descriptor.getBaseTable();
String tableName = columnAnn.table();
if (tableName.equals("") || tableName.equalsIgnoreCase(baseTable)) {
// its a base table property...
} else {
if (!"".equals(tableName) && !tableName.equalsIgnoreCase(baseTable)) {
// its on a secondary table...
prop.setSecondaryTable(tableName);
// DeployTableJoin tableJoin = info.getTableJoin(tableName);
// tableJoin.addProperty(prop);
}
}
@@ -1,33 +1,23 @@
package com.avaje.ebeaninternal.server.deploy.parse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import com.avaje.ebean.annotation.ColumnHstore;
import com.avaje.ebean.annotation.DbHstore;
import com.avaje.ebean.annotation.DbJson;
import com.avaje.ebean.annotation.DbJsonB;
import com.avaje.ebeaninternal.server.deploy.DetermineManyType;
import com.avaje.ebeaninternal.server.deploy.ManyType;
import com.avaje.ebeaninternal.server.deploy.meta.*;
import com.avaje.ebeaninternal.server.type.CtCompoundType;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.type.TypeManager;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.ManyToOne;
import javax.persistence.PersistenceException;
import javax.persistence.Transient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.annotation.ColumnHstore;
import com.avaje.ebeaninternal.server.core.Message;
import com.avaje.ebeaninternal.server.deploy.DetermineManyType;
import com.avaje.ebeaninternal.server.deploy.ManyType;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection;
import com.avaje.ebeaninternal.server.type.CtCompoundType;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.type.ScalarTypePostgresHstore;
import com.avaje.ebeaninternal.server.type.TypeManager;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
import java.lang.reflect.*;
/**
* Create the properties for a bean.
@@ -95,15 +85,13 @@ public class DeployCreateProperties {
Field field = fields[i];
if (Modifier.isStatic(field.getModifiers())) {
// not interested in static fields
logger.trace("Skipping static field {} in {}", field.getName(), beanType.getName());
} else if (Modifier.isTransient(field.getModifiers())) {
// not interested in transient fields
logger.trace("Skipping transient field " + field.getName() + " in " + beanType.getName());
logger.trace("Skipping transient field {} in {}", field.getName(), beanType.getName());
} else if (ignoreFieldByName(field.getName())) {
// not interested this field (ebean or aspectJ field)
} else {
} else if (!ignoreFieldByName(field.getName())) {
String fieldName = getFieldName(field, beanType);
String initFieldName = initCap(fieldName);
@@ -118,14 +106,10 @@ public class DeployCreateProperties {
prop.setSortOrder((level * 10000 + 100 - i + sortOverride));
DeployBeanProperty replaced = desc.addBeanProperty(prop);
if (replaced != null) {
if (replaced.isTransient()) {
// expected for inheritance...
} else {
String msg = "Huh??? property " + prop.getFullBeanName() + " being defined twice";
msg += " but replaced property was not transient? This is not expected?";
logger.warn(msg);
}
if (replaced != null && !replaced.isTransient()) {
String msg = "Huh??? property " + prop.getFullBeanName() + " being defined twice";
msg += " but replaced property was not transient? This is not expected?";
logger.warn(msg);
}
}
}
@@ -210,33 +194,6 @@ public class DeployCreateProperties {
return null;
}
/**
* Find a public non-static setter method that matches this field (according to bean-spec rules).
*/
private Method findSetter(Field field, String initFieldName, Method[] declaredMethods, boolean scalaObject) {
String methSetName = "set" + initFieldName;
String scalaSetName = field.getName() + "_$eq";
for (int i = 0; i < declaredMethods.length; i++) {
Method m = declaredMethods[i];
if ((scalaObject && m.getName().equals(scalaSetName)) || m.getName().equals(methSetName)) {
Class<?>[] params = m.getParameterTypes();
if (params.length == 1 && field.getType().equals(params[0])) {
if (void.class.equals(m.getReturnType())) {
int modifiers = m.getModifiers();
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
return m;
}
}
}
}
}
return null;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private DeployBeanProperty createManyType(DeployBeanDescriptor<?> desc, Class<?> targetType, ManyType manyType) {
@@ -266,16 +223,8 @@ public class DeployCreateProperties {
propertyType = tt;
}
}
Class<?> innerType = propertyType;
String specialTypeKey = getSpecialScalarType(field);
if (specialTypeKey != null) {
ScalarType<?> scalarType = typeManager.getScalarTypeFromKey(specialTypeKey);
if (scalarType == null) {
logger.error("Could not find ScalarType to match key ["+specialTypeKey+"]");
} else {
return new DeployBeanProperty(desc, propertyType, scalarType, null);
}
if (isMappedType(field)) {
return new DeployBeanProperty(desc, propertyType, null, null);
}
// check for Collection type (list, set or map)
@@ -295,16 +244,16 @@ public class DeployCreateProperties {
return createManyType(desc, targetType, manyType);
}
if (innerType.isEnum() || innerType.isPrimitive()) {
if (propertyType.isEnum() || propertyType.isPrimitive()) {
return new DeployBeanProperty(desc, propertyType, null, null);
}
ScalarType<?> scalarType = typeManager.getScalarType(innerType);
ScalarType<?> scalarType = typeManager.getScalarType(propertyType);
if (scalarType != null) {
return new DeployBeanProperty(desc, propertyType, scalarType, null);
}
CtCompoundType<?> compoundType = typeManager.getCompoundType(innerType);
CtCompoundType<?> compoundType = typeManager.getCompoundType(propertyType);
if (compoundType != null) {
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
}
@@ -313,19 +262,19 @@ public class DeployCreateProperties {
return null;
}
try {
CheckImmutableResponse checkImmutable = typeManager.checkImmutable(innerType);
CheckImmutableResponse checkImmutable = typeManager.checkImmutable(propertyType);
if (checkImmutable.isImmutable()) {
if (checkImmutable.isCompoundType()) {
// use reflection to support compound immutable value objects
typeManager.recursiveCreateScalarDataReader(innerType);
compoundType = typeManager.getCompoundType(innerType);
typeManager.recursiveCreateScalarDataReader(propertyType);
compoundType = typeManager.getCompoundType(propertyType);
if (compoundType != null) {
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
}
} else {
// use reflection to support simple immutable value objects
scalarType = typeManager.recursiveCreateScalarTypes(innerType);
scalarType = typeManager.recursiveCreateScalarTypes(propertyType);
return new DeployBeanProperty(desc, propertyType, scalarType, null);
}
}
@@ -338,13 +287,14 @@ public class DeployCreateProperties {
}
}
private String getSpecialScalarType(Field field) {
if (field.getAnnotation(ColumnHstore.class) != null) {
return ScalarTypePostgresHstore.KEY;
}
return null;
/**
* Return true if the field has one of the special mappings.
*/
private boolean isMappedType(Field field) {
return (field.getAnnotation(DbJson.class) != null)
|| (field.getAnnotation(DbJsonB.class) != null)
|| (field.getAnnotation(DbHstore.class) != null)
|| (field.getAnnotation(ColumnHstore.class) != null);
}
private boolean isTransientField(Field field) {
@@ -5,6 +5,8 @@ import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.PersistenceException;
import com.avaje.ebean.annotation.DbJson;
import com.avaje.ebean.annotation.DbJsonType;
import com.avaje.ebean.config.EncryptDeploy;
import com.avaje.ebean.config.EncryptDeployManager;
import com.avaje.ebean.config.EncryptKeyManager;
@@ -13,6 +15,7 @@ import com.avaje.ebean.config.NamingConvention;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.TableName;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
import com.avaje.ebeaninternal.server.type.DataEncryptSupport;
@@ -28,201 +31,252 @@ import org.slf4j.LoggerFactory;
*/
public class DeployUtil {
private static final Logger logger = LoggerFactory.getLogger(DeployUtil.class);
private static final Logger logger = LoggerFactory.getLogger(DeployUtil.class);
/**
* Assumes CLOB rather than LONGVARCHAR.
*/
private static final int dbCLOBType = Types.CLOB;
/**
* Assumes BLOB rather than LONGVARBINARY. This should probably be
* configurable.
*/
private static final int dbBLOBType = Types.BLOB;
/**
* Assumes CLOB rather than LONGVARCHAR.
*/
private static final int dbCLOBType = Types.CLOB;
private static final int DEFAULT_JSON_VARCHAR_LENGTH = 3000;
/**
* Assumes BLOB rather than LONGVARBINARY. This should probably be
* configurable.
*/
private static final int dbBLOBType = Types.BLOB;
private final NamingConvention namingConvention;
private final NamingConvention namingConvention;
private final TypeManager typeManager;
private final TypeManager typeManager;
private final DatabasePlatform dbPlatform;
private final String manyToManyAlias;
private final EncryptDeployManager encryptDeployManager;
private final DatabasePlatform dbPlatform;
private final EncryptDeployManager encryptDeployManager;
private final EncryptKeyManager encryptKeyManager;
private final EncryptKeyManager encryptKeyManager;
private final Encryptor bytesEncryptor;
public DeployUtil(TypeManager typeMgr, ServerConfig serverConfig) {
private final Encryptor bytesEncryptor;
this.typeManager = typeMgr;
this.namingConvention = serverConfig.getNamingConvention();
this.dbPlatform = serverConfig.getDatabasePlatform();
this.encryptDeployManager = serverConfig.getEncryptDeployManager();
this.encryptKeyManager = serverConfig.getEncryptKeyManager();
Encryptor be = serverConfig.getEncryptor();
this.bytesEncryptor = be != null ? be : new SimpleAesEncryptor();
// this alias is used for ManyToMany lazy loading queries
this.manyToManyAlias = "zzzzzz";
}
public TypeManager getTypeManager() {
return typeManager;
public DeployUtil(TypeManager typeMgr, ServerConfig serverConfig) {
this.typeManager = typeMgr;
this.namingConvention = serverConfig.getNamingConvention();
this.dbPlatform = serverConfig.getDatabasePlatform();
this.encryptDeployManager = serverConfig.getEncryptDeployManager();
this.encryptKeyManager = serverConfig.getEncryptKeyManager();
Encryptor be = serverConfig.getEncryptor();
this.bytesEncryptor = be != null ? be : new SimpleAesEncryptor();
}
public TypeManager getTypeManager() {
return typeManager;
}
public DatabasePlatform getDbPlatform() {
return dbPlatform;
}
public NamingConvention getNamingConvention() {
return namingConvention;
}
/**
* Check that the EncryptKeyManager has been defined.
*/
public void checkEncryptKeyManagerDefined(String fullPropName) {
if (encryptKeyManager == null) {
String msg = "Using encryption on " + fullPropName + " but no EncryptKeyManager defined!";
throw new PersistenceException(msg);
}
}
public EncryptDeploy getEncryptDeploy(TableName table, String column) {
if (encryptDeployManager == null) {
return EncryptDeploy.ANNOTATION;
}
return encryptDeployManager.getEncryptDeploy(table, column);
}
public DataEncryptSupport createDataEncryptSupport(String table, String column) {
return new DataEncryptSupport(encryptKeyManager, bytesEncryptor, table, column);
}
public ScalarType<?> setEnumScalarType(Enumerated enumerated, DeployBeanProperty prop) {
Class<?> enumType = prop.getPropertyType();
if (!enumType.isEnum()) {
throw new IllegalArgumentException("Class [" + enumType + "] is Not a Enum?");
}
ScalarType<?> scalarType = typeManager.getScalarType(enumType);
if (scalarType == null) {
// see if it has a Mapping in avaje.properties
scalarType = typeManager.createEnumScalarType(enumType);
if (scalarType == null) {
// use JPA normal Enum type (without mapping)
EnumType type = enumerated != null ? enumerated.value() : null;
scalarType = createEnumScalarTypePerSpec(enumType, type, prop.getDbType());
}
typeManager.add(scalarType);
}
prop.setScalarType(scalarType);
prop.setDbType(scalarType.getJdbcType());
return scalarType;
}
private ScalarType<?> createEnumScalarTypePerSpec(Class<?> enumType, EnumType type, int dbType) {
if (type == null) {
// default as per spec is ORDINAL
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
} else if (type == EnumType.ORDINAL) {
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
} else {
return new ScalarTypeEnumStandard.StringEnum(enumType);
}
}
/**
* Find the ScalarType for this property.
* <p>
* This determines if there is a conversion required from the logical (bean)
* type to a DB (jdbc) type. This is the case for java.util.Date etc.
* </p>
*/
public void setScalarType(DeployBeanProperty property) {
if (property.getScalarType() != null) {
// already has a ScalarType assigned.
// this will be an Enum type...
return;
}
if (property instanceof DeployBeanPropertyCompound) {
// compound properties have a CvoInternalType instead
return;
}
public DatabasePlatform getDbPlatform() {
return dbPlatform;
}
ScalarType<?> scalarType = getScalarType(property);
if (scalarType != null) {
// set the jdbc type this maps to
public NamingConvention getNamingConvention() {
return namingConvention;
}
property.setDbType(scalarType.getJdbcType());
property.setScalarType(scalarType);
}
}
/**
* Check that the EncryptKeyManager has been defined.
*/
public void checkEncryptKeyManagerDefined(String fullPropName) {
if (encryptKeyManager == null){
String msg = "Using encryption on "+fullPropName+" but no EncryptKeyManager defined!";
throw new PersistenceException(msg);
}
}
public EncryptDeploy getEncryptDeploy(TableName table, String column) {
if (encryptDeployManager == null){
return EncryptDeploy.ANNOTATION;
}
return encryptDeployManager.getEncryptDeploy(table, column);
}
public DataEncryptSupport createDataEncryptSupport(String table, String column) {
return new DataEncryptSupport(encryptKeyManager, bytesEncryptor, table, column);
}
/**
* Return the table alias used for ManyToMany joins.
*/
public String getManyToManyAlias() {
return manyToManyAlias;
}
private ScalarType<?> getScalarType(DeployBeanProperty property) {
public ScalarType<?> setEnumScalarType(Enumerated enumerated, DeployBeanProperty prop) {
// Note that Temporal types already have dbType
// set via annotations
Class<?> propType = property.getPropertyType();
ScalarType<?> scalarType = typeManager.getScalarType(propType, property.getDbType());
if (scalarType != null) {
return scalarType;
}
Class<?> enumType = prop.getPropertyType();
if (!enumType.isEnum()) {
throw new IllegalArgumentException("Class ["+enumType+"] is Not a Enum?");
}
ScalarType<?> scalarType = typeManager.getScalarType(enumType);
if (scalarType == null) {
// see if it has a Mapping in avaje.properties
scalarType = typeManager.createEnumScalarType(enumType);
if (scalarType == null){
// use JPA normal Enum type (without mapping)
EnumType type = enumerated != null? enumerated.value(): null;
scalarType = createEnumScalarTypePerSpec(enumType, type, prop.getDbType());
}
String msg = property.getFullBeanName() + " has no ScalarType - type[" + propType.getName() + "]";
if (!property.isTransient()) {
throw new PersistenceException(msg);
typeManager.add(scalarType);
}
prop.setScalarType(scalarType);
prop.setDbType(scalarType.getJdbcType());
return scalarType;
}
} else {
// this is ok...
logger.trace("... transient property " + msg);
return null;
}
}
private ScalarType<?> createEnumScalarTypePerSpec(Class<?> enumType, EnumType type, int dbType) {
/**
* Map to Postgres HSTORE type.
*/
public void setDbHstore(DeployBeanProperty prop) {
if (type == null) {
// default as per spec is ORDINAL
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
ScalarType<?> scalarType = typeManager.getScalarType(DbType.HSTORE);
if (scalarType == null) {
// this should never occur actually
throw new RuntimeException("No ScalarType found for HSTORE on [" + prop.getFullBeanName() + "]");
}
prop.setDbType(DbType.HSTORE);
prop.setScalarType(scalarType);
}
} else if (type == EnumType.ORDINAL) {
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
/**
* This property is marked as a Lob object.
*/
public void setDbJsonType(DeployBeanProperty prop, DbJson dbJsonType) {
} else {
return new ScalarTypeEnumStandard.StringEnum(enumType);
}
}
int dbType = getDbJsonStorage(dbJsonType.storage());
setDbJsonType(prop, dbType, dbJsonType.length());
}
/**
* Find the ScalarType for this property.
* <p>
* This determines if there is a conversion required from the logical (bean)
* type to a DB (jdbc) type. This is the case for java.util.Date etc.
* </p>
*/
public void setScalarType(DeployBeanProperty property) {
public void setDbJsonBType(DeployBeanProperty prop) {
setDbJsonType(prop, DbType.JSONB, 0);
}
if (property.getScalarType() != null){
// already has a ScalarType assigned.
// this will be an Enum type...
return;
}
if (property instanceof DeployBeanPropertyCompound){
// compound properties have a CvoInternalType instead
return;
}
private void setDbJsonType(DeployBeanProperty prop, int dbType, int dbLength) {
ScalarType<?> scalarType = getScalarType(property);
if (scalarType != null){
// set the jdbc type this maps to
property.setDbType(scalarType.getJdbcType());
property.setScalarType(scalarType);
}
}
Class<?> type = prop.getPropertyType();
private ScalarType<?> getScalarType(DeployBeanProperty property) {
ScalarType<?> scalarType = typeManager.getJsonScalarType(type, dbType);
if (scalarType == null) {
// this should never occur actually
throw new RuntimeException("No ScalarType for JSON type [" + type + "] [" + dbType + "]");
}
prop.setDbType(dbType);
prop.setScalarType(scalarType);
if (dbType == Types.VARCHAR) {
// determine the db column size
int columnLength = (dbLength > 0) ? dbLength : DEFAULT_JSON_VARCHAR_LENGTH;
prop.setDbLength(columnLength);
}
}
// Note that Temporal types already have dbType
// set via annotations
Class<?> propType = property.getPropertyType();
ScalarType<?> scalarType = typeManager.getScalarType(propType, property.getDbType());
if (scalarType != null) {
return scalarType;
}
/**
* Return the JDBC type for the JSON storage type.
*/
private int getDbJsonStorage(DbJsonType dbJsonType) {
String msg = property.getFullBeanName()+" has no ScalarType - type[" + propType.getName() + "]";
if (!property.isTransient()){
throw new PersistenceException(msg);
switch (dbJsonType) {
case JSON:
return DbType.JSON;
case JSONB:
return DbType.JSONB;
case VARCHAR:
return Types.VARCHAR;
case CLOB:
return Types.CLOB;
case BLOB:
return Types.BLOB;
default:
return DbType.JSON;
}
}
} else {
// this is ok...
logger.trace("... transient property "+msg);
return null;
}
}
/**
* This property is marked as a Lob object.
*/
public void setLobType(DeployBeanProperty prop) {
/**
* This property is marked as a Lob object.
*/
public void setLobType(DeployBeanProperty prop) {
// is String or byte[] ? used to determine if its a CLOB or BLOB
Class<?> type = prop.getPropertyType();
// is String or byte[] ? used to determine if its a CLOB or BLOB
Class<?> type = prop.getPropertyType();
// this also sets the lob flag on DeployBeanProperty
int lobType = isClobType(type) ? dbCLOBType : dbBLOBType;
ScalarType<?> scalarType = typeManager.getScalarType(type, lobType);
if (scalarType == null) {
// this should never occur actually
throw new RuntimeException("No ScalarType for LOB type ["+type+"] ["+lobType+"]");
}
prop.setDbType(lobType);
prop.setScalarType(scalarType);
}
// this also sets the lob flag on DeployBeanProperty
int lobType = isClobType(type) ? dbCLOBType : dbBLOBType;
public boolean isClobType(Class<?> type){
if (type.equals(String.class)){
return true;
}
return false;
}
ScalarType<?> scalarType = typeManager.getScalarType(type, lobType);
if (scalarType == null) {
// this should never occur actually
throw new RuntimeException("No ScalarType for LOB type [" + type + "] [" + lobType + "]");
}
prop.setDbType(lobType);
prop.setScalarType(scalarType);
}
public boolean isClobType(Class<?> type) {
return type.equals(String.class);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -2,7 +2,6 @@ package com.avaje.ebeaninternal.server.query;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.bean.*;
import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
import com.avaje.ebeaninternal.api.SpiTransaction;
@@ -11,9 +10,7 @@ import com.avaje.ebeaninternal.server.core.Message;
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
import com.avaje.ebeaninternal.server.core.SpiOrmQueryRequest;
import com.avaje.ebeaninternal.server.deploy.*;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.DataReader;
import org.slf4j.Logger;
@@ -9,28 +9,28 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
public class BeanDeltaProperty {
private final BeanProperty beanProperty;
private final Object value;
public BeanDeltaProperty(BeanProperty beanProperty, Object value) {
this.beanProperty = beanProperty;
this.value = value;
}
public String toString() {
return beanProperty.getName()+":"+value;
}
public void apply(EntityBean bean) {
beanProperty.setValue(bean, value);
}
public void writeBinaryMessage(BinaryMessage m) throws IOException {
private final BeanProperty beanProperty;
private final Object value;
public BeanDeltaProperty(BeanProperty beanProperty, Object value) {
this.beanProperty = beanProperty;
this.value = value;
}
public String toString() {
return beanProperty.getName() + ":" + value;
}
public void apply(EntityBean bean) {
beanProperty.setValue(bean, value);
}
public void writeBinaryMessage(BinaryMessage m) throws IOException {
DataOutputStream os = m.getOs();
os.writeUTF(beanProperty.getName());
beanProperty.getScalarType().writeData(os, value);
}
DataOutputStream os = m.getOs();
os.writeUTF(beanProperty.getName());
beanProperty.getScalarType().writeData(os, value);
}
}
@@ -7,39 +7,39 @@ import com.avaje.ebeaninternal.api.SpiTransaction;
*/
public class DefaultTransactionScopeManager extends TransactionScopeManager {
public DefaultTransactionScopeManager(TransactionManager transactionManager){
super(transactionManager);
}
public void commit() {
DefaultTransactionThreadLocal.commit(serverName);
}
public DefaultTransactionScopeManager(TransactionManager transactionManager) {
super(transactionManager);
}
public void end() {
DefaultTransactionThreadLocal.end(serverName);
}
public void commit() {
DefaultTransactionThreadLocal.commit(serverName);
}
public SpiTransaction get() {
SpiTransaction t = DefaultTransactionThreadLocal.get(serverName);
if (t == null || !t.isActive()){
return null;
} else {
return t;
}
}
public void end() {
DefaultTransactionThreadLocal.end(serverName);
}
public void replace(SpiTransaction trans) {
DefaultTransactionThreadLocal.replace(serverName, trans);
}
public SpiTransaction get() {
SpiTransaction t = DefaultTransactionThreadLocal.get(serverName);
if (t == null || !t.isActive()) {
return null;
} else {
return t;
}
}
public void rollback() {
DefaultTransactionThreadLocal.rollback(serverName);
}
public void replace(SpiTransaction trans) {
DefaultTransactionThreadLocal.replace(serverName, trans);
}
public void rollback() {
DefaultTransactionThreadLocal.rollback(serverName);
}
public void set(SpiTransaction trans) {
DefaultTransactionThreadLocal.set(serverName, trans);
}
public void set(SpiTransaction trans) {
DefaultTransactionThreadLocal.set(serverName, trans);
}
}
@@ -14,63 +14,63 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
*/
public final class DeleteByIdMap {
private final Map<String,BeanPersistIds> beanMap = new LinkedHashMap<String, BeanPersistIds>();
public String toString() {
return beanMap.toString();
}
private final Map<String, BeanPersistIds> beanMap = new LinkedHashMap<String, BeanPersistIds>();
public void notifyCache() {
for (BeanPersistIds deleteIds : beanMap.values()) {
BeanDescriptor<?> d = deleteIds.getBeanDescriptor();
List<Serializable> idValues = deleteIds.getDeleteIds();
if (idValues != null){
d.queryCacheClear();
for (int i = 0; i < idValues.size(); i++) {
d.cacheBeanRemove(idValues.get(i));
}
}
}
}
public boolean isEmpty() {
return beanMap.isEmpty();
}
public String toString() {
return beanMap.toString();
}
public Collection<BeanPersistIds> values() {
return beanMap.values();
}
/**
* Add a Insert Update or Delete payload.
*/
public void add(BeanDescriptor<?> desc, Object id) {
BeanPersistIds r = getPersistIds(desc);
r.addId(PersistRequest.Type.DELETE, (Serializable)id);
}
/**
* Add a List of Insert Update or Delete Id's.
*/
public void addList(BeanDescriptor<?> desc, List<Object> idList) {
BeanPersistIds r = getPersistIds(desc);
for (int i = 0; i < idList.size(); i++) {
r.addId(PersistRequest.Type.DELETE, (Serializable) idList.get(i));
public void notifyCache() {
for (BeanPersistIds deleteIds : beanMap.values()) {
BeanDescriptor<?> d = deleteIds.getBeanDescriptor();
List<Serializable> idValues = deleteIds.getDeleteIds();
if (idValues != null) {
d.queryCacheClear();
for (int i = 0; i < idValues.size(); i++) {
d.cacheBeanRemove(idValues.get(i));
}
}
}
private BeanPersistIds getPersistIds(BeanDescriptor<?> desc) {
String beanType = desc.getFullName();
BeanPersistIds r = beanMap.get(beanType);
if (r == null){
r = new BeanPersistIds(desc);
beanMap.put(beanType, r);
}
return r;
}
public boolean isEmpty() {
return beanMap.isEmpty();
}
public Collection<BeanPersistIds> values() {
return beanMap.values();
}
/**
* Add a Insert Update or Delete payload.
*/
public void add(BeanDescriptor<?> desc, Object id) {
BeanPersistIds r = getPersistIds(desc);
r.addId(PersistRequest.Type.DELETE, (Serializable) id);
}
/**
* Add a List of Insert Update or Delete Id's.
*/
public void addList(BeanDescriptor<?> desc, List<Object> idList) {
BeanPersistIds r = getPersistIds(desc);
for (int i = 0; i < idList.size(); i++) {
r.addId(PersistRequest.Type.DELETE, (Serializable) idList.get(i));
}
}
private BeanPersistIds getPersistIds(BeanDescriptor<?> desc) {
String beanType = desc.getFullName();
BeanPersistIds r = beanMap.get(beanType);
if (r == null) {
r = new BeanPersistIds(desc);
beanMap.put(beanType, r);
}
return r;
}
}
@@ -1,7 +1,6 @@
package com.avaje.ebeaninternal.server.transaction;
import com.avaje.ebeaninternal.api.TransactionEvent;
import com.avaje.ebeaninternal.api.TransactionEventBeans;
import com.avaje.ebeaninternal.api.TransactionEventTable;
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
@@ -48,7 +47,7 @@ public final class PostCommitProcessing {
this.serverName = manager.getServerName();
this.event = event;
this.deleteByIdMap = event.getDeleteByIdMap();
this.persistBeanRequests = createPersistBeanRequests();
this.persistBeanRequests = event.getPersistRequestBeans();
this.beanPersistIdMap = createBeanPersistIdMap();
this.remoteTransactionEvent = createRemoteTransactionEvent();
}
@@ -111,14 +110,6 @@ public final class PostCommitProcessing {
}
}
private List<PersistRequestBean<?>> createPersistBeanRequests() {
TransactionEventBeans eventBeans = event.getEventBeans();
if (eventBeans != null) {
return eventBeans.getRequests();
}
return null;
}
private BeanPersistIdMap createBeanPersistIdMap() {
if (persistBeanRequests == null) {
@@ -23,50 +23,50 @@ import java.net.UnknownHostException;
import java.util.Locale;
/**
* Rob Bygrave: This is a copy of the google guava InetAddresses class
* Rob Bygrave: This is a copy of the google guava InetAddresses class
* with some features removed.
*
*
* <p/>
* <p/>
* Static utility methods pertaining to {@link InetAddress} instances.
*
* <p/>
* <p><b>Important note:</b> Unlike {@code InetAddress.getByName()}, the
* methods of this class never cause DNS services to be accessed. For
* this reason, you should prefer these methods as much as possible over
* their JDK equivalents whenever you are expecting to handle only
* IP address string literals -- there is no blocking DNS penalty for a
* malformed string.
*
* <p/>
* <p>This class hooks into the {@code sun.net.util.IPAddressUtil} class
* to make use of the {@code textToNumericFormatV4} and
* {@code textToNumericFormatV6} methods directly as a means to avoid
* accidentally traversing all nameservices (it can be vitally important
* to avoid, say, blocking on DNS at times).
*
* <p/>
* <p>When dealing with {@link Inet4Address} and {@link Inet6Address}
* objects as byte arrays (vis. {@code InetAddress.getAddress()}) they
* are 4 and 16 bytes in length, respectively, and represent the address
* in network byte order.
*
* <p/>
* <p>Examples of IP addresses and their byte representations:
* <ul>
* <li>The IPv4 loopback address, {@code "127.0.0.1"}.<br/>
* {@code 7f 00 00 01}
*
* {@code 7f 00 00 01}
* <p/>
* <li>The IPv6 loopback address, {@code "::1"}.<br/>
* {@code 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01}
*
* {@code 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01}
* <p/>
* <li>From the IPv6 reserved documentation prefix ({@code 2001:db8::/32}),
* {@code "2001:db8::1"}.<br/>
* {@code 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01}
*
* {@code "2001:db8::1"}.<br/>
* {@code 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01}
* <p/>
* <li>An IPv6 "IPv4 compatible" (or "compat") address,
* {@code "::192.168.0.1"}.<br/>
* {@code 00 00 00 00 00 00 00 00 00 00 00 00 c0 a8 00 01}
*
* {@code "::192.168.0.1"}.<br/>
* {@code 00 00 00 00 00 00 00 00 00 00 00 00 c0 a8 00 01}
* <p/>
* <li>An IPv6 "IPv4 mapped" address, {@code "::ffff:192.168.0.1"}.<br/>
* {@code 00 00 00 00 00 00 00 00 00 00 ff ff c0 a8 00 01}
* {@code 00 00 00 00 00 00 00 00 00 00 ff ff c0 a8 00 01}
* </ul>
*
* <p/>
* <p>A few notes about IPv6 "IPv4 mapped" addresses and their observed
* use in Java.
* <br><br>
@@ -77,13 +77,13 @@ import java.util.Locale;
* these "mapped" addresses were never supposed to be seen on the
* wire. That assumption was dropped, some say mistakenly, in later
* RFCs with the apparent aim of making IPv4-to-IPv6 transition simpler.
*
* <p/>
* <p>Technically one <i>can</i> create a 128bit IPv6 address with the wire
* format of a "mapped" address, as shown above, and transmit it in an
* IPv6 packet header. However, Java's InetAddress creation methods
* appear to adhere doggedly to the original intent of the "mapped"
* address: all "mapped" addresses return {@link Inet4Address} objects.
*
* <p/>
* <p>For added safety, it is common for IPv6 network operators to filter
* all packets where either the source or destination address appears to
* be a "compat" or "mapped" address. Filtering suggestions usually
@@ -91,44 +91,44 @@ import java.util.Locale;
* in the invalid range {@code ::/3}, which includes both of these bizarre
* address formats. For more information on "bogons", including lists
* of IPv6 bogon space, see:
*
* <p/>
* <ul>
* <li><a target="_parent"
* href="http://en.wikipedia.org/wiki/Bogon_filtering"
* >http://en.wikipedia.org/wiki/Bogon_filtering</a>
* href="http://en.wikipedia.org/wiki/Bogon_filtering"
* >http://en.wikipedia.org/wiki/Bogon_filtering</a>
* <li><a target="_parent"
* href="http://www.cymru.com/Bogons/ipv6.txt"
* >http://www.cymru.com/Bogons/ipv6.txt</a>
* href="http://www.cymru.com/Bogons/ipv6.txt"
* >http://www.cymru.com/Bogons/ipv6.txt</a>
* <li><a target="_parent"
* href="http://www.cymru.com/Bogons/v6bogon.html"
* >http://www.cymru.com/Bogons/v6bogon.html</a>
* href="http://www.cymru.com/Bogons/v6bogon.html"
* >http://www.cymru.com/Bogons/v6bogon.html</a>
* <li><a target="_parent"
* href="http://www.space.net/~gert/RIPE/ipv6-filters.html"
* >http://www.space.net/~gert/RIPE/ipv6-filters.html</a>
* href="http://www.space.net/~gert/RIPE/ipv6-filters.html"
* >http://www.space.net/~gert/RIPE/ipv6-filters.html</a>
* </ul>
*
* @author Erik Kline
* @since 5
*/
//@Beta
public final class ConvertInetAddresses {
private static final int IPV4_PART_COUNT = 4;
private static final int IPV6_PART_COUNT = 8;
private ConvertInetAddresses() {}
private ConvertInetAddresses() {
}
/**
* Returns the {@link InetAddress} having the given string
* representation.
*
* <p/>
* <p>This deliberately avoids all nameservice lookups (e.g. no DNS).
*
* @param ipString {@code String} containing an IPv4 or IPv6 string literal,
* e.g. {@code "192.168.0.1"} or {@code "2001:db8::1"}
* @return {@link InetAddress} representing the argument
* @throws IllegalArgumentException if the argument is not a valid
* IP string literal
* IP string literal
*/
public static InetAddress forString(String ipString) {
byte[] addr = textToNumericFormatV4(ipString);
@@ -299,19 +299,19 @@ public final class ConvertInetAddresses {
/**
* Returns the string representation of an {@link InetAddress} suitable
* for inclusion in a URI.
*
* <p/>
* <p>For IPv4 addresses, this is identical to
* {@link InetAddress#getHostAddress()}, but for IPv6 addresses it
* surrounds this text with square brackets; for example
* {@code "[2001:db8::1]"}.
*
* <p/>
* <p>Per section 3.2.2 of
* <a target="_parent"
* href="http://tools.ietf.org/html/rfc3986#section-3.2.2"
* >http://tools.ietf.org/html/rfc3986</a>,
* href="http://tools.ietf.org/html/rfc3986#section-3.2.2"
* >http://tools.ietf.org/html/rfc3986</a>,
* a URI containing an IPv6 string literal is of the form
* {@code "http://[2001:db8::1]:8888/index.html"}.
*
* <p/>
* <p>Use of either {@link InetAddress#getHostAddress()} or this
* method is recommended over {@link InetAddress#toString()} when an
* IP address string literal is desired. This is because
@@ -331,22 +331,21 @@ public final class ConvertInetAddresses {
/**
* Returns an InetAddress representing the literal IPv4 or IPv6 host
* portion of a URL, encoded in the format specified by RFC 3986 section 3.2.2.
*
* <p/>
* <p>This function is similar to {@link ConvertInetAddresses#forString(String)},
* however, it requires that IPv6 addresses are surrounded by square brackets.
*
* <p/>
* <p>This function is the inverse of
* {@link ConvertInetAddresses#toUriString(java.net.InetAddress)}.
*
* @param hostAddr A RFC 3986 section 3.2.2 encoded IPv4 or IPv6 address
* @return an InetAddress representing the address in {@code hostAddr}
* @throws IllegalArgumentException if {@code hostAddr} is not a valid
* IPv4 address, or IPv6 address surrounded by square brackets
* IPv4 address, or IPv6 address surrounded by square brackets
*/
public static InetAddress forUriString(String hostAddr) {
//Preconditions.checkNotNull(hostAddr);
//Preconditions.checkArgument(hostAddr.length() > 0, "host string is empty");
InetAddress retval = null;
InetAddress retval;
// IPv4 address?
try {
@@ -5,78 +5,76 @@ import com.avaje.ebean.config.CompoundTypeProperty;
/**
* Wraps a CompoundTypeProperty with it's type and parent for nested compound
* types.
*
* @author rbygrave
*/
public class CtCompoundProperty {
private final String relativeName;
private final String relativeName;
private final CtCompoundProperty parent;
private final CtCompoundProperty parent;
private final CtCompoundType<?> compoundType;
private final CtCompoundType<?> compoundType;
@SuppressWarnings({ "rawtypes" })
private final CompoundTypeProperty property;
@SuppressWarnings({"rawtypes"})
private final CompoundTypeProperty property;
public CtCompoundProperty(String relativeName, CtCompoundProperty parent, CtCompoundType<?> ctType,
CompoundTypeProperty<?, ?> property) {
public CtCompoundProperty(String relativeName, CtCompoundProperty parent, CtCompoundType<?> ctType,
CompoundTypeProperty<?, ?> property) {
this.relativeName = relativeName;
this.parent = parent;
this.compoundType = ctType;
this.property = property;
this.relativeName = relativeName;
this.parent = parent;
this.compoundType = ctType;
this.property = property;
}
/**
* The property name relative to the root of the compound type.
*/
public String getRelativeName() {
return relativeName;
}
/**
* The property name local to its type.
*/
public String getPropertyName() {
return property.getName();
}
public String toString() {
return relativeName;
}
@SuppressWarnings("unchecked")
public Object getValue(Object valueObject) {
if (valueObject == null) {
return null;
}
/**
* The property name relative to the root of the compound type.
*/
public String getRelativeName() {
return relativeName;
if (parent != null) {
valueObject = parent.getValue(valueObject);
}
return property.getValue(valueObject);
}
/**
* The property name local to its type.
*/
public String getPropertyName() {
return property.getName();
}
/**
* Set a scalar value that is used to build the immutable compound value
* object.
* <p>
* When all the scalar values have been collected then the compound value
* object is built and this can be recursive for nested compound types.
* </p>
*/
public Object setValue(Object bean, Object value) {
public String toString() {
return relativeName;
}
// compoundType and propertyName should be correct depth
Object compoundValue = ImmutableCompoundTypeBuilder.set(compoundType, property.getName(), value);
@SuppressWarnings("unchecked")
public Object getValue(Object valueObject) {
if (valueObject == null) {
return null;
}
if (parent != null) {
valueObject = parent.getValue(valueObject);
}
return property.getValue(valueObject);
}
if (compoundValue != null && parent != null) {
// Continue up the tree
return parent.setValue(bean, compoundValue);
/**
* Set a scalar value that is used to build the immutable compound value
* object.
* <p>
* When all the scalar values have been collected then the compound value
* object is built and this can be recursive for nested compound types.
* </p>
*/
public Object setValue(Object bean, Object value) {
// compoundType and propertyName should be correct depth
Object compoundValue = ImmutableCompoundTypeBuilder.set(compoundType, property.getName(), value);
if (compoundValue != null && parent != null) {
// Continue up the tree
return parent.setValue(bean, compoundValue);
} else {
return compoundValue;
}
} else {
return compoundValue;
}
}
}
@@ -1,214 +1,193 @@
package com.avaje.ebeaninternal.server.type;
import java.io.IOException;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.CompoundTypeProperty;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Map;
/**
* The internal representation of a Compound Type (Immutable Compound Value Object).
*
* @param <V>
* The Type of the "Immutable Compound Value Object".
*
* @param <V> The Type of the "Immutable Compound Value Object".
*/
public final class CtCompoundType<V> implements ScalarDataReader<V> {
private final Class<V> cvoClass;
private final CompoundType<V> cvoType;
private final Class<V> cvoClass;
private final Map<String,CompoundTypeProperty<V, ?>> propertyMap;
private final CompoundType<V> cvoType;
private final ScalarDataReader<Object>[] propReaders;
private final ScalarDataReader<Object>[] propReaders;
private final CompoundTypeProperty<V, ?>[] properties;
private final CompoundTypeProperty<V, ?>[] properties;
public CtCompoundType(Class<V> cvoClass, CompoundType<V> cvoType, ScalarDataReader<Object>[] propReaders) {
this.cvoClass = cvoClass;
this.cvoType = cvoType;
this.properties = cvoType.getProperties();
this.propReaders = propReaders;
this.propertyMap = new LinkedHashMap<String, CompoundTypeProperty<V,?>>();
for (CompoundTypeProperty<V,?> cp: properties) {
propertyMap.put(cp.getName(), cp);
}
}
public String toString() {
return cvoClass.toString();
public CtCompoundType(Class<V> cvoClass, CompoundType<V> cvoType, ScalarDataReader<Object>[] propReaders) {
this.cvoClass = cvoClass;
this.cvoType = cvoType;
this.properties = cvoType.getProperties();
this.propReaders = propReaders;
}
public String toString() {
return cvoClass.toString();
}
public Class<V> getCompoundTypeClass() {
return cvoClass;
}
public V create(Object[] propertyValues) {
return cvoType.create(propertyValues);
}
public V create(Map<String, Object> valueMap) {
if (valueMap.size() != properties.length) {
// not enough elements in the map
return null;
}
public Class<V> getCompoundTypeClass() {
return cvoClass;
// we expect the map to contain a value for
// each property and that the values are the
// correct type
Object[] propertyValues = new Object[properties.length];
for (int i = 0; i < properties.length; i++) {
propertyValues[i] = valueMap.get(properties[i].getName());
if (propertyValues[i] == null) {
String m = "Null value for " + properties[i].getName() + " in map " + valueMap;
throw new RuntimeException(m);
}
}
public V create(Object[] propertyValues) {
return cvoType.create(propertyValues);
return create(propertyValues);
}
public CompoundTypeProperty<V, ?>[] getProperties() {
return cvoType.getProperties();
}
public V read(DataReader source) throws SQLException {
boolean nullValue = false;
Object[] values = new Object[propReaders.length];
for (int i = 0; i < propReaders.length; i++) {
Object o = propReaders[i].read(source);
values[i] = o;
if (o == null) {
nullValue = true;
}
}
public V create(Map<String, Object> valueMap) {
if (valueMap.size() != properties.length) {
// not enough elements in the map
return null;
}
// we expect the map to contain a value for
// each property and that the values are the
// correct type
Object[] propertyValues = new Object[properties.length];
for (int i = 0; i < properties.length; i++) {
propertyValues[i] = valueMap.get(properties[i].getName());
if (propertyValues[i] == null) {
String m = "Null value for " + properties[i].getName() + " in map " + valueMap;
throw new RuntimeException(m);
}
}
return create(propertyValues);
if (nullValue) {
return null;
}
public CompoundTypeProperty<V, ?>[] getProperties() {
return create(values);
}
return cvoType.getProperties();
public void loadIgnore(DataReader dataReader) {
for (int i = 0; i < propReaders.length; i++) {
propReaders[i].loadIgnore(dataReader);
}
}
public void bind(DataBind b, V value) throws SQLException {
CompoundTypeProperty<V, ?>[] props = cvoType.getProperties();
for (int i = 0; i < props.length; i++) {
Object o = props[i].getValue(value);
propReaders[i].bind(b, o);
}
}
/**
* Recursively accumulate all the scalar types (in depth first order).
* <p>
* This creates a flat list of scalars even when compound types are embedded
* inside compound types.
* </p>
*/
public void accumulateScalarTypes(String parent, CtCompoundTypeScalarList list) {
CompoundTypeProperty<V, ?>[] props = cvoType.getProperties();
for (int i = 0; i < propReaders.length; i++) {
String propName = getFullPropName(parent, props[i].getName());
list.addCompoundProperty(propName, this, props[i]);
propReaders[i].accumulateScalarTypes(propName, list);
}
public Object[] getPropertyValues(V valueObject) {
}
Object[] values = new Object[properties.length];
for (int i = 0; i < properties.length; i++) {
values[i] = properties[i].getValue(valueObject);
}
return values;
/**
* Return the full property name (for compound types embedded in other
* compound types).
*
* @param parent the parent property name
* @param propName the local property name
*/
private String getFullPropName(String parent, String propName) {
if (parent == null) {
return propName;
} else {
return parent + "." + propName;
}
}
public Object jsonConvert(Map<String, Object> map) {
return readJsonElementObject(map);
}
@SuppressWarnings("unchecked")
private Object readJsonElementObject(Map<String, Object> jsonObject) {
boolean nullValue = false;
Object[] values = new Object[propReaders.length];
for (int i = 0; i < propReaders.length; i++) {
String propName = properties[i].getName();
Object jsonElement = jsonObject.get(propName);
if (propReaders[i] instanceof CtCompoundType<?>) {
values[i] = ((CtCompoundType<?>) propReaders[i]).readJsonElementObject((Map<String, Object>) jsonElement);
} else {
values[i] = ((ScalarType<?>) propReaders[i]).parse(jsonElement.toString());
}
if (values[i] == null) {
nullValue = true;
}
}
public V read(DataReader source) throws SQLException {
boolean nullValue = false;
Object[] values = new Object[propReaders.length];
for (int i = 0; i < propReaders.length; i++) {
Object o = propReaders[i].read(source);
values[i] = o;
if (o == null){
nullValue = true;
}
}
if (nullValue){
return null;
}
return create(values);
if (nullValue) {
return null;
}
public void loadIgnore(DataReader dataReader) {
for (int i = 0; i < propReaders.length; i++) {
propReaders[i].loadIgnore(dataReader);
}
}
return create(values);
}
public void bind(DataBind b, V value) throws SQLException {
CompoundTypeProperty<V, ?>[] props = cvoType.getProperties();
for (int i = 0; i < props.length; i++) {
Object o = props[i].getValue(value);
propReaders[i].bind(b, o);
}
}
/**
* Recursively accumulate all the scalar types (in depth first order).
* <p>
* This creates a flat list of scalars even when compound types are embedded
* inside compound types.
* </p>
*/
public void accumulateScalarTypes(String parent, CtCompoundTypeScalarList list) {
CompoundTypeProperty<V, ?>[] props = cvoType.getProperties();
for (int i = 0; i < propReaders.length; i++) {
String propName = getFullPropName(parent, props[i].getName());
list.addCompoundProperty(propName, this, props[i]);
propReaders[i].accumulateScalarTypes(propName, list);
}
}
/**
* Return the full property name (for compound types embedded in other
* compound types).
*
* @param parent
* the parent property name
* @param propName
* the local property name
*/
private String getFullPropName(String parent, String propName) {
if (parent == null) {
return propName;
} else {
return parent + "." + propName;
}
}
public Object jsonConvert(Map<String, Object> map) {
return readJsonElementObject(map);
}
@SuppressWarnings("unchecked")
private Object readJsonElementObject(Map<String,Object> jsonObject){
boolean nullValue = false;
Object[] values = new Object[propReaders.length];
for (int i = 0; i < propReaders.length; i++) {
String propName = properties[i].getName();
Object jsonElement = jsonObject.get(propName);
if (propReaders[i] instanceof CtCompoundType<?>) {
values[i] = ((CtCompoundType<?>)propReaders[i]).readJsonElementObject((Map<String,Object>)jsonElement);
} else {
//((ScalarType<?>)propReaders[i]).jsonFromString(jsonElement.toPrimitiveString(), ctx.getValueAdapter());
values[i] = ((ScalarType<?>)propReaders[i]).parse(jsonElement.toString());;
}
if (values[i] == null){
nullValue = true;
}
}
if (nullValue){
return null;
}
return create(values);
}
public void jsonWrite(WriteJson ctx, Object valueObject, String propertyName) throws IOException {
ctx.beginAssocOne(propertyName, valueObject);
jsonWriteProps(ctx, valueObject, propertyName);
ctx.endAssocOne();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
private void jsonWriteProps(WriteJson ctx, Object valueObject, String propertyName) throws IOException {
if (propertyName != null) {
ctx.gen().writeFieldName(propertyName);
}
}
ctx.gen().writeStartObject();
for (int i = 0; i < properties.length; i++) {
@@ -219,7 +198,6 @@ public final class CtCompoundType<V> implements ScalarDataReader<V> {
} else {
((ScalarType) propReaders[i]).jsonWrite(ctx.gen(), propName, value);
//ctx.appendNameValue(propName, (ScalarType) propReaders[i], value);
}
}
@@ -12,109 +12,105 @@ import java.sql.Timestamp;
public class DataBind {
private final PreparedStatement pstmt;
private final PreparedStatement pstmt;
private int pos;
private int pos;
public DataBind(PreparedStatement pstmt) {
this.pstmt = pstmt;
}
public DataBind(PreparedStatement pstmt) {
this.pstmt = pstmt;
}
public void close() throws SQLException {
pstmt.close();
}
public int currentPos() {
return pos;
}
public void resetPos() {
pos = 0;
}
public void close() throws SQLException {
pstmt.close();
}
public void setObject(Object value) throws SQLException {
pstmt.setObject(++pos, value);
}
public int currentPos() {
return pos;
}
public void setObject(Object value, int sqlType) throws SQLException {
pstmt.setObject(++pos, value, sqlType);
}
public void setObject(Object value) throws SQLException {
pstmt.setObject(++pos, value);
}
public void setNull(int jdbcType) throws SQLException {
pstmt.setNull(++pos, jdbcType);
}
public void setObject(Object value, int sqlType) throws SQLException {
pstmt.setObject(++pos, value, sqlType);
}
public int nextPos() {
return ++pos;
}
public void setNull(int jdbcType) throws SQLException {
pstmt.setNull(++pos, jdbcType);
}
public int decrementPos() {
return ++pos;
}
public int executeUpdate() throws SQLException {
return pstmt.executeUpdate();
}
public int nextPos() {
return ++pos;
}
public PreparedStatement getPstmt() {
return pstmt;
}
public int decrementPos() {
return ++pos;
}
public void setString(String s) throws SQLException {
pstmt.setString(++pos, s);
}
public int executeUpdate() throws SQLException {
return pstmt.executeUpdate();
}
public void setInt(int i) throws SQLException {
pstmt.setInt(++pos, i);
}
public PreparedStatement getPstmt() {
return pstmt;
}
public void setLong(long i) throws SQLException {
pstmt.setLong(++pos, i);
}
public void setString(String s) throws SQLException {
pstmt.setString(++pos, s);
}
public void setShort(short i) throws SQLException {
pstmt.setShort(++pos, i);
}
public void setInt(int i) throws SQLException {
pstmt.setInt(++pos, i);
}
public void setFloat(float i) throws SQLException {
pstmt.setFloat(++pos, i);
}
public void setLong(long i) throws SQLException {
pstmt.setLong(++pos, i);
}
public void setDouble(double i) throws SQLException {
pstmt.setDouble(++pos, i);
}
public void setShort(short i) throws SQLException {
pstmt.setShort(++pos, i);
}
public void setBigDecimal(BigDecimal v) throws SQLException {
pstmt.setBigDecimal(++pos, v);
}
public void setFloat(float i) throws SQLException {
pstmt.setFloat(++pos, i);
}
public void setDate(java.sql.Date v) throws SQLException {
pstmt.setDate(++pos, v);
}
public void setDouble(double i) throws SQLException {
pstmt.setDouble(++pos, i);
}
public void setTimestamp(Timestamp v) throws SQLException {
pstmt.setTimestamp(++pos, v);
}
public void setBigDecimal(BigDecimal v) throws SQLException {
pstmt.setBigDecimal(++pos, v);
}
public void setTime(Time v) throws SQLException {
pstmt.setTime(++pos, v);
}
public void setDate(java.sql.Date v) throws SQLException {
pstmt.setDate(++pos, v);
}
public void setBoolean(boolean v) throws SQLException {
pstmt.setBoolean(++pos, v);
}
public void setBytes(byte[] v) throws SQLException {
pstmt.setBytes(++pos, v);
}
public void setByte(byte v) throws SQLException {
pstmt.setByte(++pos, v);
}
public void setChar(char v) throws SQLException {
pstmt.setString(++pos, String.valueOf(v));
}
public void setTimestamp(Timestamp v) throws SQLException {
pstmt.setTimestamp(++pos, v);
}
public void setTime(Time v) throws SQLException {
pstmt.setTime(++pos, v);
}
public void setBoolean(boolean v) throws SQLException {
pstmt.setBoolean(++pos, v);
}
public void setBytes(byte[] v) throws SQLException {
pstmt.setBytes(++pos, v);
}
public void setByte(byte v) throws SQLException {
pstmt.setByte(++pos, v);
}
public void setChar(char v) throws SQLException {
pstmt.setString(++pos, String.valueOf(v));
}
public void setBlob(InputStream inputStream, long length) throws SQLException {
pstmt.setBlob(++pos, inputStream, length);
@@ -124,14 +120,14 @@ public class DataBind {
pstmt.setBlob(++pos, inputStream);
}
public void setBlob(byte[] bytes) throws SQLException {
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
pstmt.setBinaryStream(++pos, is, bytes.length);
}
public void setClob(String content) throws SQLException {
Reader reader = new StringReader(content);
pstmt.setCharacterStream(++pos, reader, content.length());
}
public void setBlob(byte[] bytes) throws SQLException {
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
pstmt.setBinaryStream(++pos, is, bytes.length);
}
public void setClob(String content) throws SQLException {
Reader reader = new StringReader(content);
pstmt.setCharacterStream(++pos, reader, content.length());
}
}
@@ -6,38 +6,38 @@ import com.avaje.ebean.config.Encryptor;
public class DataEncryptSupport {
private final EncryptKeyManager encryptKeyManager;
private final Encryptor encryptor;
private final String table;
private final String column;
public DataEncryptSupport(EncryptKeyManager encryptKeyManager, Encryptor encryptor, String table, String column) {
this.encryptKeyManager = encryptKeyManager;
this.encryptor = encryptor;
this.table = table;
this.column = column;
}
public byte[] encrypt(byte[] data){
EncryptKey key = encryptKeyManager.getEncryptKey(table, column);
return encryptor.encrypt(data, key);
}
private final EncryptKeyManager encryptKeyManager;
private final Encryptor encryptor;
private final String table;
private final String column;
public byte[] decrypt(byte[] data){
EncryptKey key = encryptKeyManager.getEncryptKey(table, column);
return encryptor.decrypt(data, key);
}
public String decryptObject(byte[] data) {
EncryptKey key = encryptKeyManager.getEncryptKey(table, column);
return encryptor.decryptString(data, key);
}
public DataEncryptSupport(EncryptKeyManager encryptKeyManager, Encryptor encryptor, String table, String column) {
this.encryptKeyManager = encryptKeyManager;
this.encryptor = encryptor;
this.table = table;
this.column = column;
}
public <T> byte[] encryptObject(String formattedValue) {
EncryptKey key = encryptKeyManager.getEncryptKey(table, column);
return encryptor.encryptString(formattedValue, key);
}
public byte[] encrypt(byte[] data) {
EncryptKey key = encryptKeyManager.getEncryptKey(table, column);
return encryptor.encrypt(data, key);
}
public byte[] decrypt(byte[] data) {
EncryptKey key = encryptKeyManager.getEncryptKey(table, column);
return encryptor.decrypt(data, key);
}
public String decryptObject(byte[] data) {
EncryptKey key = encryptKeyManager.getEncryptKey(table, column);
return encryptor.decryptString(data, key);
}
public byte[] encryptObject(String formattedValue) {
EncryptKey key = encryptKeyManager.getEncryptKey(table, column);
return encryptor.encryptString(formattedValue, key);
}
}
@@ -1,57 +1,62 @@
package com.avaje.ebeaninternal.server.type;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.sql.Array;
import java.sql.SQLException;
public interface DataReader {
public void close() throws SQLException;
void close() throws SQLException;
public boolean next() throws SQLException;
boolean next() throws SQLException;
public void resetColumnPosition();
public void incrementPos(int increment);
void resetColumnPosition();
public byte[] getBinaryBytes() throws SQLException;
void incrementPos(int increment);
public byte[] getBlobBytes() throws SQLException;
byte[] getBinaryBytes() throws SQLException;
public String getStringFromStream() throws SQLException;
byte[] getBlobBytes() throws SQLException;
public String getStringClob() throws SQLException;
public String getString() throws SQLException;
InputStream getBlobInputStream() throws SQLException;
public Boolean getBoolean() throws SQLException;
String getStringFromStream() throws SQLException;
public Byte getByte() throws SQLException;
String getStringClob() throws SQLException;
public Short getShort() throws SQLException;
Reader getClobReader() throws SQLException;
public Integer getInt() throws SQLException;
String getString() throws SQLException;
public Long getLong() throws SQLException;
Boolean getBoolean() throws SQLException;
public Float getFloat() throws SQLException;
Byte getByte() throws SQLException;
public Double getDouble() throws SQLException;
Short getShort() throws SQLException;
public byte[] getBytes() throws SQLException;
Integer getInt() throws SQLException;
public java.sql.Date getDate() throws SQLException;
Long getLong() throws SQLException;
public java.sql.Time getTime() throws SQLException;
Float getFloat() throws SQLException;
public java.sql.Timestamp getTimestamp() throws SQLException;
Double getDouble() throws SQLException;
public BigDecimal getBigDecimal() throws SQLException;
byte[] getBytes() throws SQLException;
public Array getArray() throws SQLException;
public Object getObject() throws SQLException;
java.sql.Date getDate() throws SQLException;
public InputStream getBinaryStream() throws SQLException;
java.sql.Time getTime() throws SQLException;
java.sql.Timestamp getTimestamp() throws SQLException;
BigDecimal getBigDecimal() throws SQLException;
Array getArray() throws SQLException;
Object getObject() throws SQLException;
InputStream getBinaryStream() throws SQLException;
}
@@ -14,130 +14,128 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
*/
public class DefaultTypeFactory {
private final ServerConfig serverConfig;
private final ServerConfig serverConfig;
public DefaultTypeFactory(ServerConfig serverConfig) {
this.serverConfig = serverConfig;
public DefaultTypeFactory(ServerConfig serverConfig) {
this.serverConfig = serverConfig;
}
protected ScalarType<Boolean> createBoolean(String trueValue, String falseValue) {
try {
// first try Integer based boolean
Integer intTrue = BasicTypeConverter.toInteger(trueValue);
Integer intFalse = BasicTypeConverter.toInteger(falseValue);
return new ScalarTypeBoolean.IntBoolean(intTrue, intFalse);
} catch (NumberFormatException e) {
// treat as Varchar/String based boolean
return new ScalarTypeBoolean.StringBoolean(trueValue, falseValue);
}
}
/**
* Create the ScalarType for mapping Booleans. For some databases this is a
* native data type and for others Booleans will be converted to Y/N or 0/1
* etc.
*/
public ScalarType<Boolean> createBoolean() {
if (serverConfig == null) {
return new ScalarTypeBoolean.Native();
}
String trueValue = serverConfig.getDatabaseBooleanTrue();
String falseValue = serverConfig.getDatabaseBooleanFalse();
if (falseValue != null && trueValue != null) {
// explicit integer or string based booleans
return createBoolean(trueValue, falseValue);
}
private ScalarType<Boolean> createBoolean(String trueValue, String falseValue) {
try {
// first try Integer based boolean
Integer intTrue = BasicTypeConverter.toInteger(trueValue);
Integer intFalse = BasicTypeConverter.toInteger(falseValue);
return new ScalarTypeBoolean.IntBoolean(intTrue, intFalse);
} catch (NumberFormatException e) {
}
// treat as Varchar/String based boolean
return new ScalarTypeBoolean.StringBoolean(trueValue, falseValue);
// determine based on database platform configuration
int booleanDbType = serverConfig.getDatabasePlatform().getBooleanDbType();
// Some dbs use BIT e.g. MySQL
if (booleanDbType == Types.BIT) {
return new ScalarTypeBoolean.BitBoolean();
}
/**
* Create the ScalarType for mapping Booleans. For some databases this is a
* native data type and for others Booleans will be converted to Y/N or 0/1
* etc.
*/
public ScalarType<Boolean> createBoolean() {
if (serverConfig == null) {
return new ScalarTypeBoolean.Native();
}
String trueValue = serverConfig.getDatabaseBooleanTrue();
String falseValue = serverConfig.getDatabaseBooleanFalse();
if (falseValue != null && trueValue != null) {
// explicit integer or string based booleans
return createBoolean(trueValue, falseValue);
}
// determine based on database platform configuration
int booleanDbType = serverConfig.getDatabasePlatform().getBooleanDbType();
// Some dbs use BIT e.g. MySQL
if (booleanDbType == Types.BIT) {
return new ScalarTypeBoolean.BitBoolean();
}
if (booleanDbType == Types.INTEGER) {
return new ScalarTypeBoolean.IntBoolean(1, 0);
}
if (booleanDbType == Types.VARCHAR) {
return new ScalarTypeBoolean.StringBoolean("T", "F");
}
if (booleanDbType == Types.BOOLEAN) {
return new ScalarTypeBoolean.Native();
}
// assume the JDBC driver can convert the type
return new ScalarTypeBoolean.Native();
if (booleanDbType == Types.INTEGER) {
return new ScalarTypeBoolean.IntBoolean(1, 0);
}
if (booleanDbType == Types.VARCHAR) {
return new ScalarTypeBoolean.StringBoolean("T", "F");
}
/**
* Create the default ScalarType for java.util.Date.
*/
public ScalarType<java.util.Date> 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(mode, utilDateType);
if (booleanDbType == Types.BOOLEAN) {
return new ScalarTypeBoolean.Native();
}
/**
* Create a ScalarType for java.util.Date explicitly specifying the type to
* map to.
*/
public ScalarType<java.util.Date> createUtilDate(JsonConfig.DateTime mode, int utilDateType) {
// assume the JDBC driver can convert the type
return new ScalarTypeBoolean.Native();
}
switch (utilDateType) {
case Types.DATE:
return new ScalarTypeUtilDate.DateType();
/**
* Create the default ScalarType for java.util.Date.
*/
public ScalarType<java.util.Date> 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");
case Types.TIMESTAMP:
return new ScalarTypeUtilDate.TimestampType(mode);
return createUtilDate(mode, utilDateType);
}
default:
throw new RuntimeException("Invalid type " + utilDateType);
}
/**
* Create a ScalarType for java.util.Date explicitly specifying the type to
* map to.
*/
public ScalarType<java.util.Date> createUtilDate(JsonConfig.DateTime mode, int utilDateType) {
switch (utilDateType) {
case Types.DATE:
return new ScalarTypeUtilDate.DateType();
case Types.TIMESTAMP:
return new ScalarTypeUtilDate.TimestampType(mode);
default:
throw new RuntimeException("Invalid type " + utilDateType);
}
}
/**
* Create the default ScalarType for java.util.Calendar.
*/
public ScalarType<Calendar> createCalendar(JsonConfig.DateTime mode) {
/**
* Create the default ScalarType for java.util.Calendar.
*/
public ScalarType<Calendar> createCalendar(JsonConfig.DateTime mode) {
int jdbcType = getTemporalMapType("timestamp");
return createCalendar(mode, 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<Calendar> createCalendar(JsonConfig.DateTime mode, int jdbcType) {
return new ScalarTypeCalendar(mode, jdbcType);
}
private int getTemporalMapType(String mapType) {
if (mapType.equalsIgnoreCase("date")) {
return java.sql.Types.DATE;
}
return java.sql.Types.TIMESTAMP;
}
/**
* Create a ScalarType for java.util.Calendar explicitly specifying the type
* to map to.
*/
public ScalarType<Calendar> createCalendar(JsonConfig.DateTime mode, int jdbcType) {
/**
* Create a ScalarType for java.math.BigInteger.
*/
public ScalarType<BigInteger> createMathBigInteger() {
return new ScalarTypeCalendar(mode, jdbcType);
}
private int getTemporalMapType(String mapType) {
if (mapType.equalsIgnoreCase("date")) {
return java.sql.Types.DATE;
}
return java.sql.Types.TIMESTAMP;
}
/**
* Create a ScalarType for java.math.BigInteger.
*/
public ScalarType<BigInteger> createMathBigInteger() {
return new ScalarTypeMathBigInteger();
}
return new ScalarTypeMathBigInteger();
}
}
@@ -1,6 +1,25 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.annotation.EnumMapping;
import com.avaje.ebean.annotation.EnumValue;
import com.avaje.ebean.config.*;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebeaninternal.api.ClassUtil;
import com.avaje.ebeaninternal.server.core.BootupClasses;
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
import com.avaje.ebeaninternal.server.type.reflect.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.joda.time.*;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -12,41 +31,12 @@ 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;
import java.util.Currency;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
import java.time.Duration;
import java.time.Instant;
import java.time.Period;
import java.util.*;
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;
import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.annotation.EnumMapping;
import com.avaje.ebean.annotation.EnumValue;
import com.avaje.ebeaninternal.api.ClassUtil;
import com.avaje.ebeaninternal.server.core.BootupClasses;
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutable;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
import com.avaje.ebeaninternal.server.type.reflect.ImmutableMeta;
import com.avaje.ebeaninternal.server.type.reflect.ImmutableMetaFactory;
import com.avaje.ebeaninternal.server.type.reflect.KnownImmutable;
import com.avaje.ebeaninternal.server.type.reflect.ReflectionBasedCompoundType;
import com.avaje.ebeaninternal.server.type.reflect.ReflectionBasedCompoundTypeProperty;
import com.avaje.ebeaninternal.server.type.reflect.ReflectionBasedTypeBuilder;
/**
* Default implementation of TypeManager.
* <p>
@@ -63,10 +53,16 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
private final ConcurrentHashMap<Integer, ScalarType<?>> nativeMap;
private final ConcurrentHashMap<String, ScalarType<?>> customTypeMap;
private final DefaultTypeFactory extraTypeFactory;
private final ScalarTypeJsonMap JSON_MAP_CLOB = new ScalarTypeJsonMap.Clob();
private final ScalarTypeJsonMap jsonMapClob = JSON_MAP_CLOB;
private final ScalarTypeJsonMap jsonMapBlob = new ScalarTypeJsonMap.Blob();
private final ScalarTypeJsonMap jsonMapVarchar = new ScalarTypeJsonMap.Varchar();
private final ScalarTypeJsonMap jsonMapJson;
private final ScalarTypeJsonMap jsonMapJsonb;
private final ScalarTypeFile fileType = new ScalarTypeFile();
private final ScalarType<?> charType = new ScalarTypeChar();
@@ -125,14 +121,36 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
private final JsonConfig.DateTime jsonDateTime;
private final boolean objectMapperPresent;
// OPTIONAL ScalarTypes registered if Jackson/JsonNode is in the classpath
/**
* Jackson's JsonNode storage to Clob.
*/
private ScalarType<?> jsonNodeClob;
/**
* Jackson's JsonNode storage to Blob.
*/
private ScalarType<?> jsonNodeBlob;
/**
* Jackson's JsonNode storage to Varchar.
*/
private ScalarType<?> jsonNodeVarchar;
/**
* Jackson's JsonNode storage to Postgres JSON or Clob.
*/
private ScalarType<?> jsonNodeJson;
/**
* Jackson's JsonNode storage to Postgres JSONB or Clob.
*/
private ScalarType<?> jsonNodeJsonb;
/**
* Create the DefaultTypeManager.
*/
public DefaultTypeManager(ServerConfig config, BootupClasses bootupClasses) {
int clobType = config.getDatabasePlatform().getClobDbType();
int blobType = config.getDatabasePlatform().getBlobDbType();
this.jsonDateTime = config.getJsonDateTime();
this.checkImmutable = new CheckImmutable(this);
this.reflectScalarBuilder = new ReflectionBasedTypeBuilder(this);
@@ -140,29 +158,34 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
this.compoundTypeMap = new ConcurrentHashMap<Class<?>, CtCompoundType<?>>();
this.typeMap = new ConcurrentHashMap<Class<?>, ScalarType<?>>();
this.nativeMap = new ConcurrentHashMap<Integer, ScalarType<?>>();
this.customTypeMap = new ConcurrentHashMap<String, ScalarType<?>>();
this.customTypeMap.put(ScalarTypePostgresHstore.KEY, new ScalarTypePostgresHstore());
this.objectMapperPresent = ClassUtil.isPresent("com.fasterxml.jackson.databind.ObjectMapper", this.getClass());
this.extraTypeFactory = new DefaultTypeFactory(config);
initialiseStandard(jsonDateTime, clobType, blobType, config.isUuidStoreAsBinary());
initialiseStandard(jsonDateTime, config);
initialiseJavaTimeTypes(jsonDateTime, config);
initialiseJodaTypes(jsonDateTime);
initialiseJacksonTypes(config);
if (isPostgres(config.getDatabasePlatform())) {
// Postgres has special DB types for JSON/JSONB
this.jsonMapJson = new ScalarTypeJsonMapPostgres.JSON();
this.jsonMapJsonb = new ScalarTypeJsonMapPostgres.JSONB();
} else {
this.jsonMapJson = JSON_MAP_CLOB;
this.jsonMapJsonb = JSON_MAP_CLOB;
}
if (bootupClasses != null) {
initialiseCustomScalarTypes(jsonDateTime, bootupClasses);
initialiseCustomScalarTypes(jsonDateTime, bootupClasses, config);
initialiseScalarConverters(bootupClasses);
initialiseCompoundTypes(bootupClasses);
}
}
/**
* Lookup a special or custom scalar type by key.
*/
@Override
public ScalarType<?> getScalarTypeFromKey(String specialTypeKey) {
return customTypeMap.get(specialTypeKey);
private boolean isPostgres(DatabasePlatform databasePlatform) {
return databasePlatform.getName().toLowerCase().startsWith("postgre");
}
public boolean isKnownImmutable(Class<?> cls) {
@@ -289,6 +312,38 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
return reader;
}
@Override
public ScalarType<?> getJsonScalarType(Class<?> type, int dbType) {
if (type.equals(Map.class)) {
// @DbJson Map<String,Object> property
switch (dbType) {
case Types.VARCHAR : return jsonMapVarchar;
case Types.BLOB: return jsonMapBlob;
case Types.CLOB : return jsonMapClob;
case DbType.JSONB: return jsonMapJsonb;
case DbType.JSON: return jsonMapJson;
default:
return jsonMapJson;
}
}
if (type.equals(JsonNode.class)) {
// @DbJson JsonNode property (Jackson)
switch (dbType) {
case Types.VARCHAR : return jsonNodeVarchar;
case Types.BLOB: return jsonNodeBlob;
case Types.CLOB : return jsonNodeClob;
case DbType.JSONB: return jsonNodeJsonb;
case DbType.JSON: return jsonNodeJson;
default:
return jsonNodeJson;
}
}
throw new IllegalArgumentException("Type [" + type + "] unsupported for @DbJson mapping");
}
/**
* Return a ScalarType for a given class.
* <p>
@@ -364,8 +419,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
return value;
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private boolean isIntegerType(String s) {
try {
Integer.parseInt(s);
return true;
@@ -468,7 +523,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
* interface and register it with this TypeManager.
* </p>
*/
protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses) {
protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses, ServerConfig serverConfig) {
ScalarTypeLongToTimestamp longToTimestamp = new ScalarTypeLongToTimestamp(mode);
@@ -480,9 +535,22 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
Class<?> cls = foundTypes.get(i);
try {
ScalarType<?> scalarType = (ScalarType<?>) cls.newInstance();
add(scalarType);
ScalarType<?> scalarType;
if (!objectMapperPresent) {
scalarType = (ScalarType<?>) cls.newInstance();
} else {
try {
// first try objectMapper constructor
Constructor<?> constructor = cls.getConstructor(ObjectMapper.class);
ObjectMapper objectMapper = getObjectMapper(serverConfig);
scalarType = (ScalarType<?>)constructor.newInstance(objectMapper);
} catch (NoSuchMethodException e) {
scalarType = (ScalarType<?>) cls.newInstance();
}
}
add(scalarType);
customScalarTypes.add(scalarType);
} catch (Exception e) {
@@ -492,6 +560,16 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
}
}
private ObjectMapper getObjectMapper(ServerConfig serverConfig) {
ObjectMapper objectMapper = (ObjectMapper)serverConfig.getObjectMapper();
if (objectMapper == null) {
objectMapper = new ObjectMapper();
serverConfig.setObjectMapper(objectMapper);
}
return objectMapper;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void initialiseScalarConverters(BootupClasses bootupClasses) {
@@ -606,6 +684,38 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
return propParamTypes[1];
}
/**
* Add support for Jackson's JsonNode mapping to Clob, Blob, Varchar, JSON and JSONB.
*/
protected void initialiseJacksonTypes(ServerConfig config) {
if (ClassUtil.isPresent("com.fasterxml.jackson.databind.ObjectMapper", this.getClass())) {
logger.trace("Registering JsonNode type support");
ObjectMapper objectMapper = (ObjectMapper)config.getObjectMapper();
if (objectMapper == null) {
objectMapper = new ObjectMapper();
config.setObjectMapper(objectMapper);
}
jsonNodeClob = new ScalarTypeJsonNode.Clob(objectMapper);
jsonNodeBlob = new ScalarTypeJsonNode.Blob(objectMapper);
jsonNodeVarchar = new ScalarTypeJsonNode.Varchar(objectMapper);
jsonNodeJson = jsonNodeClob; // Default for non-Postgres databases
jsonNodeJsonb = jsonNodeClob; // Default for non-Postgres databases
if (isPostgres(config.getDatabasePlatform())) {
jsonNodeJson = new ScalarTypeJsonNodePostgres.JSON(objectMapper);
jsonNodeJsonb = new ScalarTypeJsonNodePostgres.JSONB(objectMapper);
}
// add as default mapping for JsonNode (when not annotated with @DbJson etc)
typeMap.put(JsonNode.class, jsonNodeJson);
}
}
protected void initialiseJavaTimeTypes(JsonConfig.DateTime mode, ServerConfig config) {
if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) {
logger.debug("Registering java.time data types");
@@ -656,7 +766,14 @@ 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(JsonConfig.DateTime mode, int platformClobType, int platformBlobType, boolean binaryUUID) {
protected void initialiseStandard(JsonConfig.DateTime mode, ServerConfig config) {
boolean binaryUUID = config.isUuidStoreAsBinary();
DatabasePlatform databasePlatform = config.getDatabasePlatform();
int platformClobType = databasePlatform.getClobDbType();
int platformBlobType = databasePlatform.getBlobDbType();
nativeMap.put(DbType.HSTORE, new ScalarTypePostgresHstore());
ScalarType<?> utilDateType = extraTypeFactory.createUtilDate(mode);
typeMap.put(java.util.Date.class, utilDateType);
@@ -10,52 +10,52 @@ import javax.persistence.PersistenceException;
*/
public class EnumToDbIntegerMap extends EnumToDbValueMap<Integer> {
@Override
public int getDbType() {
return Types.INTEGER;
}
@Override
public int getDbType() {
return Types.INTEGER;
}
public EnumToDbIntegerMap add(Object beanValue, Integer dbValue) {
addInternal(beanValue, dbValue);
return this;
}
@Override
public EnumToDbIntegerMap add(Object beanValue, String stringDbValue) {
@Override
public EnumToDbIntegerMap add(Object beanValue, String stringDbValue) {
try {
Integer value = Integer.valueOf(stringDbValue);
addInternal(beanValue, value);
return this;
try {
Integer value = Integer.valueOf(stringDbValue);
addInternal(beanValue, value);
} catch (Exception e) {
String msg = "Error converted enum type[" + beanValue.getClass().getName();
msg += "] enum value[" + beanValue + "] string value [" + stringDbValue + "]";
msg += " to an Integer.";
throw new PersistenceException(msg, e);
}
}
return this;
@Override
public void bind(DataBind b, Object value) throws SQLException {
if (value == null) {
b.setNull(Types.INTEGER);
} else {
Integer s = getDbValue(value);
b.setInt(s);
}
} catch (Exception e) {
String msg = "Error converted enum type[" + beanValue.getClass().getName();
msg += "] enum value[" + beanValue + "] string value [" + stringDbValue + "]";
msg += " to an Integer.";
throw new PersistenceException(msg, e);
}
}
}
@Override
public void bind(DataBind b, Object value) throws SQLException {
if (value == null) {
b.setNull(Types.INTEGER);
} else {
Integer s = getDbValue(value);
b.setInt(s);
}
@Override
public Object read(DataReader dataReader) throws SQLException {
Integer i = dataReader.getInt();
if (i == null) {
return null;
} else {
return getBeanValue(i);
}
}
}
@Override
public Object read(DataReader dataReader) throws SQLException {
Integer i = dataReader.getInt();
if (i == null) {
return null;
} else {
return getBeanValue(i);
}
}
}
@@ -8,38 +8,37 @@ import java.sql.Types;
*/
public class EnumToDbStringMap extends EnumToDbValueMap<String> {
@Override
public int getDbType() {
return Types.VARCHAR;
}
@Override
public EnumToDbStringMap add(Object beanValue, String dbValue) {
addInternal(beanValue, dbValue);
return this;
}
@Override
public int getDbType() {
return Types.VARCHAR;
}
@Override
public void bind(DataBind b, Object value) throws SQLException {
if (value == null){
b.setNull(Types.VARCHAR);
} else {
String s = getDbValue(value);
b.setString(s);
}
}
@Override
public EnumToDbStringMap add(Object beanValue, String dbValue) {
addInternal(beanValue, dbValue);
return this;
}
@Override
public void bind(DataBind b, Object value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
} else {
String s = getDbValue(value);
b.setString(s);
}
}
@Override
public Object read(DataReader dataReader) throws SQLException {
String s = dataReader.getString();
if (s == null) {
return null;
} else {
return getBeanValue(s);
}
}
@Override
public Object read(DataReader dataReader) throws SQLException {
String s = dataReader.getString();
if (s == null){
return null;
} else {
return getBeanValue(s);
}
}
}
@@ -13,122 +13,115 @@ import java.util.LinkedHashMap;
*/
public abstract class EnumToDbValueMap<T> {
public static EnumToDbValueMap<?> create(boolean integerType) {
return integerType ? new EnumToDbIntegerMap() : new EnumToDbStringMap();
}
public static EnumToDbValueMap<?> create(boolean integerType) {
return integerType ? new EnumToDbIntegerMap() : new EnumToDbStringMap();
}
final LinkedHashMap<Object, T> keyMap;
final LinkedHashMap<Object, T> keyMap;
final LinkedHashMap<T, Object> valueMap;
final LinkedHashMap<T, Object> valueMap;
final boolean allowNulls;
final boolean allowNulls;
final boolean isIntegerType;
final boolean isIntegerType;
/**
* Construct with allowNulls defaulting to false.
*/
public EnumToDbValueMap() {
this(false, false);
}
/**
* Construct with allowNulls defaulting to false.
*/
public EnumToDbValueMap() {
this(false, false);
}
/**
* Construct with allowNulls setting.
* <p>
* If allowNulls is false then an IllegalArgumentException is thrown by
* either the getDBValue or getBeanValue methods if not matching Bean or DB
* value is found.
* </p>
*/
public EnumToDbValueMap(boolean allowNulls, boolean isIntegerType) {
this.allowNulls = allowNulls;
this.isIntegerType = isIntegerType;
keyMap = new LinkedHashMap<Object, T>();
valueMap = new LinkedHashMap<T, Object>();
}
/**
* Construct with allowNulls setting.
* <p>
* If allowNulls is false then an IllegalArgumentException is thrown by
* either the getDBValue or getBeanValue methods if not matching Bean or DB
* value is found.
* </p>
*/
public EnumToDbValueMap(boolean allowNulls, boolean isIntegerType) {
this.allowNulls = allowNulls;
this.isIntegerType = isIntegerType;
keyMap = new LinkedHashMap<Object, T>();
valueMap = new LinkedHashMap<T, Object>();
}
/**
* Return true if this is mapping to integers, false
* if mapping to Strings.
*/
public boolean isIntegerType() {
return isIntegerType;
}
/**
* Return true if this is mapping to integers, false
* if mapping to Strings.
*/
public boolean isIntegerType() {
return isIntegerType;
}
/**
* Return the DB values.
*/
public Iterator<T> dbValues() {
return valueMap.keySet().iterator();
}
/**
* Return the DB values.
*/
public Iterator<T> dbValues() {
return valueMap.keySet().iterator();
}
/**
* Return the bean 'key' value.
*/
public Iterator<Object> beanValues() {
return valueMap.values().iterator();
}
/**
* Bind using the correct database type.
*/
public abstract void bind(DataBind b, Object value) throws SQLException;
/**
* Bind using the correct database type.
*/
public abstract void bind(DataBind b, Object value) throws SQLException;
/**
* Read using the correct database type.
*/
public abstract Object read(DataReader dataReader) throws SQLException;
/**
* Read using the correct database type.
*/
public abstract Object read(DataReader dataReader) throws SQLException;
/**
* Return the database type.
*/
public abstract int getDbType();
/**
* Return the database type.
*/
public abstract int getDbType();
/**
* Add name value pair where the dbValue is the raw string and may need to
* be converted (to an Integer for example).
*/
public abstract EnumToDbValueMap<T> add(Object beanValue, String dbValue);
/**
* Add name value pair where the dbValue is the raw string and may need to
* be converted (to an Integer for example).
*/
public abstract EnumToDbValueMap<T> add(Object beanValue, String dbValue);
/**
* Add a bean value and DB value pair.
* <p>
* The dbValue will be converted to an Integer if isIntegerType is true;
* </p>
*/
protected void addInternal(Object beanValue, T dbValue) {
/**
* Add a bean value and DB value pair.
* <p>
* The dbValue will be converted to an Integer if isIntegerType is true;
* </p>
*/
protected void addInternal(Object beanValue, T dbValue) {
keyMap.put(beanValue, dbValue);
valueMap.put(dbValue, beanValue);
}
keyMap.put(beanValue, dbValue);
valueMap.put(dbValue, beanValue);
}
/**
* Return the DB value given the bean value.
*/
public T getDbValue(Object beanValue) {
if (beanValue == null) {
return null;
}
T dbValue = keyMap.get(beanValue);
if (dbValue == null && !allowNulls) {
String msg = "DB value for " + beanValue + " not found in " + keyMap;
throw new IllegalArgumentException(msg);
}
return dbValue;
}
/**
* Return the DB value given the bean value.
*/
public T getDbValue(Object beanValue) {
if (beanValue == null) {
return null;
}
T dbValue = keyMap.get(beanValue);
if (dbValue == null && !allowNulls) {
String msg = "DB value for " + beanValue + " not found in " + keyMap;
throw new IllegalArgumentException(msg);
}
return dbValue;
}
/**
* Return the Bean value given the DB value.
*/
public Object getBeanValue(T dbValue) {
if (dbValue == null) {
return null;
}
Object beanValue = valueMap.get(dbValue);
if (beanValue == null && !allowNulls) {
String msg = "Bean value for " + dbValue + " not found in " + valueMap;
throw new IllegalArgumentException(msg);
}
return beanValue;
}
/**
* Return the Bean value given the DB value.
*/
public Object getBeanValue(T dbValue) {
if (dbValue == null) {
return null;
}
Object beanValue = valueMap.get(dbValue);
if (beanValue == null && !allowNulls) {
String msg = "Bean value for " + dbValue + " not found in " + valueMap;
throw new IllegalArgumentException(msg);
}
return beanValue;
}
}
@@ -4,21 +4,21 @@ import java.sql.Timestamp;
import com.avaje.ebean.config.ScalarTypeConverter;
public class LongToTimestampConverter implements ScalarTypeConverter<Long, Timestamp>{
public Long getNullValue() {
return null;
}
public class LongToTimestampConverter implements ScalarTypeConverter<Long, Timestamp> {
public Timestamp unwrapValue(Long beanType) {
return new Timestamp(beanType.longValue());
}
public Long getNullValue() {
return null;
}
public Timestamp unwrapValue(Long beanType) {
return new Timestamp(beanType.longValue());
}
public Long wrapValue(Timestamp scalarType) {
return scalarType.getTime();
}
public Long wrapValue(Timestamp scalarType) {
return scalarType.getTime();
}
}
@@ -22,7 +22,7 @@ public class ModifyAwareCollection<E> implements Collection<E> {
this.owner = owner;
this.c = c;
}
public String toString() {
return c.toString();
}
@@ -37,9 +37,7 @@ public class ModifyAwareCollection<E> implements Collection<E> {
public boolean addAll(Collection<? extends E> collection) {
boolean changed = false;
Iterator<? extends E> it = collection.iterator();
while (it.hasNext()) {
E o = it.next();
for (E o : collection) {
if (c.add(o)) {
owner.markAsModified();
changed = true;
@@ -68,7 +66,7 @@ public class ModifyAwareCollection<E> implements Collection<E> {
}
public Iterator<E> iterator() {
return new ModifyAwareIterator<E>(owner, c.iterator());
return new ModifyAwareIterator<E>(owner, c.iterator());
}
public boolean remove(Object o) {
@@ -81,10 +79,8 @@ public class ModifyAwareCollection<E> implements Collection<E> {
public boolean removeAll(Collection<?> collection) {
boolean changed = false;
Iterator<?> it = collection.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (c.remove(o)) {
for (Object element : collection) {
if (c.remove(element)) {
owner.markAsModified();
changed = true;
}
@@ -96,7 +92,7 @@ public class ModifyAwareCollection<E> implements Collection<E> {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
Object o = it.next();
if (!collection.contains(o)) {
it.remove();
owner.markAsModified();
@@ -0,0 +1,26 @@
package com.avaje.ebeaninternal.server.type;
/**
* Detects when content has been modified and as such needs to be persisted (included in an update).
*/
public class ModifyAwareFlag implements ModifyAwareOwner {
boolean dirty;
@Override
public boolean isMarkedDirty() {
if (!dirty) return false;
dirty = false;
return true;
}
@Override
public void markAsModified() {
dirty = true;
}
@Override
public void resetMarkedDirty() {
dirty = false;
}
}
@@ -0,0 +1,166 @@
package com.avaje.ebeaninternal.server.type;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* Modify aware wrapper of a list.
*/
public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
final List<E> list;
final ModifyAwareOwner owner;
public ModifyAwareList(List<E> list) {
this.list = list;
this.owner = new ModifyAwareFlag();
}
public ModifyAwareList(ModifyAwareOwner owner, List<E> list) {
this.list = list;
this.owner = owner;
}
@Override
public boolean isMarkedDirty() {
return owner.isMarkedDirty();
}
@Override
public void markAsModified() {
owner.markAsModified();
}
@Override
public void resetMarkedDirty() {
owner.resetMarkedDirty();
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator<E> iterator() {
return new ModifyAwareIterator<E>(owner, list.iterator());
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean add(E e) {
owner.markAsModified();
return list.add(e);
}
@Override
public boolean remove(Object o) {
owner.markAsModified();
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
owner.markAsModified();
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
owner.markAsModified();
return list.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
owner.markAsModified();
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
owner.markAsModified();
return list.retainAll(c);
}
@Override
public void clear() {
owner.markAsModified();
list.clear();
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
public E set(int index, E element) {
owner.markAsModified();
return list.set(index, element);
}
@Override
public void add(int index, E element) {
owner.markAsModified();
list.add(index, element);
}
@Override
public E remove(int index) {
owner.markAsModified();
return list.remove(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
return new ModifyAwareListIterator<E>(owner, list.listIterator());
}
@Override
public ListIterator<E> listIterator(int index) {
return new ModifyAwareListIterator<E>(owner, list.listIterator(index));
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return new ModifyAwareList<E>(owner,list.subList(fromIndex, toIndex));
}
}
@@ -0,0 +1,66 @@
package com.avaje.ebeaninternal.server.type;
import java.util.ListIterator;
/**
* Modify aware wrapper of a ListIterator.
*/
public class ModifyAwareListIterator<E> implements ListIterator<E> {
final ModifyAwareOwner owner;
final ListIterator<E> iterator;
public ModifyAwareListIterator(ModifyAwareOwner owner, ListIterator<E> iterator) {
this.owner = owner;
this.iterator = iterator;
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public E next() {
return iterator.next();
}
@Override
public boolean hasPrevious() {
return iterator.hasPrevious();
}
@Override
public E previous() {
return iterator.previous();
}
@Override
public int nextIndex() {
return iterator.nextIndex();
}
@Override
public int previousIndex() {
return iterator.previousIndex();
}
@Override
public void remove() {
owner.markAsModified();
iterator.remove();
}
@Override
public void set(E e) {
owner.markAsModified();
iterator.set(e);
}
@Override
public void add(E e) {
owner.markAsModified();
iterator.add(e);
}
}
@@ -7,36 +7,44 @@ import java.util.Set;
/**
* Map that is wraps an underlying map for the purpose of detecting changes.
*/
public class ModifyAwareMap<K,V> implements Map<K,V>, ModifyAwareOwner {
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
final ModifyAwareOwner owner;
/**
* Dirty flag set when the map has been modified.
*/
private boolean dirty;
/**
* The underlying map.
*/
private Map<K,V> map;
public ModifyAwareMap(Map<K,V> underyling) {
final Map<K, V> map;
public ModifyAwareMap(Map<K, V> underyling) {
this.map = underyling;
this.owner = new ModifyAwareFlag();
}
public ModifyAwareMap(ModifyAwareOwner owner, Map<K, V> underyling) {
this.owner = owner;
this.map = underyling;
}
public String toString() {
return map.toString();
}
@Override
public boolean isMarkedDirty() {
return dirty;
return owner.isMarkedDirty();
}
@Override
public void markAsModified() {
dirty = true;
owner.markAsModified();
}
@Override
public void resetMarkedDirty() {
owner.resetMarkedDirty();
}
@Override
public int size() {
return map.size();
@@ -72,7 +80,7 @@ public class ModifyAwareMap<K,V> implements Map<K,V>, ModifyAwareOwner {
public V remove(Object key) {
V value = map.remove(key);
if (value != null) {
markAsModified();
markAsModified();
}
return value;
}
@@ -107,5 +115,4 @@ public class ModifyAwareMap<K,V> implements Map<K,V>, ModifyAwareOwner {
return new ModifyAwareSet<Map.Entry<K, V>>(this, map.entrySet());
}
}
@@ -7,11 +7,18 @@ public interface ModifyAwareOwner {
/**
* Return true if the value is considered dirty.
* Note that this resets the dirty status back to clean.
*/
public boolean isMarkedDirty();
boolean isMarkedDirty();
/**
* Marks the object as modified.
*/
public void markAsModified();
void markAsModified();
/**
* Reset the dirty state to clean.
*/
void resetMarkedDirty();
}
@@ -2,5 +2,5 @@ package com.avaje.ebeaninternal.server.type;
public interface ModifyAwareType {
public boolean isDirty();
boolean isDirty();
}
@@ -19,225 +19,241 @@ import com.avaje.ebeaninternal.server.core.Message;
public class RsetDataReader implements DataReader {
private static final int bufferSize = 512;
private static final int bufferSize = 512;
static final int clobBufferSize = 512;
static final int stringInitialSize = 512;
static final int clobBufferSize = 512;
private final ResultSet rset;
protected int pos;
public RsetDataReader(ResultSet rset) {
this.rset = rset;
static final int stringInitialSize = 512;
private final ResultSet rset;
protected int pos;
public RsetDataReader(ResultSet rset) {
this.rset = rset;
}
public void close() throws SQLException {
rset.close();
}
public boolean next() throws SQLException {
return rset.next();
}
public void resetColumnPosition() {
pos = 0;
}
public void incrementPos(int increment) {
pos += increment;
}
protected int pos() {
return ++pos;
}
public Array getArray() throws SQLException {
return rset.getArray(pos());
}
public InputStream getAsciiStream() throws SQLException {
return rset.getAsciiStream(pos());
}
public Object getObject() throws SQLException {
return rset.getObject(pos());
}
public BigDecimal getBigDecimal() throws SQLException {
return rset.getBigDecimal(pos());
}
public InputStream getBinaryStream() throws SQLException {
return rset.getBinaryStream(pos());
}
public Boolean getBoolean() throws SQLException {
boolean v = rset.getBoolean(pos());
if (rset.wasNull()) {
return null;
}
return v;
}
public Byte getByte() throws SQLException {
byte v = rset.getByte(pos());
if (rset.wasNull()) {
return null;
}
return v;
}
public byte[] getBytes() throws SQLException {
return rset.getBytes(pos());
}
public Date getDate() throws SQLException {
return rset.getDate(pos());
}
public Double getDouble() throws SQLException {
double v = rset.getDouble(pos());
if (rset.wasNull()) {
return null;
}
return v;
}
public Float getFloat() throws SQLException {
float v = rset.getFloat(pos());
if (rset.wasNull()) {
return null;
}
return v;
}
public Integer getInt() throws SQLException {
int v = rset.getInt(pos());
if (rset.wasNull()) {
return null;
}
return v;
}
public Long getLong() throws SQLException {
long v = rset.getLong(pos());
if (rset.wasNull()) {
return null;
}
return v;
}
public Ref getRef() throws SQLException {
return rset.getRef(pos());
}
public Short getShort() throws SQLException {
short s = rset.getShort(pos());
if (rset.wasNull()) {
return null;
}
return s;
}
public String getString() throws SQLException {
return rset.getString(pos());
}
public Time getTime() throws SQLException {
return rset.getTime(pos());
}
public Timestamp getTimestamp() throws SQLException {
return rset.getTimestamp(pos());
}
public String getStringFromStream() throws SQLException {
Reader reader = rset.getCharacterStream(pos());
if (reader == null) {
return null;
}
return readStringLob(reader);
}
@Override
public Reader getClobReader() throws SQLException {
Clob clob = rset.getClob(pos());
if (clob == null) {
return null;
}
return clob.getCharacterStream();
}
public String getStringClob() throws SQLException {
Clob clob = rset.getClob(pos());
if (clob == null) {
return null;
}
Reader reader = clob.getCharacterStream();
if (reader == null) {
return null;
}
return readStringLob(reader);
}
protected String readStringLob(Reader reader) throws SQLException {
char[] buffer = new char[clobBufferSize];
int readLength;
StringBuilder out = new StringBuilder(stringInitialSize);
try {
while ((readLength = reader.read(buffer)) != -1) {
out.append(buffer, 0, readLength);
}
reader.close();
} catch (IOException e) {
throw new SQLException(Message.msg("persist.clob.io", e.getMessage()));
}
public void close() throws SQLException {
rset.close();
return out.toString();
}
public byte[] getBinaryBytes() throws SQLException {
InputStream in = rset.getBinaryStream(pos());
return getBinaryLob(in);
}
public byte[] getBlobBytes() throws SQLException {
Blob blob = rset.getBlob(pos());
if (blob == null) {
return null;
}
InputStream in = blob.getBinaryStream();
return getBinaryLob(in);
}
public boolean next() throws SQLException {
return rset.next();
public InputStream getBlobInputStream() throws SQLException {
Blob blob = rset.getBlob(pos());
if (blob == null) {
return null;
}
public void resetColumnPosition() {
pos = 0;
}
public void incrementPos(int increment){
pos += increment;
}
protected int pos() {
return ++pos;
}
public Array getArray() throws SQLException {
return rset.getArray(pos());
}
public InputStream getAsciiStream() throws SQLException {
return rset.getAsciiStream(pos());
}
public Object getObject() throws SQLException {
return rset.getObject(pos());
}
public BigDecimal getBigDecimal() throws SQLException {
return rset.getBigDecimal(pos());
}
public InputStream getBinaryStream() throws SQLException {
return rset.getBinaryStream(pos());
}
public Boolean getBoolean() throws SQLException {
boolean v = rset.getBoolean(pos());
if (rset.wasNull()){
return null;
}
return Boolean.valueOf(v);
}
public Byte getByte() throws SQLException {
byte v = rset.getByte(pos());
if (rset.wasNull()){
return null;
}
return Byte.valueOf(v);
}
public byte[] getBytes() throws SQLException {
return rset.getBytes(pos());
}
public Date getDate() throws SQLException {
return rset.getDate(pos());
}
public Double getDouble() throws SQLException {
double v = rset.getDouble(pos());
if (rset.wasNull()){
return null;
}
return Double.valueOf(v);
}
public Float getFloat() throws SQLException {
float v = rset.getFloat(pos());
if (rset.wasNull()){
return null;
}
return Float.valueOf(v);
}
public Integer getInt() throws SQLException {
int v = rset.getInt(pos());
if (rset.wasNull()){
return null;
}
return Integer.valueOf(v);
}
public Long getLong() throws SQLException {
long v = rset.getLong(pos());
if (rset.wasNull()){
return null;
}
return Long.valueOf(v);
}
public Ref getRef() throws SQLException {
return rset.getRef(pos());
}
public Short getShort() throws SQLException {
short s = rset.getShort(pos());
if (rset.wasNull()){
return null;
}
return Short.valueOf(s);
}
public String getString() throws SQLException {
return rset.getString(pos());
}
public Time getTime() throws SQLException {
return rset.getTime(pos());
}
public Timestamp getTimestamp() throws SQLException {
return rset.getTimestamp(pos());
}
public String getStringFromStream() throws SQLException {
Reader reader = rset.getCharacterStream(pos());
if (reader == null) {
return null;
}
return readStringLob(reader);
}
public String getStringClob() throws SQLException {
Clob clob = rset.getClob(pos());
if (clob == null) {
return null;
}
Reader reader = clob.getCharacterStream();
if (reader == null) {
return null;
}
return readStringLob(reader);
}
protected String readStringLob(Reader reader) throws SQLException {
char[] buffer = new char[clobBufferSize];
int readLength = 0;
StringBuilder out = new StringBuilder(stringInitialSize);
try {
while ((readLength = reader.read(buffer)) != -1) {
out.append(buffer, 0, readLength);
}
reader.close();
} catch (IOException e) {
throw new SQLException(Message.msg("persist.clob.io", e.getMessage()));
}
return out.toString();
}
public byte[] getBinaryBytes() throws SQLException {
InputStream in = rset.getBinaryStream(pos());
return getBinaryLob(in);
}
public byte[] getBlobBytes() throws SQLException {
Blob blob = rset.getBlob(pos());
if (blob == null) {
return null;
}
InputStream in = blob.getBinaryStream();
return getBinaryLob(in);
}
protected byte[] getBinaryLob(InputStream in) throws SQLException {
try {
if (in == null) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[bufferSize];
int len;
while ((len = in.read(buf, 0, buf.length)) != -1) {
out.write(buf, 0, len);
}
byte[] data = out.toByteArray();
if (data.length == 0) {
data = null;
}
in.close();
out.close();
return data;
} catch (IOException e) {
throw new SQLException(e.getClass().getName() + ":" + e.getMessage());
}
return blob.getBinaryStream();
}
protected byte[] getBinaryLob(InputStream in) throws SQLException {
try {
if (in == null) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[bufferSize];
int len;
while ((len = in.read(buf, 0, buf.length)) != -1) {
out.write(buf, 0, len);
}
byte[] data = out.toByteArray();
if (data.length == 0) {
data = null;
}
in.close();
out.close();
return data;
} catch (IOException e) {
throw new SQLException(e.getClass().getName() + ":" + e.getMessage());
}
}
}
@@ -4,25 +4,25 @@ import java.sql.ResultSet;
public class RsetDataReaderIndexed extends RsetDataReader {
private final int[] rsetIndexPositions;
public RsetDataReaderIndexed(ResultSet rset, int[] rsetIndexPositions, boolean rowNumberIncluded) {
super(rset);
if (!rowNumberIncluded){
this.rsetIndexPositions = rsetIndexPositions;
} else {
this.rsetIndexPositions = new int[rsetIndexPositions.length+1];
for (int i = 0; i < rsetIndexPositions.length; i++) {
// increment all the column indexes by 1
this.rsetIndexPositions[i+1] = rsetIndexPositions[i]+1;
}
}
}
private final int[] rsetIndexPositions;
@Override
protected int pos() {
int i = pos++;
return rsetIndexPositions[i];
public RsetDataReaderIndexed(ResultSet rset, int[] rsetIndexPositions, boolean rowNumberIncluded) {
super(rset);
if (!rowNumberIncluded) {
this.rsetIndexPositions = rsetIndexPositions;
} else {
this.rsetIndexPositions = new int[rsetIndexPositions.length + 1];
for (int i = 0; i < rsetIndexPositions.length; i++) {
// increment all the column indexes by 1
this.rsetIndexPositions[i + 1] = rsetIndexPositions[i] + 1;
}
}
}
@Override
protected int pos() {
int i = pos++;
return rsetIndexPositions[i];
}
}
@@ -7,24 +7,24 @@ import java.sql.SQLException;
*/
public interface ScalarDataReader<T> {
/**
* Read and return the appropriate value from the dataReader.
*/
public T read(DataReader dataReader) throws SQLException;
/**
* Read and return the appropriate value from the dataReader.
*/
T read(DataReader dataReader) throws SQLException;
/**
* Ignore typically by moving the index position.
*/
public void loadIgnore(DataReader dataReader);
/**
* Ignore typically by moving the index position.
*/
void loadIgnore(DataReader dataReader);
/**
* Bind the value to the underlying preparedStatement.
*/
public void bind(DataBind b, T value) throws SQLException;
/**
* Bind the value to the underlying preparedStatement.
*/
void bind(DataBind b, T value) throws SQLException;
/**
* Accumulate all the scalar types used by an immutable compound value type.
*/
public void accumulateScalarTypes(String propName, CtCompoundTypeScalarList list);
/**
* Accumulate all the scalar types used by an immutable compound value type.
*/
void accumulateScalarTypes(String propName, CtCompoundTypeScalarList list);
}
@@ -38,143 +38,143 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
/**
* Return true if this is a mutable scalar type (like hstore).
*/
public boolean isMutable();
boolean isMutable();
/**
* For mutable scalarType's return true if the value is dirty.
* Non-dirty properties may be excluded from updates.
*/
public boolean isDirty(Object value);
/**
* Return the default DB column length for this type.
* <p>
* If a BeanProperty has no explicit length defined then this length should
* be assigned.
* </p>
* <p>
* This is primarily to support defining a length on Enum types (to
* supplement defining the length on the BeanProperty directly).
* </p>
*/
public int getLength();
boolean isDirty(Object value);
/**
* Return true if the type is native to JDBC.
* <p>
* If it is native to JDBC then its values/instances do not need to be
* converted to and from an associated JDBC type.
* </p>
*/
public boolean isJdbcNative();
/**
* Return the default DB column length for this type.
* <p>
* If a BeanProperty has no explicit length defined then this length should
* be assigned.
* </p>
* <p>
* This is primarily to support defining a length on Enum types (to
* supplement defining the length on the BeanProperty directly).
* </p>
*/
int getLength();
/**
* Return the type as per java.sql.Types that this maps to.
* <p>
* This type should be consistent with the toJdbcType() method in converting
* the type to the appropriate type for binding to preparedStatements.
* </p>
*/
public int getJdbcType();
/**
* Return true if the type is native to JDBC.
* <p>
* If it is native to JDBC then its values/instances do not need to be
* converted to and from an associated JDBC type.
* </p>
*/
boolean isJdbcNative();
/**
* Return the type that matches the bean property type.
* <p>
* This represents the 'logical' type rather than the JDBC type this maps
* to.
* </p>
*/
public Class<T> getType();
/**
* Return the type as per java.sql.Types that this maps to.
* <p>
* This type should be consistent with the toJdbcType() method in converting
* the type to the appropriate type for binding to preparedStatements.
* </p>
*/
int getJdbcType();
/**
* Read the value from the resultSet and convert if necessary to the logical
* bean property value.
*/
public T read(DataReader dataReader) throws SQLException;
/**
* Return the type that matches the bean property type.
* <p>
* This represents the 'logical' type rather than the JDBC type this maps
* to.
* </p>
*/
Class<T> getType();
/**
* Ignore the reading of this value. Typically this means moving the index
* position in the ResultSet.
*/
public void loadIgnore(DataReader dataReader);
/**
* Read the value from the resultSet and convert if necessary to the logical
* bean property value.
*/
T read(DataReader dataReader) throws SQLException;
/**
* Convert (if necessary) and bind the value to the preparedStatement.
* <p>
* value may need to be converted from the logical bean property type to the
* JDBC type.
* </p>
*/
public void bind(DataBind b, T value) throws SQLException;
/**
* Ignore the reading of this value. Typically this means moving the index
* position in the ResultSet.
*/
void loadIgnore(DataReader dataReader);
/**
* Convert the value as necessary to the JDBC type.
* <p>
* Note that this should also match the type as per the getJdbcType()
* method.
* </p>
* <p>
* This is typically used when the matching type is used in a where clause
* and we use this to ensure it is an appropriate jdbc type.
* </p>
*/
public Object toJdbcType(Object value);
/**
* Convert (if necessary) and bind the value to the preparedStatement.
* <p>
* value may need to be converted from the logical bean property type to the
* JDBC type.
* </p>
*/
void bind(DataBind b, T value) throws SQLException;
/**
* Convert the value as necessary to the logical Bean type.
* <p>
* The type as per the bean property.
* </p>
* <p>
* This is used to automatically convert id values (typically from a string
* to a int, long or UUID).
* </p>
*/
public T toBeanType(Object value);
/**
* Convert the value as necessary to the JDBC type.
* <p>
* Note that this should also match the type as per the getJdbcType()
* method.
* </p>
* <p>
* This is typically used when the matching type is used in a where clause
* and we use this to ensure it is an appropriate jdbc type.
* </p>
*/
Object toJdbcType(Object value);
/**
* Convert the type into a string representation.
* <p>
* Reciprocal of parse().
* </p>
*/
public String formatValue(T v);
/**
* Convert the value as necessary to the logical Bean type.
* <p>
* The type as per the bean property.
* </p>
* <p>
* This is used to automatically convert id values (typically from a string
* to a int, long or UUID).
* </p>
*/
T toBeanType(Object value);
/**
* Convert the type into a string representation.
* <p>
* This assumes the value is of the correct type.
* </p>
* <p>
* This is so that ScalarType also implements the StringFormatter interface.
* </p>
*/
public String format(Object v);
/**
* Convert the type into a string representation.
* <p>
* Reciprocal of parse().
* </p>
*/
String formatValue(T v);
/**
* Convert the string value to the appropriate java object.
* <p>
* Mostly used to support CSV, JSON and XML parsing.
* </p>
* <p>
* Reciprocal of formatValue().
* </p>
*/
public T parse(String value);
/**
* Convert the type into a string representation.
* <p>
* This assumes the value is of the correct type.
* </p>
* <p>
* This is so that ScalarType also implements the StringFormatter interface.
* </p>
*/
String format(Object v);
/**
* Return true if the type can accept long systemTimeMillis input.
* <p>
* This is used to determine if is is sensible to use the
* {@link #convertFromMillis(long)} method.
* </p>
* <p>
* This includes the Date, Calendar, sql Date, Time, Timestamp, JODA types
* as well as Long, BigDecimal and String (although it generally is not
* expected to parse systemTimeMillis to a String or BigDecimal).
* </p>
*/
public boolean isDateTimeCapable();
/**
* Convert the string value to the appropriate java object.
* <p>
* Mostly used to support CSV, JSON and XML parsing.
* </p>
* <p>
* Reciprocal of formatValue().
* </p>
*/
T parse(String value);
/**
* Return true if the type can accept long systemTimeMillis input.
* <p>
* This is used to determine if is is sensible to use the
* {@link #convertFromMillis(long)} method.
* </p>
* <p>
* This includes the Date, Calendar, sql Date, Time, Timestamp, JODA types
* as well as Long, BigDecimal and String (although it generally is not
* expected to parse systemTimeMillis to a String or BigDecimal).
* </p>
*/
boolean isDateTimeCapable();
/**
* Convert the systemTimeMillis into the appropriate java object.
@@ -182,26 +182,26 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* For non dateTime types this will throw an exception.
* </p>
*/
public T convertFromMillis(long dateTime);
T convertFromMillis(long dateTime);
/**
* Read the value from binary input.
*/
public T readData(DataInput dataInput) throws IOException;
* Read the value from binary input.
*/
T readData(DataInput dataInput) throws IOException;
/**
* Write the value to binary output.
*/
public void writeData(DataOutput dataOutput, T v) throws IOException;
void writeData(DataOutput dataOutput, T v) throws IOException;
/**
* Read the value from JsonParser.
*/
public T jsonRead(JsonParser ctx, JsonToken event) throws IOException;
T jsonRead(JsonParser ctx, JsonToken event) throws IOException;
/**
* Write the value to the JsonGenerator.
*/
public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException;
void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException;
}
@@ -12,7 +12,6 @@ import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
/**
* Base type for DateTime types.
@@ -98,7 +97,7 @@ public abstract class ScalarTypeBaseDateTime<T> extends ScalarTypeBase<T> {
}
default: {
String jsonDateTime = ctx.getText();
return convertFromTimestamp(dateTimeParser.parse(jsonDateTime));
return convertFromTimestamp(dateTimeParser.parse(jsonDateTime));
}
}
}
@@ -80,16 +80,16 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
@Override
public Object toJdbcType(Object value) {
if (value instanceof String) {
return parse((String) value);
return value;
}
return value;
return format(value);
}
@Override
public T convertFromMillis(long systemTimeMillis) {
throw new TextException("Not Supported");
}
@Override
public boolean isDateTimeCapable() {
return false;
@@ -121,12 +121,12 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
dataOutput.writeUTF(s);
}
}
@Override
public T jsonRead(JsonParser ctx, JsonToken event) throws IOException {
return parse(ctx.getValueAsString());
}
@Override
public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException {
ctx.writeStringField(name, format(value));
@@ -83,7 +83,7 @@ public class ScalarTypeBigDecimal extends ScalarTypeBase<BigDecimal> {
}
public void jsonWrite(JsonGenerator ctx, String name, BigDecimal value) throws IOException {
ctx.writeNumberField(name, (BigDecimal) value);
ctx.writeNumberField(name, value);
}
}
@@ -53,7 +53,7 @@ public class ScalarTypeBoolean {
/**
* The Class BitBoolean converts a JDBC type BIT to a java boolean
*
* <p/>
* <p>
* Sometimes booleans may be mapped to the JDBC type BIT. To use the BitBoolean specify
* type.boolean.dbtype="bit" in the ebean configuration
@@ -143,11 +143,7 @@ public class ScalarTypeBoolean {
return null;
}
Boolean b = (Boolean) value;
if (b.booleanValue()) {
return trueValue;
} else {
return falseValue;
}
return b ? trueValue : falseValue;
}
/**
@@ -222,11 +218,7 @@ public class ScalarTypeBoolean {
return null;
}
Boolean b = (Boolean) value;
if (b.booleanValue()) {
return trueValue;
} else {
return falseValue;
}
return b ? trueValue : falseValue;
}
/**
@@ -293,7 +285,7 @@ public class ScalarTypeBoolean {
}
public void jsonWrite(JsonGenerator ctx, String name, Boolean value) throws IOException {
ctx.writeBooleanField(name, (Boolean) value);
ctx.writeBooleanField(name, value);
}
}
@@ -20,10 +20,6 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase<byte[]> {
super(byte[].class, jdbcNative, jdbcType);
}
public Object convertFromBytes(byte[] bytes) {
return bytes;
}
public byte[] convertToBytes(Object value) {
return (byte[]) value;
}
@@ -46,7 +42,7 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase<byte[]> {
@Override
public void jsonWrite(JsonGenerator ctx, String name, byte[] value) throws IOException {
ctx.writeBinaryField(name, (byte[]) value);
ctx.writeBinaryField(name, value);
}
@Override
@@ -12,9 +12,6 @@ import com.fasterxml.jackson.core.JsonToken;
/**
* Encrypted ScalarType that wraps a byte[] types.
*
* @author rbygrave
*
*/
public class ScalarTypeBytesEncrypted implements ScalarType<byte[]> {
@@ -68,7 +65,7 @@ public class ScalarTypeBytesEncrypted implements ScalarType<byte[]> {
@Override
public void jsonWrite(JsonGenerator ctx, String name, byte[] value) throws IOException {
ctx.writeBinaryField(name, (byte[]) value);
ctx.writeBinaryField(name, value);
}
@Override
@@ -4,11 +4,11 @@ import javax.persistence.PersistenceException;
/**
* ScalarType for Class that persists it to VARCHAR column.
*
*
* @author emcgreal
* @author rbygrave
*/
@SuppressWarnings({ "rawtypes" })
@SuppressWarnings({"rawtypes"})
public class ScalarTypeClass extends ScalarTypeBaseVarchar<Class> {
public ScalarTypeClass() {
@@ -41,5 +41,5 @@ public class ScalarTypeClass extends ScalarTypeBaseVarchar<Class> {
throw new PersistenceException("Unable to find Class " + value, e);
}
}
}
@@ -9,11 +9,7 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
* ScalarType for String.
*/
public class ScalarTypeClob extends ScalarTypeBaseVarchar<String> {
static final int clobBufferSize = 512;
static final int stringInitialSize = 512;
protected ScalarTypeClob(boolean jdbcNative, int jdbcType) {
super(String.class, jdbcNative, jdbcType);
}
@@ -23,7 +23,7 @@ public class ScalarTypeCurrency extends ScalarTypeBaseVarchar<Currency> {
@Override
public String convertToDbString(Currency beanValue) {
return ((Currency) beanValue).getCurrencyCode();
return beanValue.getCurrencyCode();
}
@Override
@@ -25,7 +25,7 @@ public class ScalarTypeDouble extends ScalarTypeBase<Double> {
if (value == null) {
b.setNull(Types.DOUBLE);
} else {
b.setDouble(value.doubleValue());
b.setDouble(value);
}
}
@@ -56,7 +56,7 @@ public class ScalarTypeDouble extends ScalarTypeBase<Double> {
@Override
public Double convertFromMillis(long systemTimeMillis) {
return Double.valueOf(systemTimeMillis);
return (double) systemTimeMillis;
}
@Override
@@ -52,8 +52,8 @@ public class ScalarTypeDuration extends ScalarTypeBase<Duration> {
@Override
public Object toJdbcType(Object value) {
if (value instanceof Long) return value;
return ((Duration)value).getSeconds();
if (value instanceof Long) return value;
return ((Duration) value).getSeconds();
}
@Override
@@ -1,14 +1,7 @@
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;
@@ -17,7 +10,7 @@ import java.time.Duration;
/**
* ScalarType for java.time.Duration (with Nanos precision).
* <p>
* Stored in the DB as DECIMAL value.
* Stored in the DB as DECIMAL value.
* </p>
*/
public class ScalarTypeDurationWithNanos extends ScalarTypeDuration {
@@ -42,8 +35,8 @@ public class ScalarTypeDurationWithNanos extends ScalarTypeDuration {
@Override
public Object toJdbcType(Object value) {
if (value instanceof BigDecimal) return value;
return convertToBigDecimal((Duration)value);
if (value instanceof BigDecimal) return value;
return convertToBigDecimal((Duration) value);
}
@Override
@@ -136,7 +136,7 @@ public class ScalarTypeEncryptedWrapper<T> implements ScalarType<T> {
public T jsonRead(JsonParser ctx, JsonToken event) throws IOException {
return wrapped.jsonRead(ctx, event);
}
@Override
public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException {
wrapped.jsonWrite(ctx, name, value);
@@ -5,9 +5,9 @@ package com.avaje.ebeaninternal.server.type;
*/
public interface ScalarTypeEnum {
/**
* Return the IN values for DB constraint construction.
*/
public String getConstraintInValues();
/**
* Return the IN values for DB constraint construction.
*/
String getConstraintInValues();
}
@@ -25,7 +25,7 @@ import com.fasterxml.jackson.core.JsonToken;
*/
public class ScalarTypeEnumStandard {
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({"rawtypes", "unchecked"})
public static class StringEnum extends EnumBase implements ScalarTypeEnum {
private final int length;
@@ -113,7 +113,7 @@ public class ScalarTypeEnumStandard {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({"rawtypes", "unchecked"})
public static class OrdinalEnum extends EnumBase implements ScalarTypeEnum {
private final Object[] enumArray;
@@ -196,7 +196,7 @@ public class ScalarTypeEnumStandard {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({"rawtypes", "unchecked"})
public abstract static class EnumBase extends ScalarTypeBase {
protected final Class enumType;
@@ -6,7 +6,7 @@ import java.util.Iterator;
/**
* Additional control over mapping to DB values.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
public class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase implements ScalarType, ScalarTypeEnum {
private final EnumToDbValueMap beanDbMap;
@@ -25,7 +25,7 @@ public class ScalarTypeFloat extends ScalarTypeBase<Float> {
if (value == null) {
b.setNull(Types.REAL);
} else {
b.setFloat(value.floatValue());
b.setFloat(value);
}
}
@@ -56,7 +56,7 @@ public class ScalarTypeFloat extends ScalarTypeBase<Float> {
@Override
public Float convertFromMillis(long systemTimeMillis) {
return Float.valueOf(systemTimeMillis);
return (float) systemTimeMillis;
}
@Override
@@ -69,8 +69,7 @@ public class ScalarTypeFloat extends ScalarTypeBase<Float> {
if (!dataInput.readBoolean()) {
return null;
} else {
float val = dataInput.readFloat();
return Float.valueOf(val);
return dataInput.readFloat();
}
}
@@ -92,6 +91,6 @@ public class ScalarTypeFloat extends ScalarTypeBase<Float> {
@Override
public void jsonWrite(JsonGenerator ctx, String name, Float value) throws IOException {
ctx.writeNumberField(name, (Float) value);
ctx.writeNumberField(name, value);
}
}

Some files were not shown because too many files have changed in this diff Show More