mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
38
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a3941227f | ||
|
|
0013cb1a76 | ||
|
|
8fe91f66c0 | ||
|
|
053fdf4abb | ||
|
|
24be907dc5 | ||
|
|
6aa915b420 | ||
|
|
40d87af5b1 | ||
|
|
75082fe0c0 | ||
|
|
7d43f5a3d7 | ||
|
|
99203a35a2 | ||
|
|
67f427b83e | ||
|
|
f5a2cf8ff9 | ||
|
|
4e1cda691f | ||
|
|
64b01324d1 | ||
|
|
3cba238073 | ||
|
|
b5b4a4639f | ||
|
|
2d0a179c3b | ||
|
|
40f7a0088d | ||
|
|
6a02a8d69f | ||
|
|
ed18cbcabf | ||
|
|
3ce4f2fb35 | ||
|
|
962a27f838 | ||
|
|
2b583cf707 | ||
|
|
ef9ade4f5c | ||
|
|
b1b7774a23 | ||
|
|
c6632bbc25 | ||
|
|
8c12fc762c | ||
|
|
8cb0b13ccb | ||
|
|
c2faffb6f4 | ||
|
|
e17d823c17 | ||
|
|
9bf9338ba9 | ||
|
|
0da764ed0c | ||
|
|
43003f4a3a | ||
|
|
7081d3f54a | ||
|
|
cce2c2e28f | ||
|
|
61ecf16978 | ||
|
|
9ff4e63c32 | ||
|
|
a13fd55f64 |
@@ -12,5 +12,11 @@ Maven Dependency
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.5.5</version>
|
||||
<version>4.6.2</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")
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.6.1</version>
|
||||
<version>4.6.3</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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -69,7 +69,9 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
list.add((E) bean);
|
||||
if (bean != null) {
|
||||
list.add((E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
@@ -154,7 +156,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(50);
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanList ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
@@ -348,7 +350,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
Object o = it.next();
|
||||
if (list.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
@@ -366,7 +368,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
boolean changed = false;
|
||||
Iterator<E> it = list.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
Object o = it.next();
|
||||
if (!c.contains(o)) {
|
||||
it.remove();
|
||||
modifyRemoval(o);
|
||||
|
||||
@@ -52,12 +52,20 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
return !touched && (map == null || map.isEmpty());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalPutNull() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalPut(Object key, Object bean) {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
map.put((K)key, (E)bean);
|
||||
if (key != null) {
|
||||
map.put((K) key, (E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void internalAdd(Object bean) {
|
||||
|
||||
@@ -62,7 +62,9 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
set.add((E) bean);
|
||||
if (bean != null) {
|
||||
set.add((E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,15 +145,8 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying set.
|
||||
*/
|
||||
public Object getActualCollection() {
|
||||
return set;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(50);
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanSet ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
@@ -274,7 +269,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
Object o = it.next();
|
||||
if (set.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
|
||||
@@ -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
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -29,364 +30,339 @@ import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
|
||||
*/
|
||||
public class BootupClasses implements ClassPathSearchMatcher {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BootupClasses.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(BootupClasses.class);
|
||||
|
||||
private ArrayList<Class<?>> embeddableList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> embeddableList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> entityList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> entityList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> scalarTypeList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> scalarTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> scalarConverterList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> scalarConverterList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> compoundTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanControllerList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> compoundTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> beanControllerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanFinderList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanListenerList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> beanFinderList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> beanListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
|
||||
|
||||
|
||||
private ArrayList<Class<?>> serverConfigStartupList = new ArrayList<Class<?>>();
|
||||
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
|
||||
private ArrayList<Class<?>> serverConfigStartupList = new ArrayList<Class<?>>();
|
||||
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
|
||||
|
||||
private List<BeanPersistController> persistControllerInstances = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
|
||||
private List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
|
||||
private List<BeanPersistController> persistControllerInstances = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
|
||||
private List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
|
||||
|
||||
public BootupClasses() {
|
||||
public BootupClasses() {
|
||||
}
|
||||
|
||||
public BootupClasses(List<Class<?>> list) {
|
||||
if (list != null) {
|
||||
for (Class<?> cls : list) {
|
||||
isMatch(cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run any ServerConfigStartup listeners.
|
||||
*/
|
||||
public void runServerConfigStartup(ServerConfig serverConfig) {
|
||||
|
||||
for (Class<?> cls : serverConfigStartupList) {
|
||||
try {
|
||||
ServerConfigStartup newInstance = (ServerConfigStartup) cls.newInstance();
|
||||
newInstance.onStart(serverConfig);
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addQueryAdapters(List<BeanQueryAdapter> queryAdapterInstances) {
|
||||
if (queryAdapterInstances != null) {
|
||||
for (BeanQueryAdapter a : queryAdapterInstances) {
|
||||
this.queryAdapterInstances.add(a);
|
||||
// don't automatically instantiate
|
||||
this.beanQueryAdapterList.remove(a.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add BeanPersistController instances.
|
||||
*/
|
||||
public void addPersistControllers(List<BeanPersistController> beanControllerInstances) {
|
||||
if (beanControllerInstances != null) {
|
||||
for (BeanPersistController c : beanControllerInstances) {
|
||||
this.persistControllerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.beanControllerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add TransactionEventListeners instances.
|
||||
*/
|
||||
public void addTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
|
||||
if (transactionEventListeners != null) {
|
||||
for (TransactionEventListener c : transactionEventListeners) {
|
||||
this.transactionEventListenerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.transactionEventListenerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addPersistListeners(List<BeanPersistListener> listenerInstances) {
|
||||
if (listenerInstances != null) {
|
||||
for (BeanPersistListener l : listenerInstances) {
|
||||
this.persistListenerInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.beanListenerList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addServerConfigStartup(List<ServerConfigStartup> startupInstances) {
|
||||
if (startupInstances != null) {
|
||||
for (ServerConfigStartup l : startupInstances) {
|
||||
this.serverConfigStartupInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.serverConfigStartupList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<BeanQueryAdapter> getBeanQueryAdapters() {
|
||||
// add class registered BeanQueryAdapter to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanQueryAdapterList) {
|
||||
try {
|
||||
BeanQueryAdapter newInstance = (BeanQueryAdapter) cls.newInstance();
|
||||
queryAdapterInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
public BootupClasses(List<Class<?>> list) {
|
||||
if (list != null) {
|
||||
for (Class<?> cls : list) {
|
||||
isMatch(cls);
|
||||
}
|
||||
}
|
||||
return queryAdapterInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistListener> getBeanPersistListeners() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanListenerList) {
|
||||
try {
|
||||
BeanPersistListener newInstance = (BeanPersistListener) cls.newInstance();
|
||||
persistListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
private BootupClasses(BootupClasses parent) {
|
||||
this.embeddableList.addAll(parent.embeddableList);
|
||||
this.entityList.addAll(parent.entityList);
|
||||
this.scalarTypeList.addAll(parent.scalarTypeList);
|
||||
this.scalarConverterList.addAll(parent.scalarConverterList);
|
||||
this.compoundTypeList.addAll(parent.compoundTypeList);
|
||||
this.beanControllerList.addAll(parent.beanControllerList);
|
||||
this.transactionEventListenerList.addAll(parent.transactionEventListenerList);
|
||||
this.beanFinderList.addAll(parent.beanFinderList);
|
||||
this.beanListenerList.addAll(parent.beanListenerList);
|
||||
this.beanQueryAdapterList.addAll(parent.beanQueryAdapterList);
|
||||
this.serverConfigStartupList.addAll(parent.serverConfigStartupList);
|
||||
return persistListenerInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistController> getBeanPersistControllers() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanControllerList) {
|
||||
try {
|
||||
BeanPersistController newInstance = (BeanPersistController) cls.newInstance();
|
||||
persistControllerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this object so that classes can be added to it.
|
||||
*/
|
||||
public BootupClasses createCopy() {
|
||||
return new BootupClasses(this);
|
||||
return persistControllerInstances;
|
||||
}
|
||||
|
||||
public List<TransactionEventListener> getTransactionEventListeners() {
|
||||
// add class registered TransactionEventListener to the
|
||||
// already created instances
|
||||
for (Class<?> cls : transactionEventListenerList) {
|
||||
try {
|
||||
TransactionEventListener newInstance = (TransactionEventListener) cls.newInstance();
|
||||
transactionEventListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating TransactionEventListener " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run any ServerConfigStartup listeners.
|
||||
*/
|
||||
public void runServerConfigStartup(ServerConfig serverConfig) {
|
||||
|
||||
for (Class<?> cls : serverConfigStartupList) {
|
||||
try {
|
||||
ServerConfigStartup newInstance = (ServerConfigStartup) cls.newInstance();
|
||||
newInstance.onStart(serverConfig);
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addQueryAdapters(List<BeanQueryAdapter> queryAdapterInstances) {
|
||||
if (queryAdapterInstances != null) {
|
||||
for (BeanQueryAdapter a : queryAdapterInstances) {
|
||||
this.queryAdapterInstances.add(a);
|
||||
// don't automatically instantiate
|
||||
this.beanQueryAdapterList.remove(a.getClass());
|
||||
}
|
||||
}
|
||||
return transactionEventListenerInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Embeddable classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEmbeddables() {
|
||||
return embeddableList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of entity classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEntities() {
|
||||
return entityList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarTypes found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarTypes() {
|
||||
return scalarTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarConverters() {
|
||||
return scalarConverterList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getCompoundTypes() {
|
||||
return compoundTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanControllers found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanControllers() {
|
||||
return beanControllerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of TransactionEventListeners found
|
||||
*/
|
||||
public ArrayList<Class<?>> getTransactionEventListenerList() {
|
||||
return transactionEventListenerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanFinders found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanFinders() {
|
||||
return beanFinderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanListeners found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanListeners() {
|
||||
return beanListenerList;
|
||||
}
|
||||
|
||||
public boolean isMatch(Class<?> cls) {
|
||||
|
||||
if (isEmbeddable(cls)) {
|
||||
embeddableList.add(cls);
|
||||
|
||||
} else if (isEntity(cls)) {
|
||||
entityList.add(cls);
|
||||
|
||||
} else {
|
||||
return isInterestingInterface(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add BeanPersistController instances.
|
||||
*/
|
||||
public void addPersistControllers(List<BeanPersistController> beanControllerInstances) {
|
||||
if (beanControllerInstances != null) {
|
||||
for (BeanPersistController c : beanControllerInstances) {
|
||||
this.persistControllerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.beanControllerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for interesting interfaces.
|
||||
* <p>
|
||||
* This includes ScalarType, BeanController, BeanFinder and BeanListener.
|
||||
* </p>
|
||||
*/
|
||||
private boolean isInterestingInterface(Class<?> cls) {
|
||||
|
||||
if (Modifier.isAbstract(cls.getModifiers())) {
|
||||
// do not include abstract classes as we can
|
||||
// not instantiate them
|
||||
return false;
|
||||
}
|
||||
boolean interesting = false;
|
||||
|
||||
if (BeanPersistController.class.isAssignableFrom(cls)) {
|
||||
beanControllerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add TransactionEventListeners instances.
|
||||
*/
|
||||
public void addTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
|
||||
if (transactionEventListeners != null) {
|
||||
for (TransactionEventListener c : transactionEventListeners) {
|
||||
this.transactionEventListenerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.transactionEventListenerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
if (TransactionEventListener.class.isAssignableFrom(cls)) {
|
||||
transactionEventListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
public void addPersistListeners(List<BeanPersistListener> listenerInstances) {
|
||||
if (listenerInstances != null) {
|
||||
for (BeanPersistListener l : listenerInstances) {
|
||||
this.persistListenerInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.beanListenerList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addServerConfigStartup(List<ServerConfigStartup> startupInstances) {
|
||||
if (startupInstances != null) {
|
||||
for (ServerConfigStartup l : startupInstances) {
|
||||
this.serverConfigStartupInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.serverConfigStartupList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<BeanQueryAdapter> getBeanQueryAdapters() {
|
||||
// add class registered BeanQueryAdapter to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanQueryAdapterList) {
|
||||
try {
|
||||
BeanQueryAdapter newInstance = (BeanQueryAdapter) cls.newInstance();
|
||||
queryAdapterInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return queryAdapterInstances;
|
||||
if (ScalarType.class.isAssignableFrom(cls)) {
|
||||
scalarTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
public List<BeanPersistListener> getBeanPersistListeners() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanListenerList) {
|
||||
try {
|
||||
BeanPersistListener newInstance = (BeanPersistListener) cls.newInstance();
|
||||
persistListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return persistListenerInstances;
|
||||
if (ScalarTypeConverter.class.isAssignableFrom(cls)) {
|
||||
scalarConverterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
public List<BeanPersistController> getBeanPersistControllers() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanControllerList) {
|
||||
try {
|
||||
BeanPersistController newInstance = (BeanPersistController) cls.newInstance();
|
||||
persistControllerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return persistControllerInstances;
|
||||
if (CompoundType.class.isAssignableFrom(cls)) {
|
||||
compoundTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
public List<TransactionEventListener> getTransactionEventListeners() {
|
||||
// add class registered TransactionEventListener to the
|
||||
// already created instances
|
||||
for (Class<?> cls : transactionEventListenerList) {
|
||||
try {
|
||||
TransactionEventListener newInstance = (TransactionEventListener) cls.newInstance();
|
||||
transactionEventListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating TransactionEventListener " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return transactionEventListenerInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Embeddable classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEmbeddables() {
|
||||
return embeddableList;
|
||||
if (BeanFinder.class.isAssignableFrom(cls)) {
|
||||
beanFinderList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of entity classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEntities() {
|
||||
return entityList;
|
||||
if (BeanPersistListener.class.isAssignableFrom(cls)) {
|
||||
beanListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarTypes found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarTypes() {
|
||||
return scalarTypeList;
|
||||
if (BeanQueryAdapter.class.isAssignableFrom(cls)) {
|
||||
beanQueryAdapterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarConverters() {
|
||||
return scalarConverterList;
|
||||
if (ServerConfigStartup.class.isAssignableFrom(cls)) {
|
||||
serverConfigStartupList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getCompoundTypes() {
|
||||
return compoundTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanControllers found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanControllers() {
|
||||
return beanControllerList;
|
||||
return interesting;
|
||||
}
|
||||
|
||||
private boolean isEntity(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Entity.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(Table.class);
|
||||
return ann != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of TransactionEventListeners found
|
||||
*/
|
||||
public ArrayList<Class<?>> getTransactionEventListenerList() {
|
||||
return transactionEventListenerList;
|
||||
}
|
||||
private boolean isEmbeddable(Class<?> cls) {
|
||||
|
||||
/**
|
||||
* Return the list of BeanFinders found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanFinders() {
|
||||
return beanFinderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanListeners found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanListeners() {
|
||||
return beanListenerList;
|
||||
}
|
||||
|
||||
public boolean isMatch(Class<?> cls) {
|
||||
|
||||
if (isEmbeddable(cls)) {
|
||||
embeddableList.add(cls);
|
||||
|
||||
} else if (isEntity(cls)) {
|
||||
entityList.add(cls);
|
||||
|
||||
} else if (isInterestingInterface(cls)) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for interesting interfaces.
|
||||
* <p>
|
||||
* This includes ScalarType, BeanController, BeanFinder and BeanListener.
|
||||
* </p>
|
||||
*/
|
||||
private boolean isInterestingInterface(Class<?> cls) {
|
||||
|
||||
boolean interesting = false;
|
||||
|
||||
if (BeanPersistController.class.isAssignableFrom(cls)) {
|
||||
beanControllerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (TransactionEventListener.class.isAssignableFrom(cls)) {
|
||||
transactionEventListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ScalarType.class.isAssignableFrom(cls)) {
|
||||
scalarTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ScalarTypeConverter.class.isAssignableFrom(cls)) {
|
||||
scalarConverterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (CompoundType.class.isAssignableFrom(cls)) {
|
||||
compoundTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanFinder.class.isAssignableFrom(cls)) {
|
||||
beanFinderList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanPersistListener.class.isAssignableFrom(cls)) {
|
||||
beanListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanQueryAdapter.class.isAssignableFrom(cls)) {
|
||||
beanQueryAdapterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ServerConfigStartup.class.isAssignableFrom(cls)){
|
||||
serverConfigStartupList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
return interesting;
|
||||
}
|
||||
|
||||
private boolean isEntity(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Entity.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(Table.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isEmbeddable(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Embeddable.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Annotation ann = cls.getAnnotation(Embeddable.class);
|
||||
return ann != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -104,18 +104,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
|
||||
private final boolean autoFetchTunable;
|
||||
|
||||
private final String lazyFetchIncludes;
|
||||
|
||||
/**
|
||||
* The concurrency mode for beans of this type.
|
||||
*/
|
||||
private final ConcurrencyMode concurrencyMode;
|
||||
|
||||
/**
|
||||
* The tables this bean is dependent on.
|
||||
*/
|
||||
private final String[] dependantTables;
|
||||
|
||||
private final CompoundUniqueContraint[] compoundUniqueConstraints;
|
||||
|
||||
/**
|
||||
@@ -127,7 +120,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Map of BeanProperty Linked so as to preserve order.
|
||||
*/
|
||||
private final LinkedHashMap<String, BeanProperty> propMap;
|
||||
private final LinkedHashMap<String, BeanProperty> propMapByDbColumn;
|
||||
|
||||
/**
|
||||
* The type of bean this describes.
|
||||
@@ -222,7 +214,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneImportedSave;
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneImportedDelete;
|
||||
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneExported;
|
||||
//private final BeanPropertyAssocOne<?>[] propertiesOneExported;
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneExportedSave;
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneExportedDelete;
|
||||
|
||||
@@ -339,11 +331,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.sequenceInitialValue = deploy.getSequenceInitialValue();
|
||||
this.sequenceAllocationSize = deploy.getSequenceAllocationSize();
|
||||
this.selectLastInsertedId = deploy.getSelectLastInsertedId();
|
||||
this.lazyFetchIncludes = InternString.intern(deploy.getLazyFetchIncludes());
|
||||
this.concurrencyMode = deploy.getConcurrencyMode();
|
||||
this.updateChangesOnly = deploy.isUpdateChangesOnly();
|
||||
|
||||
this.dependantTables = deploy.getDependantTables();
|
||||
this.compoundUniqueConstraints = deploy.getCompoundUniqueConstraints();
|
||||
|
||||
this.baseTable = InternString.intern(deploy.getBaseTable());
|
||||
@@ -356,7 +345,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.idProperty = listHelper.getId();
|
||||
this.versionProperty = listHelper.getVersionProperty();
|
||||
this.propMap = listHelper.getPropertyMap();
|
||||
this.propMapByDbColumn = getReverseMap(propMap);
|
||||
this.propertiesTransient = listHelper.getTransients();
|
||||
this.propertiesNonTransient = listHelper.getNonTransients();
|
||||
this.propertiesBaseScalar = listHelper.getBaseScalar();
|
||||
@@ -366,7 +354,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.propertiesMutable = listHelper.getMutable();
|
||||
this.unidirectional = listHelper.getUnidirectional();
|
||||
this.propertiesOne = listHelper.getOnes();
|
||||
this.propertiesOneExported = listHelper.getOneExported();
|
||||
//this.propertiesOneExported = listHelper.getOneExported();
|
||||
this.propertiesOneExportedSave = listHelper.getOneExportedSave();
|
||||
this.propertiesOneExportedDelete = listHelper.getOneExportedDelete();
|
||||
this.propertiesOneImported = listHelper.getOneImported();
|
||||
@@ -649,10 +637,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return (queryUseCache != null) ? queryUseCache.booleanValue() : isBeanCaching();
|
||||
}
|
||||
|
||||
public T cacheNaturalKey(SpiQuery<T> query, SpiTransaction t) {
|
||||
return cacheHelp.naturalKeyLookup(query, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache options.
|
||||
*/
|
||||
@@ -718,13 +702,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
cacheHelp.setUseCache(useCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently query caching for this type of bean.
|
||||
*/
|
||||
public boolean isQueryCaching() {
|
||||
return cacheHelp.isQueryCaching();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently bean caching for this type of bean.
|
||||
*/
|
||||
@@ -786,20 +763,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
cacheHelp.manyPropClear(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CachedManyIds for a given bean and property. Returns null if not in the cache.
|
||||
*/
|
||||
public CachedManyIds cacheManyPropGet(Object parentId, String propertyName) {
|
||||
return cacheHelp.manyPropGet(parentId, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the bean cache.
|
||||
*/
|
||||
public void cacheBeanClear() {
|
||||
cacheHelp.beanCacheClear();
|
||||
}
|
||||
|
||||
public void cacheBeanPut(T bean) {
|
||||
cacheBeanPutData((EntityBean)bean);
|
||||
}
|
||||
@@ -1534,14 +1497,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return EntityType.EMBEDDED.equals(entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tables this bean is dependent on. This implies that if any of
|
||||
* these tables are modified then cached beans may be invalidated.
|
||||
*/
|
||||
public String[] getDependantTables() {
|
||||
return dependantTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the compound unique constraints.
|
||||
*/
|
||||
@@ -1570,26 +1525,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return queryAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* De-register the BeanPersistListener.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void deregister(BeanPersistListener listener) {
|
||||
// volatile read...
|
||||
BeanPersistListener currListener = persistListener;
|
||||
if (currListener == null) {
|
||||
// nothing to deregister
|
||||
} else {
|
||||
BeanPersistListener deregListener = listener;
|
||||
if (currListener instanceof ChainedBeanPersistListener) {
|
||||
// remove it from the existing chain
|
||||
persistListener = ((ChainedBeanPersistListener) currListener).deregister(deregListener);
|
||||
} else if (currListener.equals(deregListener)) {
|
||||
persistListener = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* De-register the BeanPersistController.
|
||||
*/
|
||||
@@ -1717,20 +1652,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return selectLastInsertedId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the IdGenerator.
|
||||
*/
|
||||
public IdGenerator getIdGenerator() {
|
||||
return idGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the includes for getReference().
|
||||
*/
|
||||
public String getLazyFetchIncludes() {
|
||||
return lazyFetchIncludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TableJoins.
|
||||
* <p>
|
||||
@@ -1823,14 +1744,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
public void checkMutableProperties(EntityBeanIntercept ebi) {
|
||||
for (int i = 0; i < propertiesMutable.length; i++) {
|
||||
BeanProperty beanProperty = propertiesMutable[i];
|
||||
if (ebi.isDirtyProperty(beanProperty.getPropertyIndex())) {
|
||||
// already marked as dirty
|
||||
} else if (ebi.isLoadedProperty(beanProperty.getPropertyIndex())) {
|
||||
int propertyIndex = beanProperty.getPropertyIndex();
|
||||
if (!ebi.isDirtyProperty(propertyIndex) && ebi.isLoadedProperty(propertyIndex)) {
|
||||
Object value = beanProperty.getValue(ebi.getOwner());
|
||||
if (value == null || beanProperty.isDirtyValue(value)) {
|
||||
// mutable scalar value which is considered dirty so mark
|
||||
// it as such so that it is included in an update
|
||||
ebi.markPropertyAsChanged(beanProperty.getPropertyIndex());
|
||||
ebi.markPropertyAsChanged(propertyIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +104,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
private List<BeanDescriptor<?>> immutableDescriptorList;
|
||||
|
||||
private final Set<Integer> descriptorUniqueIds = new HashSet<Integer>();
|
||||
|
||||
private final DbIdentity dbIdentity;
|
||||
|
||||
private final DataSource dataSource;
|
||||
@@ -286,9 +284,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
for (BeanDescriptor<?> desc : descMap.values()) {
|
||||
String baseTable = desc.getBaseTable();
|
||||
if (baseTable == null) {
|
||||
|
||||
} else {
|
||||
if (baseTable != null) {
|
||||
baseTable = baseTable.toLowerCase();
|
||||
|
||||
List<BeanDescriptor<?>> list = tableToDescMap.get(baseTable);
|
||||
@@ -363,8 +359,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
BeanDescriptor<?> idBeanDescriptor = embId.getIdBeanDescriptor();
|
||||
Class<?> idType = idBeanDescriptor.getBeanType();
|
||||
try {
|
||||
idType.getDeclaredMethod("hashCode", new Class[] {});
|
||||
idType.getDeclaredMethod("equals", new Class[] { Object.class });
|
||||
idType.getDeclaredMethod("hashCode");
|
||||
idType.getDeclaredMethod("equals", Object.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
checkMissingHashCodeOrEquals(e, idType, d.getBeanType());
|
||||
}
|
||||
@@ -385,18 +381,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
return immutableDescriptorList;
|
||||
}
|
||||
|
||||
public Map<Class<?>, BeanTable> getBeanTables() {
|
||||
return beanTableMap;
|
||||
}
|
||||
|
||||
public BeanTable getBeanTable(Class<?> type) {
|
||||
return beanTableMap.get(type);
|
||||
}
|
||||
|
||||
public Map<String, BeanDescriptor<?>> getBeanDescriptors() {
|
||||
return descMap;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanManager<T> getBeanManager(Class<T> entityType) {
|
||||
|
||||
@@ -539,9 +527,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
BeanDescriptor<?> desc = getBeanDescriptor(deployDesc.getBeanType());
|
||||
|
||||
for (DRawSqlMeta rawSqlMeta : deployDesc.getRawSqlMeta()) {
|
||||
if (rawSqlMeta.getQuery() == null) {
|
||||
|
||||
} else {
|
||||
if (rawSqlMeta.getQuery() != null) {
|
||||
DeployNamedQuery nq = new DRawSqlSelectBuilder(namingConvention, desc, rawSqlMeta).parse();
|
||||
desc.addNamedQuery(nq);
|
||||
}
|
||||
@@ -603,15 +589,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
private Integer getUniqueHash(DeployBeanDescriptor<?> deployBeanDescriptor) {
|
||||
|
||||
int hashCode = deployBeanDescriptor.getFullName().hashCode();
|
||||
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
Integer key = Integer.valueOf(hashCode + i);
|
||||
if (!descriptorUniqueIds.contains(key)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Failed to generate a unique hash for " + deployBeanDescriptor.getFullName());
|
||||
return deployBeanDescriptor.getFullName().hashCode();
|
||||
}
|
||||
|
||||
private void secondaryPropsJoins(DeployBeanInfo<?> info) {
|
||||
@@ -646,7 +624,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
|
||||
if (!oneProp.isTransient()) {
|
||||
if (oneProp.getMappedBy() != null) {
|
||||
checkMappedByOneToOne(info, oneProp);
|
||||
checkMappedByOneToOne(oneProp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -654,7 +632,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
for (DeployBeanPropertyAssocMany<?> manyProp : info.getDescriptor().propertiesAssocMany()) {
|
||||
if (!manyProp.isTransient()) {
|
||||
if (manyProp.isManyToMany()) {
|
||||
checkMappedByManyToMany(info, manyProp);
|
||||
checkMappedByManyToMany(manyProp);
|
||||
} else {
|
||||
checkMappedByOneToMany(info, manyProp);
|
||||
}
|
||||
@@ -724,7 +702,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
// search for this in the possible matches
|
||||
for (String possibleMappedBy : matchSet) {
|
||||
String possibleLower = possibleMappedBy.toLowerCase();
|
||||
if (possibleLower.indexOf(searchName) > -1) {
|
||||
if (possibleLower.contains(searchName)) {
|
||||
// we have a match..
|
||||
prop.setMappedBy(possibleMappedBy);
|
||||
|
||||
@@ -809,7 +787,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
}
|
||||
|
||||
private void checkMappedByOneToOne(DeployBeanInfo<?> info, DeployBeanPropertyAssocOne<?> prop) {
|
||||
private void checkMappedByOneToOne(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
// check that the mappedBy property is valid and read
|
||||
// its associated join information if it is available
|
||||
@@ -901,7 +879,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
/**
|
||||
* For mappedBy copy the joins from the other side.
|
||||
*/
|
||||
private void checkMappedByManyToMany(DeployBeanInfo<?> info, DeployBeanPropertyAssocMany<?> prop) {
|
||||
private void checkMappedByManyToMany(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
// get the bean descriptor that holds the mappedBy property
|
||||
String mappedBy = prop.getMappedBy();
|
||||
@@ -1029,10 +1007,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
private <T> IdType setIdGeneration(DeployBeanDescriptor<T> desc) {
|
||||
|
||||
if (desc.propertiesId().size() == 0) {
|
||||
// bean doen't have an Id property
|
||||
if (!desc.isBaseTableType() || desc.getBeanFinder() != null) {
|
||||
// using BeanFinder so perhaps valid without an id
|
||||
} else {
|
||||
// bean doesn't have an Id property
|
||||
if (desc.isBaseTableType() && desc.getBeanFinder() == null) {
|
||||
// expecting an id property
|
||||
logger.warn(Message.msg("deploy.nouid", desc.getFullName()));
|
||||
}
|
||||
@@ -1120,7 +1096,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
private void setScalarType(DeployBeanDescriptor<?> deployDesc) {
|
||||
|
||||
for (DeployBeanProperty prop : deployDesc.propertiesAll()) {
|
||||
if (prop instanceof DeployBeanPropertyAssoc<?> == false) {
|
||||
if (!(prop instanceof DeployBeanPropertyAssoc<?>)) {
|
||||
deployUtil.setScalarType(prop);
|
||||
}
|
||||
}
|
||||
@@ -1228,7 +1204,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
for (Dnode namedQueryXml : namedQueries) {
|
||||
|
||||
String name = (String) namedQueryXml.getAttribute("name");
|
||||
String name = namedQueryXml.getAttribute("name");
|
||||
Dnode query = namedQueryXml.find("query");
|
||||
if (query == null) {
|
||||
logger.warn("orm.xml " + deployDesc.getFullName() + " named-query missing query element?");
|
||||
@@ -1271,7 +1247,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
BeanPropertiesReader reflectProps = new BeanPropertiesReader(beanType);
|
||||
|
||||
BeanPropertyInfo beanReflect = reflectFactory.create(beanType);
|
||||
desc.setBeanReflect(beanReflect);
|
||||
desc.setProperties(reflectProps.getProperties());
|
||||
|
||||
for (DeployBeanProperty prop : desc.propertiesAll()) {
|
||||
@@ -1283,7 +1258,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
} else {
|
||||
int propertyIndex = pos.intValue();
|
||||
final int propertyIndex = pos;
|
||||
prop.setPropertyIndex(propertyIndex);
|
||||
prop.setGetter(beanReflect.getGetter(propName, propertyIndex));
|
||||
prop.setSetter(beanReflect.getSetter(propName, propertyIndex));
|
||||
@@ -1295,16 +1270,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Return true if this is a persistent field (not transient or static).
|
||||
*/
|
||||
private boolean isPersistentField(DeployBeanProperty prop) {
|
||||
|
||||
|
||||
Field field = prop.getField();
|
||||
int modifiers = field.getModifiers();
|
||||
if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) {
|
||||
return false;
|
||||
}
|
||||
if (field.isAnnotationPresent(Transient.class)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !(Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) && !field.isAnnotationPresent(Transient.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -109,8 +109,12 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
|
||||
@Override
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
|
||||
Object keyValue = beanProperty.getValueIntercept(bean);
|
||||
((BeanMap<?, ?>) collection).internalPut(keyValue, bean);
|
||||
if (bean == null) {
|
||||
((BeanMap<?, ?>) collection).internalPutNull();
|
||||
} else {
|
||||
Object keyValue = beanProperty.getValueIntercept(bean);
|
||||
((BeanMap<?, ?>) collection).internalPut(keyValue, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,11 @@ import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
* scalar properties match to DB columns and the non-scalar ones are here solely
|
||||
* to support EL expression language for nested compound types.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class BeanPropertyCompoundRoot {
|
||||
|
||||
private final BeanPropertySetter setter;
|
||||
|
||||
/**
|
||||
* The method used to write the property.
|
||||
*/
|
||||
private final Method writeMethod;
|
||||
|
||||
private final String name;
|
||||
private final String fullBeanName;
|
||||
|
||||
@@ -42,7 +35,6 @@ public class BeanPropertyCompoundRoot {
|
||||
this.fullBeanName = deploy.getFullBeanName();
|
||||
this.name = deploy.getName();
|
||||
this.setter = deploy.getSetter();
|
||||
this.writeMethod = deploy.getWriteMethod();
|
||||
this.propList = new ArrayList<BeanPropertyCompoundScalar>();
|
||||
this.propMap = new LinkedHashMap<String, BeanPropertyCompoundScalar>();
|
||||
}
|
||||
@@ -75,13 +67,7 @@ public class BeanPropertyCompoundRoot {
|
||||
*/
|
||||
public void setRootValue(EntityBean bean, Object value) {
|
||||
try {
|
||||
if (bean instanceof EntityBean) {
|
||||
setter.set(bean, value);
|
||||
} else {
|
||||
Object[] args = new Object[1];
|
||||
args[0] = value;
|
||||
writeMethod.invoke(bean, args);
|
||||
}
|
||||
setter.set(bean, value);
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "set " + name + " with arg[" + value + "] on ["+fullBeanName+"] with type[" + beanType + "] threw error";
|
||||
@@ -94,13 +80,7 @@ public class BeanPropertyCompoundRoot {
|
||||
*/
|
||||
public void setRootValueIntercept(EntityBean bean, Object value) {
|
||||
try {
|
||||
if (bean instanceof EntityBean) {
|
||||
setter.setIntercept(bean, value);
|
||||
} else {
|
||||
Object[] args = new Object[1];
|
||||
args[0] = value;
|
||||
writeMethod.invoke(bean, args);
|
||||
}
|
||||
setter.setIntercept(bean, value);
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "setIntercept " + name + " arg[" + value + "] on ["+fullBeanName+"] with type[" + beanType + "] threw error";
|
||||
|
||||
@@ -13,75 +13,70 @@ import com.avaje.ebeaninternal.server.type.DataReader;
|
||||
* Context provided when a BeanProperty reads from a ResultSet.
|
||||
*/
|
||||
public interface DbReadContext {
|
||||
|
||||
|
||||
/**
|
||||
* Return the state of the object graph.
|
||||
*/
|
||||
public Boolean isReadOnly();
|
||||
|
||||
Boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Propagate the state to the bean.
|
||||
*/
|
||||
public void propagateState(Object e);
|
||||
|
||||
void propagateState(Object e);
|
||||
|
||||
/**
|
||||
* Return the DataReader.
|
||||
*/
|
||||
public DataReader getDataReader();
|
||||
|
||||
/**
|
||||
* Return true if the query is using supplied SQL rather than generated SQL.
|
||||
*/
|
||||
public boolean isRawSql();
|
||||
|
||||
/**
|
||||
* Set the JoinNode - used by proxy/reference beans for profiling.
|
||||
*/
|
||||
public void setCurrentPrefix(String currentPrefix, Map<String,String> pathMap);
|
||||
DataReader getDataReader();
|
||||
|
||||
/**
|
||||
* Return true if we are profiling this query.
|
||||
*/
|
||||
public boolean isAutoFetchProfiling();
|
||||
|
||||
/**
|
||||
* Add autoFetch profiling for a loaded entity bean.
|
||||
*/
|
||||
public void profileBean(EntityBeanIntercept ebi, String prefix);
|
||||
|
||||
/**
|
||||
* Return the persistence context.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
/**
|
||||
* Return true if the query is using supplied SQL rather than generated SQL.
|
||||
*/
|
||||
boolean isRawSql();
|
||||
|
||||
/**
|
||||
* Register a reference for lazy loading.
|
||||
*/
|
||||
public void register(String path, EntityBeanIntercept ebi);
|
||||
/**
|
||||
* Set the JoinNode - used by proxy/reference beans for profiling.
|
||||
*/
|
||||
void setCurrentPrefix(String currentPrefix, Map<String, String> pathMap);
|
||||
|
||||
/**
|
||||
* Register a collection for lazy loading.
|
||||
*/
|
||||
public void register(String path, BeanCollection<?> bc);
|
||||
/**
|
||||
* Return true if we are profiling this query.
|
||||
*/
|
||||
boolean isAutoFetchProfiling();
|
||||
|
||||
/**
|
||||
* Return the property that is associated with the many. There can only be
|
||||
* one. This can be null.
|
||||
*/
|
||||
public BeanPropertyAssocMany<?> getManyProperty();
|
||||
/**
|
||||
* Add autoFetch profiling for a loaded entity bean.
|
||||
*/
|
||||
void profileBean(EntityBeanIntercept ebi, String prefix);
|
||||
|
||||
/**
|
||||
* Set back the bean that has just been loaded with its id.
|
||||
*/
|
||||
public void setLoadedBean(EntityBean loadedBean, Object id, Object lazyLoadParentId);
|
||||
/**
|
||||
* Return the persistence context.
|
||||
*/
|
||||
PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Set back the 'detail' bean that has just been loaded.
|
||||
*/
|
||||
public void setLoadedManyBean(EntityBean loadedBean);
|
||||
|
||||
/**
|
||||
* Return the query mode.
|
||||
*/
|
||||
public SpiQuery.Mode getQueryMode();
|
||||
/**
|
||||
* Register a reference for lazy loading.
|
||||
*/
|
||||
void register(String path, EntityBeanIntercept ebi);
|
||||
|
||||
/**
|
||||
* Register a collection for lazy loading.
|
||||
*/
|
||||
void register(String path, BeanCollection<?> bc);
|
||||
|
||||
/**
|
||||
* Return the property that is associated with the many. There can only be
|
||||
* one. This can be null.
|
||||
*/
|
||||
BeanPropertyAssocMany<?> getManyProperty();
|
||||
|
||||
/**
|
||||
* Set back the bean that has just been loaded with its id.
|
||||
*/
|
||||
void setLazyLoadedChildBean(EntityBean loadedBean, Object parentId);
|
||||
|
||||
/**
|
||||
* Return the query mode.
|
||||
*/
|
||||
SpiQuery.Mode getQueryMode();
|
||||
}
|
||||
|
||||
+10
-159
@@ -1,23 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.annotation.ConcurrencyMode;
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebean.config.dbplatform.IdGenerator;
|
||||
@@ -28,16 +10,14 @@ import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebeaninternal.server.core.CacheOptions;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistController;
|
||||
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistListener;
|
||||
import com.avaje.ebeaninternal.server.deploy.ChainedBeanQueryAdapter;
|
||||
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueContraint;
|
||||
import com.avaje.ebeaninternal.server.deploy.DRawSqlMeta;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.*;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertyInfo;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Describes Beans including their deployment information.
|
||||
*/
|
||||
@@ -57,8 +37,6 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
private static final String I_SCALAOBJECT = "scala.ScalaObject";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployBeanDescriptor.class);
|
||||
|
||||
/**
|
||||
* Map of BeanProperty Linked so as to preserve order.
|
||||
*/
|
||||
@@ -100,8 +78,6 @@ public class DeployBeanDescriptor<T> {
|
||||
*/
|
||||
private String selectLastInsertedId;
|
||||
|
||||
private String lazyFetchIncludes;
|
||||
|
||||
/**
|
||||
* The concurrency mode for beans of this type.
|
||||
*/
|
||||
@@ -109,11 +85,6 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
private boolean updateChangesOnly;
|
||||
|
||||
/**
|
||||
* The tables this bean is dependent on.
|
||||
*/
|
||||
private String[] dependantTables;
|
||||
|
||||
private List<CompoundUniqueContraint> compoundUniqueConstraints;
|
||||
|
||||
/**
|
||||
@@ -122,11 +93,6 @@ public class DeployBeanDescriptor<T> {
|
||||
private String baseTable;
|
||||
private TableName baseTableFull;
|
||||
|
||||
/**
|
||||
* Used to provide mechanism to new EntityBean instances. Generated code
|
||||
* faster than reflection at this stage.
|
||||
*/
|
||||
private BeanPropertyInfo beanReflect;
|
||||
private String[] properties;
|
||||
|
||||
/**
|
||||
@@ -219,34 +185,6 @@ public class DeployBeanDescriptor<T> {
|
||||
return beanTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all the properties to see if they all have read and write methods
|
||||
* (required if using "subclassing" but not for "enhancement").
|
||||
*/
|
||||
public boolean checkReadAndWriteMethods() {
|
||||
|
||||
boolean missingMethods = false;
|
||||
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (!prop.isTransient()) {
|
||||
String m = "";
|
||||
if (prop.getReadMethod() == null) {
|
||||
m += " missing readMethod ";
|
||||
}
|
||||
if (prop.getWriteMethod() == null) {
|
||||
m += " missing writeMethod ";
|
||||
}
|
||||
if (!"".equals(m)) {
|
||||
m += ". Should it be transient?";
|
||||
String msg = "Bean property " + getFullName() + "." + prop.getName() + " has " + m;
|
||||
logger.error(msg);
|
||||
missingMethods = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !missingMethods;
|
||||
}
|
||||
|
||||
public void setEntityType(EntityType entityType) {
|
||||
this.entityType = entityType;
|
||||
}
|
||||
@@ -317,10 +255,6 @@ public class DeployBeanDescriptor<T> {
|
||||
this.properties = props;
|
||||
}
|
||||
|
||||
public BeanPropertyInfo getBeanReflect() {
|
||||
return beanReflect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class type this BeanDescriptor describes.
|
||||
*/
|
||||
@@ -328,14 +262,6 @@ public class DeployBeanDescriptor<T> {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BeanReflect used to create new instances of an EntityBean. This
|
||||
* could use reflection or code generation to do this.
|
||||
*/
|
||||
public void setBeanReflect(BeanPropertyInfo beanReflect) {
|
||||
this.beanReflect = beanReflect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Inheritance mapping information. This will be null if this type
|
||||
* of bean is not involved in any ORM inheritance mapping.
|
||||
@@ -358,10 +284,6 @@ public class DeployBeanDescriptor<T> {
|
||||
return cacheOptions;
|
||||
}
|
||||
|
||||
public boolean isNaturalKeyProperty(String name) {
|
||||
return name.equals(cacheOptions.getNaturalKey());
|
||||
}
|
||||
|
||||
public DeployBeanPropertyAssocOne<?> getUnidirectional() {
|
||||
return unidirectional;
|
||||
}
|
||||
@@ -392,14 +314,6 @@ public class DeployBeanDescriptor<T> {
|
||||
this.updateChangesOnly = updateChangesOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tables this bean is dependant on. This implies that if any of
|
||||
* these tables are modified then cached beans may be invalidated.
|
||||
*/
|
||||
public String[] getDependantTables() {
|
||||
return dependantTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a compound unique constraint.
|
||||
*/
|
||||
@@ -421,14 +335,6 @@ public class DeployBeanDescriptor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tables this bean is dependant on. This implies that if any of these
|
||||
* tables are modified then cached beans may be invalidated.
|
||||
*/
|
||||
public void setDependantTables(String[] dependantTables) {
|
||||
this.dependantTables = dependantTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the beanFinder. Usually null unless overriding the finder.
|
||||
*/
|
||||
@@ -495,17 +401,6 @@ public class DeployBeanDescriptor<T> {
|
||||
queryAdapters.add(queryAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this bean type should use IdGeneration.
|
||||
* <p>
|
||||
* If this is false and the Id is null it is assumed that a database auto
|
||||
* increment feature is being used to populate the id.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isUseIdGenerator() {
|
||||
return idType == IdType.GENERATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table. Only properties mapped to the base table are by
|
||||
* default persisted.
|
||||
@@ -659,24 +554,6 @@ public class DeployBeanDescriptor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the includes for getReference().
|
||||
*/
|
||||
public String getLazyFetchIncludes() {
|
||||
return lazyFetchIncludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set includes to use for lazy loading by getReference(). Note queries also
|
||||
* build references and includes on the actual association are used for those
|
||||
* references.
|
||||
*/
|
||||
public void setLazyFetchIncludes(String lazyFetchIncludes) {
|
||||
if (lazyFetchIncludes != null && lazyFetchIncludes.length() > 0) {
|
||||
this.lazyFetchIncludes = lazyFetchIncludes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary description.
|
||||
*/
|
||||
@@ -712,11 +589,7 @@ public class DeployBeanDescriptor<T> {
|
||||
boolean hasLazyFetch = false;
|
||||
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop.isTransient()) {
|
||||
// ignore transient props etc
|
||||
} else if (prop instanceof DeployBeanPropertyAssocMany<?>) {
|
||||
// ignore the associated many properties
|
||||
} else {
|
||||
if (!prop.isTransient() && !(prop instanceof DeployBeanPropertyAssocMany<?>)) {
|
||||
if (prop.isFetchEager()) {
|
||||
sb.append(prop.getName()).append(",");
|
||||
} else {
|
||||
@@ -748,7 +621,7 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
LinkedHashSet<String> set = new LinkedHashSet<String>(res.length + 3);
|
||||
|
||||
String temp = null;
|
||||
String temp;
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
temp = res[i].trim();
|
||||
if (temp.length() > 0) {
|
||||
@@ -844,26 +717,6 @@ public class DeployBeanDescriptor<T> {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'Version' properties on this bean. These are 'Counter' or 'Update
|
||||
* Timestamp' type properties. Note version properties can also be on embedded
|
||||
* beans rather than on the bean itself.
|
||||
*/
|
||||
public List<DeployBeanProperty> propertiesVersion() {
|
||||
|
||||
ArrayList<DeployBeanProperty> list = new ArrayList<DeployBeanProperty>();
|
||||
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop instanceof DeployBeanPropertyAssoc<?> == false) {
|
||||
if (!prop.isId() && prop.isVersionColumn()) {
|
||||
list.add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* base properties without the unique id properties.
|
||||
*/
|
||||
@@ -872,10 +725,8 @@ public class DeployBeanDescriptor<T> {
|
||||
ArrayList<DeployBeanProperty> list = new ArrayList<DeployBeanProperty>();
|
||||
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop instanceof DeployBeanPropertyAssoc<?> == false) {
|
||||
if (!prop.isId()) {
|
||||
list.add(prop);
|
||||
}
|
||||
if (!(prop instanceof DeployBeanPropertyAssoc<?>) && !prop.isId()) {
|
||||
list.add(prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -195,11 +195,6 @@ public class DeployBeanProperty {
|
||||
*/
|
||||
private Method readMethod;
|
||||
|
||||
/**
|
||||
* The method used to write the property.
|
||||
*/
|
||||
private Method writeMethod;
|
||||
|
||||
private int propertyIndex;
|
||||
|
||||
private BeanPropertyGetter getter;
|
||||
@@ -454,13 +449,6 @@ public class DeployBeanProperty {
|
||||
return readMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the setter method.
|
||||
*/
|
||||
public Method getWriteMethod() {
|
||||
return writeMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to the owning type form a Inheritance heirarchy.
|
||||
*/
|
||||
@@ -850,17 +838,6 @@ public class DeployBeanProperty {
|
||||
this.readMethod = readMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean write method.
|
||||
* <p>
|
||||
* NB: That a BeanReflectSetter is used to actually perform the setting of
|
||||
* property values to a bean. This is due to performance considerations.
|
||||
* </p>
|
||||
*/
|
||||
public void setWriteMethod(Method writeMethod) {
|
||||
this.writeMethod = writeMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property type.
|
||||
*/
|
||||
|
||||
+15
-15
@@ -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,18 @@ 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);
|
||||
}
|
||||
|
||||
Formula formula = get(prop, Formula.class);
|
||||
if (formula != null) {
|
||||
prop.setSqlFormula(formula.select(), formula.join());
|
||||
@@ -202,8 +214,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 +230,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 +243,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 +253,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 +262,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 +328,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 +372,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 +415,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+41
-116
@@ -1,33 +1,22 @@
|
||||
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.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.
|
||||
@@ -56,20 +45,6 @@ public class DeployCreateProperties {
|
||||
|
||||
createProperties(desc, desc.getBeanType(), 0);
|
||||
desc.sortProperties();
|
||||
|
||||
// check the transient properties...
|
||||
for (DeployBeanProperty prop : desc.propertiesAll()) {
|
||||
if (prop.isTransient()) {
|
||||
if (prop.getWriteMethod() == null || prop.getReadMethod() == null) {
|
||||
// Typically a helper method ... this is expected
|
||||
logger.trace("... transient: " + prop.getFullBeanName());
|
||||
} else {
|
||||
// dubious, possible error...
|
||||
String msg = Message.msg("deploy.property.nofield", desc.getFullName(), prop.getName());
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,41 +84,31 @@ 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);
|
||||
|
||||
Method getter = findGetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
Method setter = findSetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
|
||||
DeployBeanProperty prop = createProp(desc, field, beanType, getter, setter);
|
||||
if (prop == null) {
|
||||
// transient annotation on unsupported type
|
||||
|
||||
} else {
|
||||
DeployBeanProperty prop = createProp(desc, field, beanType, getter);
|
||||
if (prop != null) {
|
||||
// set a order that gives priority to inherited properties
|
||||
// push Id/EmbeddedId up and CreatedTimestamp/UpdatedTimestamp down
|
||||
int sortOverride = prop.getSortOverride();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,33 +193,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) {
|
||||
|
||||
@@ -264,7 +202,7 @@ public class DeployCreateProperties {
|
||||
return new DeployBeanPropertySimpleCollection(desc, targetType, manyType);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("expected non-scalar type" + e.getMessage());
|
||||
logger.debug("expected non-scalar type {}", e.getMessage());
|
||||
}
|
||||
// TODO: Handle Collection of CompoundType and Embedded Type
|
||||
return new DeployBeanPropertyAssocMany(desc, targetType, manyType);
|
||||
@@ -282,19 +220,10 @@ public class DeployCreateProperties {
|
||||
|
||||
if (tt != null && !tt.equals(void.class)){
|
||||
propertyType = tt;
|
||||
logger.debug("target type" + 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)
|
||||
@@ -314,16 +243,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);
|
||||
}
|
||||
@@ -332,19 +261,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);
|
||||
}
|
||||
}
|
||||
@@ -357,13 +286,13 @@ 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(ColumnHstore.class) != null);
|
||||
}
|
||||
|
||||
private boolean isTransientField(Field field) {
|
||||
@@ -372,8 +301,7 @@ public class DeployCreateProperties {
|
||||
return (t != null);
|
||||
}
|
||||
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field, Class<?> beanType,
|
||||
Method getter, Method setter) {
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field, Class<?> beanType, Method getter) {
|
||||
|
||||
DeployBeanProperty prop = createProp(desc, field);
|
||||
if (prop == null) {
|
||||
@@ -383,11 +311,8 @@ public class DeployCreateProperties {
|
||||
prop.setOwningType(beanType);
|
||||
prop.setName(field.getName());
|
||||
|
||||
// the getter or setter could be null if we are using
|
||||
// javaagent type enhancement. If we are using subclass
|
||||
// generation then we do need to find the getter and setter
|
||||
// interested in the getter for reading annotations
|
||||
prop.setReadMethod(getter);
|
||||
prop.setWriteMethod(setter);
|
||||
prop.setField(field);
|
||||
return prop;
|
||||
}
|
||||
|
||||
@@ -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
@@ -785,18 +785,27 @@ public final class DefaultPersister implements Persister {
|
||||
if (!skipSavingThisBean) {
|
||||
saveRecurse(detail, t, parentBean, insertMode);
|
||||
}
|
||||
if (detailIds != null) {
|
||||
// remember the Id (other details not in the collection) will be removed
|
||||
Object id = targetDescriptor.getId(detail);
|
||||
if (!DmlUtil.isNullOrZero(id)) {
|
||||
detailIds.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (detailIds != null) {
|
||||
// deleteMissingChildren is true so deleting children that were not just processed
|
||||
// stateless update with deleteMissingChildren so first
|
||||
// flushBatch to ensure that we have Id values from any inserts
|
||||
t.flushBatch();
|
||||
// now collect the Id values to determine the 'missing children'
|
||||
for (Object detailBean : collection) {
|
||||
if (isMap) {
|
||||
detailBean = ((Map.Entry<?, ?>) detailBean).getValue();
|
||||
}
|
||||
if (detailBean instanceof EntityBean) {
|
||||
Object id = targetDescriptor.getId((EntityBean) detailBean);
|
||||
if (!DmlUtil.isNullOrZero(id)) {
|
||||
// remember the Id (other details not in the collection) will be removed
|
||||
detailIds.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// deleting missing children - children not in our collected detailIds
|
||||
deleteManyDetails(t, prop.getBeanDescriptor(), parentBean, prop, detailIds);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -44,7 +41,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQuery.class);
|
||||
|
||||
private static final int GLOBAL_ROW_LIMIT = Integer.valueOf(System.getProperty("ebean.query.globallimit","1000000"));
|
||||
private static final int GLOBAL_ROW_LIMIT = Integer.valueOf(System.getProperty("ebean.query.globallimit", "1000000"));
|
||||
|
||||
/**
|
||||
* The resultSet rows read.
|
||||
@@ -60,46 +57,22 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
* Flag set when no more rows are in the resultSet.
|
||||
*/
|
||||
private boolean noMoreRows;
|
||||
/**
|
||||
* Id of loaded 'master' bean.
|
||||
*/
|
||||
private Object loadedBeanId;
|
||||
/**
|
||||
* Flag set when 'master' bean changed.
|
||||
*/
|
||||
private boolean loadedBeanChanged;
|
||||
|
||||
/**
|
||||
* The 'master' bean just loaded.
|
||||
*/
|
||||
private EntityBean loadedBean;
|
||||
private EntityBean nextBean;
|
||||
|
||||
/**
|
||||
* Holds the previous loaded bean.
|
||||
*/
|
||||
private EntityBean currentBean;
|
||||
|
||||
private final BeanPropertyAssocMany<?> lazyLoadManyProperty;
|
||||
|
||||
private Object lazyLoadParentId;
|
||||
|
||||
|
||||
private EntityBean lazyLoadParentBean;
|
||||
|
||||
/**
|
||||
* Holds the previous loaded bean.
|
||||
*/
|
||||
private EntityBean prevLoadedBean;
|
||||
|
||||
/**
|
||||
* The detail bean just loaded.
|
||||
*/
|
||||
private EntityBean loadedManyBean;
|
||||
|
||||
/**
|
||||
* The previous 'detail' collection remembered so that for manyToMany we can
|
||||
* turn on the modify listening.
|
||||
*/
|
||||
private Object prevDetailCollection;
|
||||
|
||||
/**
|
||||
* The current 'detail' collection being populated.
|
||||
*/
|
||||
private Object currentDetailCollection;
|
||||
|
||||
/**
|
||||
* The 'master' collection being populated.
|
||||
@@ -123,11 +96,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
private String currentPrefix;
|
||||
|
||||
/**
|
||||
* Flag set true when reading 'master' and 'detail' beans.
|
||||
*/
|
||||
private final boolean manyIncluded;
|
||||
|
||||
/**
|
||||
* Where clause predicates.
|
||||
*/
|
||||
@@ -166,11 +134,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
*/
|
||||
private final BeanPropertyAssocMany<?> manyProperty;
|
||||
|
||||
/**
|
||||
* The many property Expression language object.
|
||||
*/
|
||||
private final ElPropertyValue manyPropertyEl;
|
||||
|
||||
private final int maxRowsLimit;
|
||||
|
||||
private DataReader dataReader;
|
||||
@@ -186,7 +149,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
private final CQueryPlan queryPlan;
|
||||
|
||||
|
||||
private final Mode queryMode;
|
||||
|
||||
private final boolean autoFetchProfiling;
|
||||
@@ -194,20 +156,15 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
private final ObjectGraphNode objectGraphNode;
|
||||
|
||||
private final AutoFetchManager autoFetchManager;
|
||||
|
||||
|
||||
private final WeakReference<NodeUsageListener> autoFetchManagerRef;
|
||||
|
||||
|
||||
private final Boolean readOnly;
|
||||
|
||||
private final SpiExpressionList<?> filterMany;
|
||||
|
||||
private long startNano;
|
||||
|
||||
private long executionTimeMicros;
|
||||
|
||||
private BeanCollectionAdd currentDetailAdd;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
@@ -233,19 +190,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
this.sqlTree = queryPlan.getSqlTree();
|
||||
this.rootNode = sqlTree.getRootNode();
|
||||
|
||||
this.manyProperty = sqlTree.getManyProperty();
|
||||
this.manyPropertyEl = sqlTree.getManyPropertyEl();
|
||||
this.manyIncluded = sqlTree.isManyIncluded();
|
||||
if (manyIncluded) {
|
||||
// get filter to put on the collection for reuse with refresh
|
||||
String manyPropertyName = sqlTree.getManyPropertyName();
|
||||
OrmQueryProperties chunk = query.getDetail().getChunk(manyPropertyName, false);
|
||||
this.filterMany = (chunk == null) ? null : chunk.getFilterMany();
|
||||
} else {
|
||||
this.filterMany = null;
|
||||
}
|
||||
|
||||
this.sql = queryPlan.getSql();
|
||||
this.rawSql = queryPlan.isRawSql();
|
||||
this.rowNumberIncluded = queryPlan.isRowNumberIncluded();
|
||||
@@ -340,7 +285,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
// prepare
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
|
||||
|
||||
if (query.isRawSql()) {
|
||||
ResultSet suppliedResultSet = query.getRawSql().getResultSet();
|
||||
if (suppliedResultSet != null) {
|
||||
@@ -350,13 +295,13 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (forwardOnlyHint) {
|
||||
// Use forward only hints for large resultset processing (Issue 56, MySql specific)
|
||||
pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
pstmt.setFetchSize(Integer.MIN_VALUE);
|
||||
} else {
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
}
|
||||
|
||||
if (query.getTimeout() > 0) {
|
||||
@@ -414,57 +359,17 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
return request.getPersistenceContext();
|
||||
}
|
||||
|
||||
public void setLoadedBean(EntityBean bean, Object id, Object lazyLoadParentId) {
|
||||
if (id != null && id.equals(loadedBeanId)) {
|
||||
// master/detail loading with master bean
|
||||
// unchanged. NB Using id to avoid any issue
|
||||
// with equals not being implemented
|
||||
public void setLazyLoadedChildBean(EntityBean bean, Object lazyLoadParentId) {
|
||||
|
||||
} else {
|
||||
if (manyIncluded) {
|
||||
if (rowCount > 1) {
|
||||
loadedBeanChanged = true;
|
||||
}
|
||||
this.prevLoadedBean = loadedBean;
|
||||
this.loadedBeanId = id;
|
||||
if (lazyLoadParentId != null) {
|
||||
if (!lazyLoadParentId.equals(this.lazyLoadParentId)) {
|
||||
// get the appropriate parent bean from the persistence context
|
||||
this.lazyLoadParentBean = (EntityBean) getPersistenceContext().get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId);
|
||||
this.lazyLoadParentId = lazyLoadParentId;
|
||||
}
|
||||
|
||||
this.loadedBean = bean;
|
||||
|
||||
if (lazyLoadParentId != null) {
|
||||
if (!lazyLoadParentId.equals(this.lazyLoadParentId)) {
|
||||
// get the appropriate parent bean from the persistence context
|
||||
this.lazyLoadParentBean = (EntityBean)getPersistenceContext().get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId);
|
||||
this.lazyLoadParentId = lazyLoadParentId;
|
||||
}
|
||||
|
||||
// add the loadedBean to the appropriate collection of lazyLoadParentBean
|
||||
lazyLoadManyProperty.addBeanToCollectionWithCreate(lazyLoadParentBean, loadedBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoadedManyBean(EntityBean manyValue) {
|
||||
this.loadedManyBean = manyValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last read bean.
|
||||
*/
|
||||
public EntityBean getLoadedBean() {
|
||||
if (manyIncluded) {
|
||||
if (prevDetailCollection instanceof BeanCollection<?>) {
|
||||
((BeanCollection<?>) prevDetailCollection).setModifyListening(manyProperty.getModifyListenMode());
|
||||
|
||||
} else if (currentDetailCollection instanceof BeanCollection<?>) {
|
||||
((BeanCollection<?>) currentDetailCollection).setModifyListening(manyProperty.getModifyListenMode());
|
||||
}
|
||||
}
|
||||
|
||||
if (prevLoadedBean != null) {
|
||||
return prevLoadedBean;
|
||||
} else {
|
||||
return loadedBean;
|
||||
// add the loadedBean to the appropriate collection of lazyLoadParentBean
|
||||
lazyLoadManyProperty.addBeanToCollectionWithCreate(lazyLoadParentBean, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,29 +380,78 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
* the one/master and the second the many/detail.
|
||||
* </p>
|
||||
*/
|
||||
private boolean readRow() throws SQLException {
|
||||
private boolean readNextBean() throws SQLException {
|
||||
|
||||
synchronized (this) {
|
||||
if (cancelled) {
|
||||
if (!moveToNextRow()) {
|
||||
if (currentBean == null) {
|
||||
return false;
|
||||
} else {
|
||||
// the last bean
|
||||
nextBean = currentBean;
|
||||
loadedBeanCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dataReader.next()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rowCount++;
|
||||
dataReader.resetColumnPosition();
|
||||
|
||||
if (rowNumberIncluded) {
|
||||
// row_number() column used for limit features
|
||||
dataReader.incrementPos(1);
|
||||
}
|
||||
|
||||
rootNode.load(this, null);
|
||||
loadedBeanCount++;
|
||||
|
||||
if (manyProperty == null) {
|
||||
// only single resultSet row required to build object so we are done
|
||||
// read a single resultSet row into single bean
|
||||
nextBean = rootNode.load(this, null, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nextBean == null) {
|
||||
// very first read
|
||||
nextBean = rootNode.load(this, null, null);
|
||||
} else {
|
||||
// nextBean set to previously read currentBean
|
||||
nextBean = currentBean;
|
||||
// check the current row we have just moved to
|
||||
if (checkForDifferentBean()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
readUntilDifferentBeanStarted();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read resultSet rows until we hit the end or get a different bean.
|
||||
*/
|
||||
private void readUntilDifferentBeanStarted() throws SQLException {
|
||||
while (moveToNextRow()) {
|
||||
if (checkForDifferentBean()) return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the currentBean from the row data returning true if the bean
|
||||
* is different to the nextBean (false if we need to read more rows).
|
||||
*/
|
||||
private boolean checkForDifferentBean() throws SQLException {
|
||||
currentBean = rootNode.load(this, null, null);
|
||||
return currentBean != nextBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we can move to the next resultSet row.
|
||||
*/
|
||||
private boolean moveToNextRow() throws SQLException {
|
||||
|
||||
if (!dataReader.next()) {
|
||||
noMoreRows = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
rowCount++;
|
||||
dataReader.resetColumnPosition();
|
||||
if (rowNumberIncluded) {
|
||||
// row_number() column used for limit features
|
||||
dataReader.incrementPos(1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public long getQueryExecutionTimeMicros() {
|
||||
@@ -506,96 +460,33 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
public boolean readBean() throws SQLException {
|
||||
|
||||
boolean result = readBeanInternal();
|
||||
|
||||
boolean result = hasNext();
|
||||
updateExecutionStatistics();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean readBeanInternal() throws SQLException {
|
||||
protected EntityBean next() {
|
||||
return nextBean;
|
||||
}
|
||||
|
||||
if (loadedBeanCount >= maxRowsLimit) {
|
||||
return false;
|
||||
}
|
||||
protected boolean hasNext() throws SQLException {
|
||||
|
||||
if (!manyIncluded) {
|
||||
// simple query... no details...
|
||||
return readRow();
|
||||
}
|
||||
|
||||
if (noMoreRows) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rowCount == 0) {
|
||||
if (!readRow()) {
|
||||
// no rows at all...
|
||||
synchronized (this) {
|
||||
if (noMoreRows || cancelled || loadedBeanCount >= maxRowsLimit) {
|
||||
return false;
|
||||
} else {
|
||||
createNewDetailCollection();
|
||||
}
|
||||
}
|
||||
|
||||
if (readIntoCurrentDetailCollection()) {
|
||||
createNewDetailCollection();
|
||||
// return prevLoadedBean
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// return loadedBean
|
||||
prevDetailCollection = null;
|
||||
prevLoadedBean = null;
|
||||
noMoreRows = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readIntoCurrentDetailCollection() throws SQLException {
|
||||
while (readRow()) {
|
||||
if (loadedBeanChanged) {
|
||||
loadedBeanChanged = false;
|
||||
return true;
|
||||
} else {
|
||||
addToCurrentDetailCollection();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void createNewDetailCollection() {
|
||||
prevDetailCollection = currentDetailCollection;
|
||||
if (queryMode.equals(Mode.LAZYLOAD_MANY)) {
|
||||
// just populate the current collection
|
||||
currentDetailCollection = manyPropertyEl.elGetValue(loadedBean);
|
||||
} else {
|
||||
// create a new collection to populate and assign to the bean
|
||||
currentDetailCollection = manyProperty.createEmpty(loadedBean);
|
||||
manyPropertyEl.elSetValue(loadedBean, currentDetailCollection, false);
|
||||
}
|
||||
|
||||
if (filterMany != null) {
|
||||
// remember the for use with a refresh
|
||||
((BeanCollection<?>) currentDetailCollection).setFilterMany(filterMany);
|
||||
}
|
||||
|
||||
// the manyKey is always null for this case, just using default mapKey on the property
|
||||
currentDetailAdd = manyProperty.getBeanCollectionAdd(currentDetailCollection, null);
|
||||
addToCurrentDetailCollection();
|
||||
}
|
||||
|
||||
private void addToCurrentDetailCollection() {
|
||||
if (loadedManyBean != null) {
|
||||
currentDetailAdd.addBean(loadedManyBean);
|
||||
return readNextBean();
|
||||
}
|
||||
}
|
||||
|
||||
public BeanCollection<T> readCollection() throws SQLException {
|
||||
|
||||
readTheRows();
|
||||
while (hasNext()) {
|
||||
EntityBean bean = next();
|
||||
help.add(collection, bean);
|
||||
}
|
||||
|
||||
updateExecutionStatistics();
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
@@ -605,13 +496,12 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
executionTimeMicros = TimeUnit.NANOSECONDS.toMicros(exeNano);
|
||||
|
||||
if (autoFetchProfiling) {
|
||||
autoFetchManager
|
||||
.collectQueryInfo(objectGraphNode, loadedBeanCount, executionTimeMicros);
|
||||
autoFetchManager.collectQueryInfo(objectGraphNode, loadedBeanCount, executionTimeMicros);
|
||||
}
|
||||
queryPlan.executionTime(loadedBeanCount, executionTimeMicros, objectGraphNode);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error(null, e);
|
||||
logger.error("Error updating execution statistics", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,26 +515,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
}
|
||||
}
|
||||
|
||||
private void readTheRows() throws SQLException {
|
||||
while (hasNextBean()) {
|
||||
// add to the list/set/map
|
||||
help.add(collection, getLoadedBean());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean hasNextBean() throws SQLException {
|
||||
|
||||
if (!readBeanInternal()) {
|
||||
return false;
|
||||
|
||||
} else {
|
||||
loadedBeanCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public String getLoadedRowDetail() {
|
||||
if (!manyIncluded) {
|
||||
if (manyProperty == null) {
|
||||
return String.valueOf(rowCount);
|
||||
} else {
|
||||
return loadedBeanCount + ":" + rowCount;
|
||||
@@ -738,13 +610,11 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
* Create a PersistenceException including interesting information like the
|
||||
* bindLog and sql used.
|
||||
*/
|
||||
public static PersistenceException createPersistenceException(SQLException e, SpiTransaction t,
|
||||
String bindLog, String sql) {
|
||||
public static PersistenceException createPersistenceException(SQLException e, SpiTransaction t, String bindLog, String sql) {
|
||||
|
||||
if (t.isLogSummary()) {
|
||||
// log the error to the transaction log
|
||||
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[] { "\r", "\n" },
|
||||
"\\n ");
|
||||
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[]{"\r", "\n"}, "\\n ");
|
||||
String msg = "ERROR executing query: bindLog[" + bindLog + "] error[" + errMsg + "]";
|
||||
t.logSummary(msg);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ public class CQueryEngine {
|
||||
CQueryFetchIds rcQuery = queryBuilder.buildFetchIdsQuery(request);
|
||||
try {
|
||||
|
||||
|
||||
BeanIdList list = rcQuery.findIds();
|
||||
|
||||
if (request.isLogSql()) {
|
||||
@@ -83,13 +82,13 @@ public class CQueryEngine {
|
||||
|
||||
CQueryRowCount rcQuery = queryBuilder.buildRowCountQuery(request);
|
||||
try {
|
||||
|
||||
|
||||
int rowCount = rcQuery.findRowCount();
|
||||
|
||||
if (request.isLogSql()) {
|
||||
String logSql = rcQuery.getGeneratedSql();
|
||||
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
|
||||
logSql= Str.add(logSql, "; --bind(", rcQuery.getBindLog(), ")");
|
||||
logSql = Str.add(logSql, "; --bind(", rcQuery.getBindLog(), ")");
|
||||
}
|
||||
request.logSql(logSql);
|
||||
}
|
||||
@@ -168,7 +167,7 @@ public class CQueryEngine {
|
||||
logger.trace("Future fetch already cancelled");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (request.isLogSql()) {
|
||||
logSql(cquery);
|
||||
}
|
||||
@@ -192,7 +191,7 @@ public class CQueryEngine {
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw cquery.createPersistenceException(e);
|
||||
|
||||
|
||||
} finally {
|
||||
if (cquery != null) {
|
||||
cquery.close();
|
||||
@@ -224,7 +223,7 @@ public class CQueryEngine {
|
||||
}
|
||||
|
||||
if (cquery.readBean()) {
|
||||
bean = cquery.getLoadedBean();
|
||||
bean = cquery.next();
|
||||
}
|
||||
|
||||
if (request.isLogSummary()) {
|
||||
@@ -233,7 +232,7 @@ public class CQueryEngine {
|
||||
|
||||
request.executeSecondaryQueries();
|
||||
|
||||
return (T)bean;
|
||||
return (T) bean;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw cquery.createPersistenceException(e);
|
||||
@@ -250,7 +249,7 @@ public class CQueryEngine {
|
||||
|
||||
String sql = query.getGeneratedSql();
|
||||
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
|
||||
sql= Str.add(sql, "; --bind(", query.getBindLog(), ")");
|
||||
sql = Str.add(sql, "; --bind(", query.getBindLog(), ")");
|
||||
}
|
||||
query.getTransaction().logSql(sql);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
@@ -21,263 +9,262 @@ import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.core.SpiOrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.DataReader;
|
||||
import com.avaje.ebeaninternal.server.type.RsetDataReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Executes the select row count query.
|
||||
*/
|
||||
public class CQueryFetchIds {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQueryFetchIds.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQueryFetchIds.class);
|
||||
|
||||
/**
|
||||
* The overall find request wrapper object.
|
||||
*/
|
||||
private final OrmQueryRequest<?> request;
|
||||
/**
|
||||
* The overall find request wrapper object.
|
||||
*/
|
||||
private final OrmQueryRequest<?> request;
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
private final BeanDescriptor<?> desc;
|
||||
|
||||
private final SpiQuery<?> query;
|
||||
private final SpiQuery<?> query;
|
||||
|
||||
/**
|
||||
* Where clause predicates.
|
||||
*/
|
||||
private final CQueryPredicates predicates;
|
||||
/**
|
||||
* Where clause predicates.
|
||||
*/
|
||||
private final CQueryPredicates predicates;
|
||||
|
||||
/**
|
||||
* The final sql that is generated.
|
||||
*/
|
||||
private final String sql;
|
||||
/**
|
||||
* The final sql that is generated.
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
private RsetDataReader dataReader;
|
||||
|
||||
/**
|
||||
* The statement used to create the resultSet.
|
||||
*/
|
||||
private PreparedStatement pstmt;
|
||||
private RsetDataReader dataReader;
|
||||
|
||||
private String bindLog;
|
||||
/**
|
||||
* The statement used to create the resultSet.
|
||||
*/
|
||||
private PreparedStatement pstmt;
|
||||
|
||||
private long startNano;
|
||||
|
||||
private int executionTimeMicros;
|
||||
private String bindLog;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private final int maxRows;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
public CQueryFetchIds(OrmQueryRequest<?> request, CQueryPredicates predicates, String sql) {
|
||||
private int executionTimeMicros;
|
||||
|
||||
this.request = request;
|
||||
this.query = request.getQuery();
|
||||
this.sql = sql;
|
||||
this.maxRows = query.getMaxRows();
|
||||
private int rowCount;
|
||||
|
||||
query.setGeneratedSql(sql);
|
||||
private final int maxRows;
|
||||
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
public CQueryFetchIds(OrmQueryRequest<?> request, CQueryPredicates predicates, String sql) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a summary description of this query.
|
||||
*/
|
||||
public String getSummary() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("FindIds exeMicros[").append(executionTimeMicros)
|
||||
.append("] rows[").append(rowCount)
|
||||
.append("] type[").append(desc.getName())
|
||||
.append("] predicates[").append(predicates.getLogWhereSql())
|
||||
.append("] bind[").append(bindLog).append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
this.request = request;
|
||||
this.query = request.getQuery();
|
||||
this.sql = sql;
|
||||
this.maxRows = query.getMaxRows();
|
||||
|
||||
/**
|
||||
* Return the bind log.
|
||||
*/
|
||||
public String getBindLog() {
|
||||
return bindLog;
|
||||
query.setGeneratedSql(sql);
|
||||
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a summary description of this query.
|
||||
*/
|
||||
public String getSummary() {
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append("FindIds exeMicros[").append(executionTimeMicros)
|
||||
.append("] rows[").append(rowCount)
|
||||
.append("] type[").append(desc.getName())
|
||||
.append("] predicates[").append(predicates.getLogWhereSql())
|
||||
.append("] bind[").append(bindLog).append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind log.
|
||||
*/
|
||||
public String getBindLog() {
|
||||
return bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated sql.
|
||||
*/
|
||||
public String getGeneratedSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query returning the row count.
|
||||
*/
|
||||
public BeanIdList findIds() throws SQLException {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
|
||||
try {
|
||||
// get the list that we are going to put the id's into.
|
||||
// This was already set so that it is available to be
|
||||
// read by other threads (it is a synchronised list)
|
||||
List<Object> idList = query.getIdList();
|
||||
if (idList == null) {
|
||||
// running in foreground thread (not FutureIds query)
|
||||
idList = Collections.synchronizedList(new ArrayList<Object>());
|
||||
query.setIdList(idList);
|
||||
}
|
||||
|
||||
BeanIdList result = new BeanIdList(idList);
|
||||
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
if (query.getBufferFetchSizeHint() > 0) {
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
|
||||
if (query.getTimeout() > 0) {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
|
||||
bindLog = predicates.bind(new DataBind(pstmt));
|
||||
|
||||
ResultSet rset = pstmt.executeQuery();
|
||||
dataReader = new RsetDataReader(rset);
|
||||
|
||||
boolean hitMaxRows = false;
|
||||
boolean hasMoreRows = false;
|
||||
rowCount = 0;
|
||||
|
||||
DbReadContext ctx = new DbContext();
|
||||
|
||||
while (rset.next()) {
|
||||
Object idValue = desc.getIdBinder().read(ctx);
|
||||
idList.add(idValue);
|
||||
// reset back to 0
|
||||
dataReader.resetColumnPosition();
|
||||
rowCount++;
|
||||
|
||||
if (maxRows > 0 && rowCount == maxRows) {
|
||||
hitMaxRows = true;
|
||||
hasMoreRows = rset.next();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (hitMaxRows) {
|
||||
result.setHasMore(hasMoreRows);
|
||||
}
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = (int) exeNano / 1000;
|
||||
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resources.
|
||||
* <p>
|
||||
* The jdbc resultSet and statement need to be closed. Its important that
|
||||
* this method is called.
|
||||
* </p>
|
||||
*/
|
||||
private void close() {
|
||||
try {
|
||||
if (dataReader != null) {
|
||||
dataReader.close();
|
||||
dataReader = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
try {
|
||||
if (pstmt != null) {
|
||||
pstmt.close();
|
||||
pstmt = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DbContext implements DbReadContext {
|
||||
|
||||
public void propagateState(Object e) {
|
||||
throw new RuntimeException("Not Called");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated sql.
|
||||
*/
|
||||
public String getGeneratedSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public SpiOrmQueryRequest<?> getQueryRequest() {
|
||||
return request;
|
||||
}
|
||||
public Mode getQueryMode() {
|
||||
return Mode.NORMAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query returning the row count.
|
||||
*/
|
||||
public BeanIdList findIds() throws SQLException {
|
||||
public DataReader getDataReader() {
|
||||
return dataReader;
|
||||
}
|
||||
|
||||
startNano = System.nanoTime();
|
||||
|
||||
try {
|
||||
// get the list that we are going to put the id's into.
|
||||
// This was already set so that it is available to be
|
||||
// read by other threads (it is a synchronised list)
|
||||
List<Object> idList = query.getIdList();
|
||||
if (idList == null){
|
||||
// running in foreground thread (not FutureIds query)
|
||||
idList = Collections.synchronizedList(new ArrayList<Object>());
|
||||
query.setIdList(idList);
|
||||
}
|
||||
|
||||
BeanIdList result = new BeanIdList(idList);
|
||||
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
if (query.getBufferFetchSizeHint() > 0){
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
|
||||
if (query.getTimeout() > 0){
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
|
||||
bindLog = predicates.bind(new DataBind(pstmt));
|
||||
|
||||
ResultSet rset = pstmt.executeQuery();
|
||||
dataReader = new RsetDataReader(rset);
|
||||
|
||||
boolean hitMaxRows = false;
|
||||
boolean hasMoreRows = false;
|
||||
rowCount = 0;
|
||||
|
||||
DbReadContext ctx = new DbContext();
|
||||
|
||||
while (rset.next()){
|
||||
Object idValue = desc.getIdBinder().read(ctx);
|
||||
idList.add(idValue);
|
||||
// reset back to 0
|
||||
dataReader.resetColumnPosition();
|
||||
rowCount++;
|
||||
|
||||
if (maxRows > 0 && rowCount == maxRows) {
|
||||
hitMaxRows = true;
|
||||
hasMoreRows = rset.next();
|
||||
break;
|
||||
public Boolean isReadOnly() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (hitMaxRows){
|
||||
result.setHasMore(hasMoreRows);
|
||||
}
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = (int)exeNano/1000;
|
||||
public boolean isRawSql() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
public void register(String path, EntityBeanIntercept ebi) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resources.
|
||||
* <p>
|
||||
* The jdbc resultSet and statement need to be closed. Its important that
|
||||
* this method is called.
|
||||
* </p>
|
||||
*/
|
||||
private void close() {
|
||||
try {
|
||||
if (dataReader != null) {
|
||||
dataReader.close();
|
||||
dataReader = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
try {
|
||||
if (pstmt != null) {
|
||||
pstmt.close();
|
||||
pstmt = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
}
|
||||
public void register(String path, BeanCollection<?> bc) {
|
||||
}
|
||||
|
||||
|
||||
class DbContext implements DbReadContext {
|
||||
public BeanPropertyAssocMany<?> getManyProperty() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
|
||||
public void propagateState(Object e) {
|
||||
throw new RuntimeException("Not Called");
|
||||
}
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
|
||||
public Mode getQueryMode() {
|
||||
return Mode.NORMAL;
|
||||
}
|
||||
|
||||
public DataReader getDataReader() {
|
||||
return dataReader;
|
||||
}
|
||||
public boolean isAutoFetchProfiling() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Boolean isReadOnly() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
public boolean isRawSql() {
|
||||
return false;
|
||||
}
|
||||
public void profileBean(EntityBeanIntercept ebi, String prefix) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void register(String path, EntityBeanIntercept ebi){
|
||||
}
|
||||
public void setCurrentPrefix(String currentPrefix, Map<String, String> pathMap) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void register(String path, BeanCollection<?> bc){
|
||||
}
|
||||
public void setLazyLoadedChildBean(EntityBean loadedBean, Object lazyLoadParentId) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?> getManyProperty() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isAutoFetchProfiling() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void profileBean(EntityBeanIntercept ebi, String prefix) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void setCurrentPrefix(String currentPrefix,Map<String, String> pathMap) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void setLoadedBean(EntityBean loadedBean, Object id, Object lazyLoadParentId) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void setLoadedManyBean(EntityBean loadedBean) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
class CQueryIteratorSimple<T> implements QueryIterator<T> {
|
||||
|
||||
private final CQuery<T> cquery;
|
||||
|
||||
private final OrmQueryRequest<T> request;
|
||||
|
||||
CQueryIteratorSimple(CQuery<T> cquery, OrmQueryRequest<T> request) {
|
||||
@@ -23,7 +24,7 @@ class CQueryIteratorSimple<T> implements QueryIterator<T> {
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
request.flushPersistenceContextOnIterate();
|
||||
return cquery.hasNextBean();
|
||||
return cquery.hasNext();
|
||||
} catch (SQLException e) {
|
||||
throw cquery.createPersistenceException(e);
|
||||
}
|
||||
@@ -31,7 +32,7 @@ class CQueryIteratorSimple<T> implements QueryIterator<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T next() {
|
||||
return (T)cquery.getLoadedBean();
|
||||
return (T) cquery.next();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
||||
@@ -36,8 +36,8 @@ class CQueryIteratorWithBuffer<T> implements QueryIterator<T> {
|
||||
|
||||
int i = -1;
|
||||
while (moreToLoad && ++i < bufferSize) {
|
||||
if (cquery.hasNextBean()) {
|
||||
buffer.add((T)cquery.getLoadedBean());
|
||||
if (cquery.hasNext()) {
|
||||
buffer.add((T) cquery.next());
|
||||
} else {
|
||||
moreToLoad = false;
|
||||
}
|
||||
|
||||
@@ -9,31 +9,25 @@ import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
|
||||
public interface SqlTreeNode {
|
||||
|
||||
public static final String PERIOD = ".";
|
||||
String COMMA = ", ";
|
||||
|
||||
public static final String COMMA = ", ";
|
||||
|
||||
public static final int NORMAL = 0;
|
||||
public static final int SHARED = 1;
|
||||
public static final int READONLY = 2;
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain);
|
||||
void buildSelectExpressionChain(List<String> selectChain);
|
||||
|
||||
/**
|
||||
* Append the required column information to the SELECT part of the sql
|
||||
* statement.
|
||||
*/
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery);
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery);
|
||||
|
||||
/**
|
||||
* Append to the FROM part of the sql.
|
||||
*/
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType);
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType);
|
||||
|
||||
/**
|
||||
* Append any where predicates for inheritance.
|
||||
*/
|
||||
public void appendWhere(DbSqlContext ctx);
|
||||
void appendWhere(DbSqlContext ctx);
|
||||
|
||||
/**
|
||||
* Load the appropriate information from the SqlSelectReader.
|
||||
@@ -41,8 +35,7 @@ public interface SqlTreeNode {
|
||||
* At a high level this actually controls the reading of the data from the
|
||||
* jdbc resultSet and putting it into the bean etc.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public void load(DbReadContext ctx, EntityBean parentBean) throws SQLException;
|
||||
EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -69,7 +69,9 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
protected final Map<String, String> pathMap;
|
||||
|
||||
protected final BeanPropertyAssocMany<?> lazyLoadParent;
|
||||
|
||||
|
||||
private final IdBinder lazyLoadParentIdBinder;
|
||||
|
||||
public SqlTreeNodeBean(String prefix, BeanPropertyAssoc<?> beanProp, SqlTreeProperties props,
|
||||
List<SqlTreeNode> myChildren, boolean withId) {
|
||||
|
||||
@@ -83,6 +85,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
SqlTreeProperties props, List<SqlTreeNode> myChildren, boolean withId, BeanPropertyAssocMany<?> lazyLoadParent) {
|
||||
|
||||
this.lazyLoadParent = lazyLoadParent;
|
||||
this.lazyLoadParentIdBinder = (lazyLoadParent == null) ? null : lazyLoadParent.getBeanDescriptor().getIdBinder();
|
||||
this.prefix = prefix;
|
||||
this.nodeBeanProp = beanProp;
|
||||
this.desc = desc;
|
||||
@@ -134,9 +137,6 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
protected void postLoad(DbReadContext cquery, EntityBean loadedBean, Object id, Object lazyLoadParentId) {
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
if (readId) {
|
||||
idBinder.buildSelectExpressionChain(prefix, selectChain);
|
||||
@@ -155,11 +155,11 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
/**
|
||||
* read the properties from the resultSet.
|
||||
*/
|
||||
public void load(DbReadContext ctx, EntityBean parentBean) throws SQLException {
|
||||
public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException {
|
||||
|
||||
Object lazyLoadParentId = null;
|
||||
if (lazyLoadParent != null) {
|
||||
lazyLoadParentId = lazyLoadParent.getBeanDescriptor().getIdBinder().read(ctx);
|
||||
if (lazyLoadParentIdBinder != null) {
|
||||
lazyLoadParentId = lazyLoadParentIdBinder.read(ctx);
|
||||
}
|
||||
|
||||
// bean already existing in the persistence context
|
||||
@@ -196,12 +196,8 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
|
||||
PersistenceContext persistenceContext = !readId ? null : ctx.getPersistenceContext();
|
||||
|
||||
Object id = null;
|
||||
if (!readId) {
|
||||
// report type bean... or perhaps excluding the id for SqlSelect?
|
||||
|
||||
} else {
|
||||
id = localIdBinder.readSet(ctx, localBean);
|
||||
if (readId) {
|
||||
Object id = localIdBinder.readSet(ctx, localBean);
|
||||
if (id == null) {
|
||||
// bean must be null...
|
||||
localBean = null;
|
||||
@@ -265,51 +261,45 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
// read each child... and let them set their
|
||||
// values back to this localBean
|
||||
children[i].load(ctx, localBean);
|
||||
children[i].load(ctx, localBean, contextBean);
|
||||
}
|
||||
|
||||
if (lazyLoadMany) {
|
||||
// special case where we load children
|
||||
|
||||
} else if (localBean != null) {
|
||||
|
||||
if (!lazyLoadMany && localBean != null) {
|
||||
ctx.setCurrentPrefix(prefix, pathMap);
|
||||
if (readId) {
|
||||
createListProxies(localDesc, ctx, localBean);
|
||||
}
|
||||
localDesc.postLoad(localBean, null);
|
||||
|
||||
if (localBean instanceof EntityBean) {
|
||||
EntityBeanIntercept ebi = ((EntityBean) localBean)._ebean_getIntercept();
|
||||
ebi.setPersistenceContext(persistenceContext);
|
||||
if (Mode.LAZYLOAD_BEAN.equals(queryMode)) {
|
||||
// Lazy Load does not reset the dirty state
|
||||
ebi.setLoadedLazy();
|
||||
} else {
|
||||
// normal bean loading
|
||||
ebi.setLoaded();
|
||||
}
|
||||
|
||||
if (partialObject) {
|
||||
if (readId) {
|
||||
// register for lazy loading
|
||||
ctx.register(null, ebi);
|
||||
}
|
||||
} else {
|
||||
ebi.setFullyLoadedBean(true);
|
||||
}
|
||||
|
||||
if (disableLazyLoad) {
|
||||
// bean does not have an Id or is SqlSelect based
|
||||
ebi.setDisableLazyLoad(true);
|
||||
}
|
||||
if (ctx.isAutoFetchProfiling()) {
|
||||
// collect autofetch profiling for this bean...
|
||||
ctx.profileBean(ebi, prefix);
|
||||
}
|
||||
EntityBeanIntercept ebi = localBean._ebean_getIntercept();
|
||||
ebi.setPersistenceContext(persistenceContext);
|
||||
if (Mode.LAZYLOAD_BEAN.equals(queryMode)) {
|
||||
// Lazy Load does not reset the dirty state
|
||||
ebi.setLoadedLazy();
|
||||
} else {
|
||||
// normal bean loading
|
||||
ebi.setLoaded();
|
||||
}
|
||||
|
||||
if (partialObject) {
|
||||
if (readId) {
|
||||
// register for lazy loading
|
||||
ctx.register(null, ebi);
|
||||
}
|
||||
} else {
|
||||
ebi.setFullyLoadedBean(true);
|
||||
}
|
||||
|
||||
if (disableLazyLoad) {
|
||||
// bean does not have an Id or is SqlSelect based
|
||||
ebi.setDisableLazyLoad(true);
|
||||
}
|
||||
if (ctx.isAutoFetchProfiling()) {
|
||||
// collect autofetch profiling for this bean...
|
||||
ctx.profileBean(ebi, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
if (parentBean != null) {
|
||||
// set this back to the parentBean
|
||||
nodeBeanProp.setValue(parentBean, contextBean);
|
||||
@@ -317,13 +307,13 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
|
||||
if (!readId) {
|
||||
// a bean with no Id (never found in context)
|
||||
postLoad(ctx, localBean, id, null);
|
||||
return localBean;
|
||||
|
||||
} else {
|
||||
// return the contextBean which is either the localBean
|
||||
// read from the resultSet and put into the context OR
|
||||
// the 'matching' bean that already existed in the context
|
||||
postLoad(ctx, contextBean, id, lazyLoadParentId);
|
||||
if (lazyLoadParentId != null) {
|
||||
ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId);
|
||||
}
|
||||
return contextBean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,10 +329,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
BeanPropertyAssocMany<?>[] manys = localDesc.propertiesMany();
|
||||
for (int i = 0; i < manys.length; i++) {
|
||||
|
||||
if (fetchedMany != null && fetchedMany.equals(manys[i])) {
|
||||
// this many property is included in the query...
|
||||
// it is being loaded with real row data (result[1])
|
||||
} else {
|
||||
if (fetchedMany == null || !fetchedMany.equals(manys[i])) {
|
||||
// create a proxy for the many (deferred fetching)
|
||||
BeanCollection<?> ref = manys[i].createReferenceIfNull(localBean);
|
||||
if (ref != null && !ref.isRegisteredWithLoadContext()) {
|
||||
@@ -418,13 +405,9 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
|
||||
// Only apply inheritance to root node as any join will alreay have the inheritance join include - see TableJoin
|
||||
if (inheritInfo != null && nodeBeanProp == null) {
|
||||
if (inheritInfo.isRoot()) {
|
||||
// at root of hierarchy so don't bother
|
||||
// adding a where clause because we want
|
||||
// all the types...
|
||||
} else {
|
||||
// Only apply inheritance to root node as any join will alreay have the inheritance join include - see TableJoin
|
||||
if (inheritInfo != null && nodeBeanProp == null) {
|
||||
if (!inheritInfo.isRoot()) {
|
||||
// restrict to this type and
|
||||
// sub types of this type.
|
||||
if (ctx.length() > 0) {
|
||||
|
||||
@@ -21,81 +21,76 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
*/
|
||||
public class SqlTreeNodeExtraJoin implements SqlTreeNode {
|
||||
|
||||
|
||||
private final BeanPropertyAssoc<?> assocBeanProperty;
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private final boolean manyJoin;
|
||||
|
||||
private List<SqlTreeNodeExtraJoin> children;
|
||||
|
||||
public SqlTreeNodeExtraJoin(String prefix, BeanPropertyAssoc<?> assocBeanProperty) {
|
||||
this.prefix = prefix;
|
||||
this.assocBeanProperty = assocBeanProperty;
|
||||
this.manyJoin = assocBeanProperty instanceof BeanPropertyAssocMany<?>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
private final BeanPropertyAssoc<?> assocBeanProperty;
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private final boolean manyJoin;
|
||||
|
||||
private List<SqlTreeNodeExtraJoin> children;
|
||||
|
||||
public SqlTreeNodeExtraJoin(String prefix, BeanPropertyAssoc<?> assocBeanProperty) {
|
||||
this.prefix = prefix;
|
||||
this.assocBeanProperty = assocBeanProperty;
|
||||
this.manyJoin = assocBeanProperty instanceof BeanPropertyAssocMany<?>;
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the extra join is a many join.
|
||||
* <p>
|
||||
* This means we need to add distinct to the sql query.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isManyJoin() {
|
||||
return manyJoin;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the extra join is a many join.
|
||||
* <p>
|
||||
* This means we need to add distinct to the sql query.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isManyJoin() {
|
||||
return manyJoin;
|
||||
}
|
||||
public void addChild(SqlTreeNodeExtraJoin child) {
|
||||
if (children == null) {
|
||||
children = new ArrayList<SqlTreeNodeExtraJoin>();
|
||||
}
|
||||
children.add(child);
|
||||
}
|
||||
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
public String getName() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void addChild(SqlTreeNodeExtraJoin child){
|
||||
if (children == null){
|
||||
children = new ArrayList<SqlTreeNodeExtraJoin>();
|
||||
}
|
||||
children.add(child);
|
||||
}
|
||||
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
boolean manyToMany = false;
|
||||
|
||||
if (assocBeanProperty instanceof BeanPropertyAssocMany<?>){
|
||||
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>)assocBeanProperty;
|
||||
if (manyProp.isManyToMany()){
|
||||
|
||||
manyToMany = true;
|
||||
|
||||
String alias = ctx.getTableAlias(prefix);
|
||||
String[] split = SplitName.split(prefix);
|
||||
String parentAlias = ctx.getTableAlias(split[0]);
|
||||
String alias2 = alias+"z_";
|
||||
|
||||
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
|
||||
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
|
||||
|
||||
assocBeanProperty.addJoin(joinType, alias2, alias, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (!manyToMany){
|
||||
assocBeanProperty.addJoin(joinType, prefix, ctx);
|
||||
}
|
||||
boolean manyToMany = false;
|
||||
|
||||
if (assocBeanProperty instanceof BeanPropertyAssocMany<?>) {
|
||||
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>) assocBeanProperty;
|
||||
if (manyProp.isManyToMany()) {
|
||||
|
||||
manyToMany = true;
|
||||
|
||||
String alias = ctx.getTableAlias(prefix);
|
||||
String[] split = SplitName.split(prefix);
|
||||
String parentAlias = ctx.getTableAlias(split[0]);
|
||||
String alias2 = alias + "z_";
|
||||
|
||||
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
|
||||
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
|
||||
|
||||
assocBeanProperty.addJoin(joinType, alias2, alias, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (!manyToMany) {
|
||||
assocBeanProperty.addJoin(joinType, prefix, ctx);
|
||||
}
|
||||
|
||||
if (children != null) {
|
||||
|
||||
if (manyJoin) {
|
||||
// if AUTO then make all decendants use OUTER JOIN
|
||||
// if AUTO then make all descendants use OUTER JOIN
|
||||
joinType = joinType.autoToOuter();
|
||||
}
|
||||
|
||||
@@ -106,22 +101,23 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
}
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
}
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void load(DbReadContext ctx, EntityBean parentBean) throws SQLException {
|
||||
}
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,24 +10,22 @@ import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
|
||||
public final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
|
||||
|
||||
final BeanPropertyAssocMany<?> manyProp;
|
||||
|
||||
public SqlTreeNodeManyRoot(String prefix, BeanPropertyAssocMany<?> prop, SqlTreeProperties props, List<SqlTreeNode> myList) {
|
||||
super(prefix, prop, prop.getTargetDescriptor(), props, myList, true, null);
|
||||
this.manyProp = prop;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postLoad(DbReadContext cquery, EntityBean loadedBean, Object id, Object lazyLoadParentId) {
|
||||
|
||||
// put the localBean into the manyValue so that it
|
||||
// is added to the collection/map
|
||||
cquery.setLoadedManyBean(loadedBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(DbReadContext cquery, EntityBean parentBean) throws SQLException {
|
||||
public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException {
|
||||
// pass in null for parentBean because the localBean
|
||||
// that is built is added to a collection rather than
|
||||
// being set to the parentBean directly
|
||||
super.load(cquery, null);
|
||||
EntityBean detailBean = super.load(cquery, null, null);
|
||||
// initialise the collection and add detailBean if it is not null
|
||||
manyProp.addBeanToCollectionWithCreate(contextParent, detailBean);
|
||||
return detailBean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,91 +17,80 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
*/
|
||||
public class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
|
||||
|
||||
private final String parentPrefix;
|
||||
|
||||
private final String prefix;
|
||||
private final String parentPrefix;
|
||||
|
||||
private final BeanPropertyAssoc<?> nodeBeanProp;
|
||||
|
||||
/**
|
||||
* Child joins.
|
||||
*/
|
||||
private final SqlTreeNode[] children;
|
||||
|
||||
/**
|
||||
* The many where join which is either INNER or OUTER.
|
||||
*/
|
||||
private final SqlJoinType manyJoinType;
|
||||
private final String prefix;
|
||||
|
||||
public SqlTreeNodeManyWhereJoin(String prefix, BeanPropertyAssoc<?> prop, SqlJoinType manyJoinType) {
|
||||
|
||||
this.nodeBeanProp = prop;
|
||||
this.prefix = prefix;
|
||||
this.manyJoinType = manyJoinType;
|
||||
private final BeanPropertyAssoc<?> nodeBeanProp;
|
||||
|
||||
String[] split = SplitName.split(prefix);
|
||||
this.parentPrefix = split[0];
|
||||
|
||||
List<SqlTreeNode> childrenList = new ArrayList<SqlTreeNode>(0);
|
||||
this.children = childrenList.toArray(new SqlTreeNode[childrenList.size()]);
|
||||
/**
|
||||
* The many where join which is either INNER or OUTER.
|
||||
*/
|
||||
private final SqlJoinType manyJoinType;
|
||||
|
||||
public SqlTreeNodeManyWhereJoin(String prefix, BeanPropertyAssoc<?> prop, SqlJoinType manyJoinType) {
|
||||
|
||||
this.nodeBeanProp = prop;
|
||||
this.prefix = prefix;
|
||||
this.manyJoinType = manyJoinType;
|
||||
|
||||
String[] split = SplitName.split(prefix);
|
||||
this.parentPrefix = split[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to the FROM clause for this node.
|
||||
*/
|
||||
@Override
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType currentJoinType) {
|
||||
|
||||
// always use the join type as per this many where join
|
||||
// (OUTER for disjunction and otherwise INNER)
|
||||
appendFromBaseTable(ctx, manyJoinType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join to base table for this node. This includes a join to the
|
||||
* intersection table if this is a ManyToMany node.
|
||||
*/
|
||||
public void appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
String alias = ctx.getTableAliasManyWhere(prefix);
|
||||
String parentAlias = ctx.getTableAliasManyWhere(parentPrefix);
|
||||
|
||||
if (nodeBeanProp instanceof BeanPropertyAssocOne<?>) {
|
||||
nodeBeanProp.addJoin(joinType, parentAlias, alias, ctx);
|
||||
|
||||
} else {
|
||||
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>) nodeBeanProp;
|
||||
if (!manyProp.isManyToMany()) {
|
||||
manyProp.addJoin(joinType, parentAlias, alias, ctx);
|
||||
|
||||
} else {
|
||||
String alias2 = alias + "z_";
|
||||
|
||||
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
|
||||
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
|
||||
manyProp.addJoin(joinType, alias2, alias, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to the FROM clause for this node.
|
||||
*/
|
||||
@Override
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType currentJoinType) {
|
||||
|
||||
// always use the join type as per this many where join
|
||||
// (OUTER for disjunction and otherwise INNER)
|
||||
appendFromBaseTable(ctx, manyJoinType);
|
||||
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
children[i].appendFrom(ctx, manyJoinType);
|
||||
}
|
||||
}
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
/**
|
||||
* Join to base table for this node. This includes a join to the
|
||||
* intersection table if this is a ManyToMany node.
|
||||
*/
|
||||
public void appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
String alias = ctx.getTableAliasManyWhere(prefix);
|
||||
String parentAlias = ctx.getTableAliasManyWhere(parentPrefix);
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
if (nodeBeanProp instanceof BeanPropertyAssocOne<?>){
|
||||
nodeBeanProp.addJoin(joinType, parentAlias, alias, ctx);
|
||||
|
||||
} else {
|
||||
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>)nodeBeanProp;
|
||||
if (!manyProp.isManyToMany()) {
|
||||
manyProp.addJoin(joinType, parentAlias, alias, ctx);
|
||||
|
||||
} else {
|
||||
String alias2 = alias + "z_";
|
||||
|
||||
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
|
||||
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
|
||||
manyProp.addJoin(joinType, alias2, alias, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
public void load(DbReadContext ctx, EntityBean parentBean) throws SQLException {
|
||||
// nothing to do here
|
||||
}
|
||||
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) throws SQLException {
|
||||
// nothing to do here
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,41 +1,32 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the root node of the Sql Tree.
|
||||
*/
|
||||
public final class SqlTreeNodeRoot extends SqlTreeNodeBean {
|
||||
|
||||
private final TableJoin includeJoin;
|
||||
|
||||
/**
|
||||
* Specify for SqlSelect to include an Id property or not.
|
||||
*/
|
||||
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId, TableJoin includeJoin, BeanPropertyAssocMany<?> many){
|
||||
super(null, null, desc, props, myList, withId, many);
|
||||
this.includeJoin = includeJoin;
|
||||
}
|
||||
private final TableJoin includeJoin;
|
||||
|
||||
/**
|
||||
* Specify for SqlSelect to include an Id property or not.
|
||||
*/
|
||||
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId, TableJoin includeJoin, BeanPropertyAssocMany<?> many) {
|
||||
super(null, null, desc, props, myList, withId, many);
|
||||
this.includeJoin = includeJoin;
|
||||
}
|
||||
|
||||
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId) {
|
||||
super(null, null, desc, props, myList, withId, null);
|
||||
this.includeJoin = null;
|
||||
}
|
||||
|
||||
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId) {
|
||||
super(null, null, desc, props, myList, withId, null);
|
||||
this.includeJoin = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postLoad(DbReadContext cquery, EntityBean loadedBean, Object id, Object lazyLoadParentId) {
|
||||
|
||||
// set the current bean with id...
|
||||
cquery.setLoadedBean(loadedBean, id, lazyLoadParentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the root node there is no join type or on clause etc.
|
||||
*/
|
||||
@@ -53,5 +44,5 @@ public final class SqlTreeNodeRoot extends SqlTreeNodeBean {
|
||||
|
||||
return joinType;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -14,86 +14,69 @@ public class SqlTreeProperties {
|
||||
|
||||
private static final TableJoin[] EMPTY_TABLE_JOINS = new TableJoin[0];
|
||||
|
||||
/**
|
||||
* True if this node of the tree should have read only entity beans.
|
||||
*/
|
||||
private boolean readOnly;
|
||||
/**
|
||||
* True if this node of the tree should have read only entity beans.
|
||||
*/
|
||||
private boolean readOnly;
|
||||
|
||||
/**
|
||||
* set to false if the id field is not included.
|
||||
*/
|
||||
private boolean includeId = true;
|
||||
private TableJoin[] tableJoins = EMPTY_TABLE_JOINS;
|
||||
|
||||
private TableJoin[] tableJoins = EMPTY_TABLE_JOINS;
|
||||
/**
|
||||
* The bean properties in order.
|
||||
*/
|
||||
private List<BeanProperty> propsList = new ArrayList<BeanProperty>();
|
||||
|
||||
/**
|
||||
* The bean properties in order.
|
||||
*/
|
||||
private List<BeanProperty> propsList = new ArrayList<BeanProperty>();
|
||||
|
||||
/**
|
||||
* Maintain a list of property names to detect embedded bean additions.
|
||||
*/
|
||||
private LinkedHashSet<String> propNames = new LinkedHashSet<String>();
|
||||
/**
|
||||
* Maintain a list of property names to detect embedded bean additions.
|
||||
*/
|
||||
private LinkedHashSet<String> propNames = new LinkedHashSet<String>();
|
||||
|
||||
private boolean allProperties;
|
||||
|
||||
public SqlTreeProperties() {
|
||||
}
|
||||
|
||||
public boolean containsProperty(String propName){
|
||||
return propNames.contains(propName);
|
||||
}
|
||||
|
||||
public void add(BeanProperty[] props) {
|
||||
for (BeanProperty beanProperty : props) {
|
||||
propsList.add(beanProperty);
|
||||
}
|
||||
}
|
||||
public SqlTreeProperties() {
|
||||
}
|
||||
|
||||
public void add(BeanProperty prop) {
|
||||
public boolean containsProperty(String propName) {
|
||||
return propNames.contains(propName);
|
||||
}
|
||||
|
||||
public void add(BeanProperty[] props) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
propsList.add(props[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(BeanProperty prop) {
|
||||
propsList.add(prop);
|
||||
propNames.add(prop.getName());
|
||||
}
|
||||
|
||||
public BeanProperty[] getProps() {
|
||||
return propsList.toArray(new BeanProperty[propsList.size()]);
|
||||
}
|
||||
propNames.add(prop.getName());
|
||||
}
|
||||
|
||||
public boolean isIncludeId() {
|
||||
return includeId;
|
||||
}
|
||||
public BeanProperty[] getProps() {
|
||||
return propsList.toArray(new BeanProperty[propsList.size()]);
|
||||
}
|
||||
|
||||
public void setIncludeId(boolean includeId) {
|
||||
this.includeId = includeId;
|
||||
}
|
||||
public boolean isPartialObject() {
|
||||
return !allProperties;
|
||||
}
|
||||
|
||||
public boolean isPartialObject() {
|
||||
return !allProperties;
|
||||
}
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
public TableJoin[] getTableJoins() {
|
||||
return tableJoins;
|
||||
}
|
||||
|
||||
public TableJoin[] getTableJoins() {
|
||||
return tableJoins;
|
||||
}
|
||||
|
||||
public void setTableJoins(TableJoin[] tableJoins) {
|
||||
this.tableJoins = tableJoins;
|
||||
}
|
||||
public void setTableJoins(TableJoin[] tableJoins) {
|
||||
this.tableJoins = tableJoins;
|
||||
}
|
||||
|
||||
public void setAllProperties(boolean allProperties) {
|
||||
this.allProperties = allProperties;
|
||||
}
|
||||
|
||||
public boolean isAllProperties() {
|
||||
return allProperties;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class ScalarTypeInteger extends ScalarTypeBase<Integer> {
|
||||
if (value == null) {
|
||||
b.setNull(Types.INTEGER);
|
||||
} else {
|
||||
b.setInt(value.intValue());
|
||||
b.setInt(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class ScalarTypeInteger extends ScalarTypeBase<Integer> {
|
||||
if (!dataInput.readBoolean()) {
|
||||
return null;
|
||||
} else {
|
||||
return Integer.valueOf(dataInput.readInt());
|
||||
return dataInput.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import org.joda.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* ScalarType for Joda DateTime. This maps to a JDBC Timestamp.
|
||||
*/
|
||||
|
||||
@@ -23,7 +23,7 @@ public class ScalarTypeJodaLocalDate extends ScalarTypeBaseDate<LocalDate> {
|
||||
|
||||
@Override
|
||||
public LocalDate convertFromDate(Date ts) {
|
||||
return new LocalDate(((java.util.Date) ts).getTime());
|
||||
return new LocalDate(ts.getTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.text.TextException;
|
||||
import com.avaje.ebean.text.json.EJson;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Type which maps Map<String,Object> to various DB types (Clob, Varchar, Blob) in JSON format.
|
||||
*/
|
||||
public abstract class ScalarTypeJsonMap extends ScalarTypeBase<Map> {
|
||||
|
||||
public static class Clob extends ScalarTypeJsonMap {
|
||||
|
||||
public Clob() {
|
||||
super(Types.CLOB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map read(DataReader dataReader) throws SQLException {
|
||||
|
||||
Reader reader = dataReader.getClobReader();
|
||||
if (reader == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Map map = parse(reader);
|
||||
reader.close();
|
||||
return map;
|
||||
} catch (IOException e) {
|
||||
throw new SQLException("Error reading Clob stream from DB", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Varchar extends ScalarTypeJsonMap {
|
||||
|
||||
public Varchar() {
|
||||
super(Types.VARCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Blob extends ScalarTypeJsonMap {
|
||||
public Blob() {
|
||||
super(Types.BLOB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map read(DataReader dataReader) throws SQLException {
|
||||
|
||||
InputStream is = dataReader.getBlobInputStream();
|
||||
if (is == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
InputStreamReader reader = new InputStreamReader(is);
|
||||
Map map = parse(reader);
|
||||
reader.close();
|
||||
return map;
|
||||
} catch (IOException e) {
|
||||
throw new SQLException("Error reading Blob stream from DB", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, Map value) throws SQLException {
|
||||
|
||||
if (value == null) {
|
||||
b.setNull(Types.BLOB);
|
||||
} else {
|
||||
String rawJson = formatValue(value);
|
||||
InputStream stream = new ByteArrayInputStream(rawJson.getBytes(StandardCharsets.UTF_8));
|
||||
b.setBlob(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ScalarTypeJsonMap(int jdbcType) {
|
||||
super(Map.class, false, jdbcType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map is a mutable type. Use the isDirty() method to check for dirty state.
|
||||
*/
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the value should be considered dirty (and included in an update).
|
||||
*/
|
||||
@Override
|
||||
public boolean isDirty(Object value) {
|
||||
return !(value instanceof ModifyAwareOwner) || ((ModifyAwareOwner) value).isMarkedDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map read(DataReader dataReader) throws SQLException {
|
||||
|
||||
String rawJson = dataReader.getString();
|
||||
if (rawJson == null) {
|
||||
return null;
|
||||
}
|
||||
return parse(rawJson);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, Map value) throws SQLException {
|
||||
|
||||
if (value == null) {
|
||||
b.setNull(Types.VARCHAR);
|
||||
} else {
|
||||
String rawJson = formatValue(value);
|
||||
b.setString(rawJson);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map toBeanType(Object value) {
|
||||
return (Map) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(Map v) {
|
||||
try {
|
||||
return EJson.write(v);
|
||||
} catch (IOException e) {
|
||||
throw new TextException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map parse(String value) {
|
||||
try {
|
||||
// return a modify aware map
|
||||
return EJson.parseObject(value, true);
|
||||
} catch (IOException e) {
|
||||
throw new TextException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map parse(Reader reader) {
|
||||
try {
|
||||
// return a modify aware map
|
||||
return EJson.parseObject(reader, true);
|
||||
} catch (IOException e) {
|
||||
throw new TextException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map convertFromMillis(long dateTime) {
|
||||
throw new RuntimeException("Should never be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDateTimeCapable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map readData(DataInput dataInput) throws IOException {
|
||||
if (!dataInput.readBoolean()) {
|
||||
return null;
|
||||
} else {
|
||||
String json = dataInput.readUTF();
|
||||
return parse(json);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeData(DataOutput dataOutput, Map v) throws IOException {
|
||||
if (v == null) {
|
||||
dataOutput.writeBoolean(false);
|
||||
} else {
|
||||
dataOutput.writeBoolean(true);
|
||||
String json = format(v);
|
||||
dataOutput.writeUTF(json);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Map value) throws IOException {
|
||||
// write the field name followed by the Map/JSON Object
|
||||
if (value == null) {
|
||||
ctx.writeNullField(name);
|
||||
} else {
|
||||
ctx.writeFieldName(name);
|
||||
EJson.write(value, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
// at this point the BeanProperty has read the START_OBJECT token
|
||||
// to check for a null value. Pass the START_OBJECT token through to
|
||||
// the EJson parsing so that it knows the first token has been read
|
||||
return EJson.parseObject(ctx, event);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import org.postgresql.util.PGobject;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Support for the Postgres DB types JSON and JSONB.
|
||||
*/
|
||||
public abstract class ScalarTypeJsonMapPostgres extends ScalarTypeJsonMap {
|
||||
|
||||
private static final String POSTGRES_TYPE_JSON = "json";
|
||||
|
||||
private static final String POSTGRES_TYPE_JSONB = "jsonb";
|
||||
|
||||
final String postgresType;
|
||||
|
||||
ScalarTypeJsonMapPostgres(int jdbcType, String postgresType) {
|
||||
super(jdbcType);
|
||||
this.postgresType = postgresType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, Map value) throws SQLException {
|
||||
|
||||
String rawJson = (value == null) ? null : formatValue(value);
|
||||
|
||||
PGobject pgo = new PGobject();
|
||||
pgo.setType(postgresType);
|
||||
pgo.setValue(rawJson);
|
||||
b.setObject(pgo);
|
||||
}
|
||||
|
||||
/**
|
||||
* ScalarType mapping java Map type to Postgres JSON database type.
|
||||
*/
|
||||
public static class JSON extends ScalarTypeJsonMapPostgres {
|
||||
|
||||
public JSON() {
|
||||
super(DbType.JSON, POSTGRES_TYPE_JSON);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ScalarType mapping java Map type to Postgres JSONB database type.
|
||||
*/
|
||||
public static class JSONB extends ScalarTypeJsonMapPostgres {
|
||||
|
||||
public JSONB() {
|
||||
super(DbType.JSONB, POSTGRES_TYPE_JSONB);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.text.TextException;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Type which maps Jackson's JsonNode to various DB types (Clob, Varchar, Blob) in JSON format.
|
||||
*/
|
||||
public abstract class ScalarTypeJsonNode extends ScalarTypeBase<JsonNode> {
|
||||
|
||||
/**
|
||||
* Clob storage based implementation.
|
||||
*/
|
||||
public static class Clob extends ScalarTypeJsonNode {
|
||||
|
||||
public Clob(ObjectMapper objectMapper) {
|
||||
super(objectMapper, Types.CLOB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode read(DataReader dataReader) throws SQLException {
|
||||
|
||||
Reader reader = dataReader.getClobReader();
|
||||
if (reader == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JsonNode tree = parse(reader);
|
||||
reader.close();
|
||||
return tree;
|
||||
} catch (IOException e) {
|
||||
throw new SQLException("Error reading Clob stream from DB", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Varchar storage based implementation.
|
||||
*/
|
||||
public static class Varchar extends ScalarTypeJsonNode {
|
||||
|
||||
public Varchar(ObjectMapper objectMapper) {
|
||||
super(objectMapper, Types.VARCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blob storage based implementation.
|
||||
*/
|
||||
public static class Blob extends ScalarTypeJsonNode {
|
||||
|
||||
public Blob(ObjectMapper objectMapper) {
|
||||
super(objectMapper, Types.BLOB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode read(DataReader dataReader) throws SQLException {
|
||||
|
||||
InputStream is = dataReader.getBlobInputStream();
|
||||
if (is == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
InputStreamReader reader = new InputStreamReader(is);
|
||||
JsonNode tree = parse(reader);
|
||||
reader.close();
|
||||
return tree;
|
||||
} catch (IOException e) {
|
||||
throw new SQLException("Error reading Blob stream from DB", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind dataBind, JsonNode value) throws SQLException {
|
||||
|
||||
if (value == null) {
|
||||
dataBind.setNull(Types.BLOB);
|
||||
} else {
|
||||
String rawJson = formatValue(value);
|
||||
InputStream stream = new ByteArrayInputStream(rawJson.getBytes(StandardCharsets.UTF_8));
|
||||
dataBind.setBlob(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Jackson's ObjectMapper used to read / write JsonNode
|
||||
*/
|
||||
final ObjectMapper objectMapper;
|
||||
|
||||
public ScalarTypeJsonNode(ObjectMapper objectMapper, int jdbcType) {
|
||||
super(JsonNode.class, false, jdbcType);
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map is a mutable type. Use the isDirty() method to check for dirty state.
|
||||
*/
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the value should be considered dirty (and included in an update).
|
||||
*/
|
||||
@Override
|
||||
public boolean isDirty(Object value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode read(DataReader dataReader) throws SQLException {
|
||||
|
||||
String rawJson = dataReader.getString();
|
||||
if (rawJson == null) {
|
||||
return null;
|
||||
}
|
||||
return parse(rawJson);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind dataBind, JsonNode value) throws SQLException {
|
||||
|
||||
if (value == null) {
|
||||
dataBind.setNull(Types.VARCHAR);
|
||||
} else {
|
||||
String rawJson = formatValue(value);
|
||||
dataBind.setString(rawJson);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode toBeanType(Object value) {
|
||||
return (JsonNode) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(JsonNode jsonNode) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(jsonNode);
|
||||
} catch (IOException e) {
|
||||
throw new TextException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode parse(String value) {
|
||||
try {
|
||||
return objectMapper.readValue(value, JsonNode.class);
|
||||
} catch (IOException e) {
|
||||
throw new TextException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public JsonNode parse(Reader reader) {
|
||||
try {
|
||||
return objectMapper.readValue(reader, JsonNode.class);
|
||||
} catch (IOException e) {
|
||||
throw new TextException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode convertFromMillis(long dateTime) {
|
||||
throw new RuntimeException("Should never be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDateTimeCapable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode readData(DataInput dataInput) throws IOException {
|
||||
if (!dataInput.readBoolean()) {
|
||||
return null;
|
||||
} else {
|
||||
String json = dataInput.readUTF();
|
||||
return parse(json);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeData(DataOutput dataOutput, JsonNode value) throws IOException {
|
||||
if (value == null) {
|
||||
dataOutput.writeBoolean(false);
|
||||
} else {
|
||||
dataOutput.writeBoolean(true);
|
||||
String json = format(value);
|
||||
dataOutput.writeUTF(json);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, JsonNode value) throws IOException {
|
||||
// write the field name followed by the JsonNode object
|
||||
if (value == null) {
|
||||
ctx.writeNullField(name);
|
||||
} else {
|
||||
ctx.writeFieldName(name);
|
||||
objectMapper.writeTree(ctx, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
// at this point the BeanProperty has read the START_OBJECT token
|
||||
// to check for a null value.
|
||||
return objectMapper.readValue(ctx, JsonNode.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.postgresql.util.PGobject;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Support for mapping JsonNode to Postgres DB types JSON and JSONB.
|
||||
*/
|
||||
public abstract class ScalarTypeJsonNodePostgres extends ScalarTypeJsonNode {
|
||||
|
||||
private static final String POSTGRES_TYPE_JSON = "json";
|
||||
|
||||
private static final String POSTGRES_TYPE_JSONB = "jsonb";
|
||||
|
||||
final ObjectMapper objectMapper;
|
||||
|
||||
final String postgresType;
|
||||
|
||||
ScalarTypeJsonNodePostgres(ObjectMapper objectMapper, int jdbcType, String postgresType) {
|
||||
super(objectMapper, jdbcType);
|
||||
this.objectMapper = objectMapper;
|
||||
this.postgresType = postgresType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind dataBind, JsonNode value) throws SQLException {
|
||||
|
||||
String rawJson = (value == null) ? null : formatValue(value);
|
||||
|
||||
PGobject pgo = new PGobject();
|
||||
pgo.setType(postgresType);
|
||||
pgo.setValue(rawJson);
|
||||
dataBind.setObject(pgo);
|
||||
}
|
||||
|
||||
/**
|
||||
* ScalarType mapping JsonNode to Postgres JSON database type.
|
||||
*/
|
||||
public static class JSON extends ScalarTypeJsonNodePostgres {
|
||||
|
||||
public JSON(ObjectMapper objectMapper) {
|
||||
super(objectMapper, DbType.JSON, POSTGRES_TYPE_JSON);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ScalarType mapping JsonNode to Postgres JSONB database type.
|
||||
*/
|
||||
public static class JSONB extends ScalarTypeJsonNodePostgres {
|
||||
|
||||
public JSONB(ObjectMapper objectMapper) {
|
||||
super(objectMapper, DbType.JSONB, POSTGRES_TYPE_JSONB);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,8 +44,8 @@ public class ScalarTypeLocalTime extends ScalarTypeBase<LocalTime> {
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
if (value instanceof Time) return value;
|
||||
return Time.valueOf((LocalTime)value);
|
||||
if (value instanceof Time) return value;
|
||||
return Time.valueOf((LocalTime) value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user