Compare commits

..
Author SHA1 Message Date
Rob Bygrave e2731a99be [maven-release-plugin] prepare release ebean-9.4.1 2016-12-06 23:44:26 +13:00
Rob Bygrave 7d56df3b23 Bump pom to 9.4.1-SNAPSHOT 2016-12-06 23:43:37 +13:00
Rob Bygrave bebef48332 Update test ebean.properties 2016-12-03 22:03:55 +13:00
Rob Bygrave f66ea12fbf #912 - Refactor - move platform specfic code into subpackages 2016-12-03 15:39:24 +13:00
Rob Bygrave b08f1580f9 #910 - SQL Server update - Add ANSI based row limiter (2012+) and make as default platform 2016-12-03 15:10:11 +13:00
Rob Bygrave 707912f7ad No effective change - add some wait into history test (TestHistoryInsert) 2016-12-03 13:55:45 +13:00
Rob Bygrave 5ce31b16d4 #910 - SQL Server update - refactor rename platform to SqlServerPlatform 2016-12-03 13:30:17 +13:00
Rob Bygrave a5945b1d5d #911 - SQL Server - remove old MsSqlServer2000Platform (expecting users migrated to SQL Server 2005+) 2016-12-03 13:24:52 +13:00
Rob Bygrave b8577ae6d0 #910 - SQL Server update - tidy whitespace for MsSqlServer2005SqlLimiter 2016-12-03 13:19:15 +13:00
Rob Bygrave 14dedb7b9a #910 - SQL Server update 2016-12-03 13:18:33 +13:00
Rob Bygrave 2dbd543127 #909 - @Lob with @Size ... produces incorrect DDL for Postgres 2016-12-03 08:42:46 +13:00
Rob Bygrave cc989af1c6 #908 - Remove support for Immutable Compound Values 2016-12-02 22:49:00 +13:00
Rob Bygrave 0aad285f35 #907 - Remove Model.Finder ... migrate to Finder 2016-12-02 21:47:30 +13:00
Rob Bygrave a3754e31f2 #906 - Add NamingConvention Support for JoinColumn (OneToMany, ManyToOne) - was PR #887 2016-12-02 21:21:19 +13:00
Rob Bygrave 1dd0f3f609 [maven-release-plugin] prepare for next development iteration 2016-12-01 21:04:18 +13:00
140 changed files with 446 additions and 3675 deletions
+2 -2
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean</artifactId>
<version>9.3.1</version>
<version>9.4.1</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -21,7 +21,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-9.3.1</tag>
<tag>ebean-9.4.1</tag>
</scm>
<dependencies>
+5 -618
View File
@@ -1,16 +1,8 @@
package com.avaje.ebean;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.util.ClassUtil;
import org.jetbrains.annotations.Nullable;
import javax.persistence.MappedSuperclass;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* A MappedSuperclass base class that provides convenience methods for inserting, updating and
@@ -19,7 +11,7 @@ import java.util.function.Predicate;
* By having your entity beans extend this it provides a 'Active Record' style programming model for
* Ebean users.
* <p>
* Note that there is a avaje-ebeanorm-mocker project that enables you to use Mockito or similar
* Note that there is a ebean-mocker project that enables you to use Mockito or similar
* tools to still mock out the underlying 'default EbeanServer' for testing purposes.
* <p>
* You may choose not use this Model mapped superclass if you don't like the 'Active Record' style
@@ -32,7 +24,7 @@ import java.util.function.Predicate;
* that same instance also used to support the Model and Finder active record style.
* <p>
* If you choose to use the Model mapped superclass you will probably also chose to additionally add
* a {@link Find} as a public static field to complete the active record pattern and provide a
* a {@link Finder} as a public static field to complete the active record pattern and provide a
* relatively nice clean way to write queries.
* <p>
* <h3>Typical common @MappedSuperclass</h3>
@@ -48,9 +40,9 @@ import java.util.function.Predicate;
*
* @Version Long version;
*
* @CreatedTimestamp Timestamp whenCreated;
* @WhenCreated Timestamp whenCreated;
*
* @UpdatedTimestamp Timestamp whenUpdated;
* @WhenUpdated Timestamp whenUpdated;
*
* ...
*
@@ -61,15 +53,9 @@ import java.util.function.Predicate;
*
* // Extend the mappedSuperclass
*
* @Entity @Table(name="oto_account")
* @Entity @Table(name="o_account")
* public class Customer extends BaseModel {
*
* // Add a static Find
* // ... with Long being the type of our @Id property.
* // ... Note the {} at the end as Find is an abstract class.
*
* public static final Find<Long,Account> find = new Find<Long,Account>(){};
*
* String name;
* ...
* }
@@ -87,25 +73,6 @@ import java.util.function.Predicate;
* customer.save();
*
* }</pre>
* <p>
* <h3>Find byId</h3>
* <pre>{@code
*
* // find byId
* Customer customer = Customer.find.byId(42);
*
* }</pre>
* <p>
* <h3>Find where</h3>
* <pre>{@code
*
* // find where ...
* List<Customer> customers =
* Customer.find
* .where().gt("startDate", lastMonth)
* .findList();
*
* }</pre>
*/
@MappedSuperclass
public abstract class Model {
@@ -305,584 +272,4 @@ public abstract class Model {
db().refresh(this);
}
/**
* A concrete implementation of Find.
* <p>
* It should be preferred to use {@link Find} instead of Finder as that can use reflection to determine the class
* literal type of the entity bean.
* </p>
*
* @param <I> type of the Id property
* @param <T> type of the entity bean
*/
public static class Finder<I, T> extends Find<I, T> {
/**
* Create with the type of the entity bean.
* <p>
* <pre>{@code
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final Finder<Long,Customer> find = new Finder<Long,Customer>(Customer.class);
* ...
*
* }</pre>
* <p>
* <p/>
* The preferred approach is to instead use <code>Find</code> as below. This approach is more DRY in that it does
* not require the class literal Customer.class to be passed into the constructor.
* <p>
* <pre>{@code
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
* ...
*
* }</pre>
*/
public Finder(Class<T> type) {
super(null, type);
}
/**
* Create with the type of the entity bean and specific server name.
*/
public Finder(String serverName, Class<T> type) {
super(serverName, type);
}
}
/**
* Helper object for performing queries.
* <p>
* <p>
* Typically a Find instance is defined as a public static field on an entity bean class to provide a
* nice way to write queries.
* <p>
* <h3>Example use:</h3>
* <p>
* <pre>{@code
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
*
* ...
*
* }</pre>
* <p/>
* This enables you to write code like:
* <pre>{@code
*
* Customer customer = Customer.find.byId(42L);
*
* List<Customer> customers =
* Customer.find
* .select("name, dateOfBirth")
* .findList();
*
* }</pre>
* <p>
* <h3>Kotlin</h3>
* In Kotlin you would typically create Find as a companion object.
* <pre>{@code
*
* // kotlin
* companion object : Model.Find<Long, Product>() {}
*
* }</pre>
*
* @param <I> The Id type. This is most often a {@link Long} but is also often a {@link UUID} or
* {@link String}.
* @param <T> The entity bean type
*/
public static abstract class Find<I, T> {
/**
* The entity bean type.
*/
private final Class<T> type;
/**
* The name of the EbeanServer, null for the default server.
*/
private final String serverName;
/**
* Creates a finder for entity of type <code>T</code> with ID of type <code>I</code>.
* <p/>
* Typically you create Find as a public static field on each entity bean as the example below.
* <p>
* <p/>
* Note that Find is an abstract class and hence <code>{}</code> is required. This is done so
* that the type (class literal) of the entity bean can be derived from the generics parameter.
* <p>
* <pre>{@code
*
* @Entity
* public class Customer extends BaseModel {
*
* // Note the trailing {} as Find is an abstract class.
* // We do this so that we can derive the type literal Customer.class
* // via reflection
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
* ...
*
* }</pre>
* <p/>
* This enables you to write code like:
* <pre>{@code
*
* Customer customer = Customer.find.byId(42L);
*
* List<Customer> customers =
* Customer.find
* .select("name, email, dateOfBirth")
* .findList();
*
* }</pre>
* <p>
* <h3>Kotlin</h3>
* In Kotlin you would typically create it as a companion object.
* <p>
* <pre>{@code
*
* // kotlin
* companion object : Model.Find<Long, Product>() {}
*
* }</pre>
*/
@SuppressWarnings("unchecked")
public Find() {
this.serverName = null;
this.type = (Class<T>) ClassUtil.getSecondArgumentType(getClass());
}
/**
* Construct passing the class literal type of the entity type.
*/
protected Find(String serverName, Class<T> type) {
this.serverName = serverName;
this.type = type;
}
/**
* Return the underlying 'default' EbeanServer.
* <p>
* <p>
* This provides full access to the API such as explicit transaction demarcation etc.
*/
public EbeanServer db() {
return Ebean.getServer(serverName);
}
/**
* Return typically a different EbeanServer to the default.
* <p>
* This is equivalent to {@link Ebean#getServer(String)}
*
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
* returned.
*/
public EbeanServer db(String server) {
return Ebean.getServer(server);
}
/**
* Creates a Finder for the named EbeanServer.
* <p>
* <p>
* Create and return a new Finder for a different server.
*/
public Finder<I, T> on(String server) {
return new Finder<>(server, type);
}
/**
* Delete a bean by Id.
* <p>
* Equivalent to {@link EbeanServer#delete(Class, Object)}
*/
public void deleteById(I id) {
db().delete(type, id);
}
/**
* Retrieves all entities of the given type.
* <p>
* <p>
* This is the same as (synonym for) {@link #findList()}
*/
public List<T> all() {
return findList();
}
/**
* Retrieves an entity by ID.
* <p>
* <p>
* Equivalent to {@link EbeanServer#find(Class, Object)}
*/
@Nullable
public T byId(I id) {
return db().find(type, id);
}
/**
* Creates an entity reference for this ID.
* <p>
* <p>
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
*/
public T ref(I id) {
return db().getReference(type, id);
}
/**
* Creates a filter for sorting and filtering lists of entities locally without going back to
* the database.
* <p>
* Equivalent to {@link EbeanServer#filter(Class)}
*/
public Filter<T> filter() {
return db().filter(type);
}
/**
* Creates a query.
* <p>
* Equivalent to {@link EbeanServer#find(Class)}
*/
public Query<T> query() {
return db().find(type);
}
/**
* Creates a query applying the path properties to set the select and fetch clauses.
* <p>
* Equivalent to {@link Query#apply(FetchPath)}
*/
public Query<T> apply(FetchPath fetchPath) {
return db().find(type).apply(fetchPath);
}
/**
* Returns the next identity value.
*
* @see EbeanServer#nextId(Class)
*/
@SuppressWarnings("unchecked")
public I nextId() {
return (I) db().nextId(type);
}
/**
* Executes a query and returns the results as a list of IDs.
* <p>
* Equivalent to {@link Query#findIds()}
*/
public <A> List<A> findIds() {
return query().findIds();
}
/**
* Execute the query consuming each bean one at a time.
* <p>
* This is generally used to process large queries where unlike findList
* you do not want to hold all the results in memory at once but instead
* process them one at a time (requiring far less memory).
* </p>
* Equivalent to {@link Query#findEach(Consumer)}
*/
public void findEach(Consumer<T> consumer) {
query().findEach(consumer);
}
/**
* Execute the query consuming each bean one at a time.
* <p>
* Equivalent to {@link Query#findEachWhile(Predicate)}
* <p>
* This is similar to #findEach except that you return boolean
* true to continue processing beans and return false to stop
* processing early.
* </p>
* <p>
* This is generally used to process large queries where unlike findList
* you do not want to hold all the results in memory at once but instead
* process them one at a time (requiring far less memory).
* </p>
* Equivalent to {@link Query#findEachWhile(Predicate)}
*/
public void findEachWhile(Predicate<T> consumer) {
query().findEachWhile(consumer);
}
/**
* Retrieves all entities of the given type.
* <p>
* The same as {@link #all()}
* <p>
* Equivalent to {@link Query#findList()}
*/
public List<T> findList() {
return query().findList();
}
/**
* Returns all the entities of the given type as a set.
* <p>
* Equivalent to {@link Query#findSet()}
*/
public Set<T> findSet() {
return query().findSet();
}
/**
* Retrieves all entities of the given type as a map of objects.
* <p>
* Equivalent to {@link Query#findMap()}
*/
public <K> Map<K, T> findMap() {
return query().findMap();
}
/**
* Executes a find row count query in a background thread.
* <p>
* Equivalent to {@link Query#findFutureCount()}
*/
public FutureRowCount<T> findFutureCount() {
return query().findFutureCount();
}
/**
* Deprecated in favor of findFutureCount().
* <p>
* Equivalent to {@link Query#findFutureCount()}
*/
public FutureRowCount<T> findFutureRowCount() {
return query().findFutureCount();
}
/**
* Returns the total number of entities for this type. *
* <p>
* Equivalent to {@link Query#findCount()}
*/
public int findCount() {
return query().findCount();
}
/**
* Deprecated in favor of findCount().
*
* @deprecated
*/
public int findRowCount() {
return query().findCount();
}
/**
* Returns the <code>ExpressionFactory</code> used by this query.
*/
public ExpressionFactory getExpressionFactory() {
return query().getExpressionFactory();
}
/**
* Explicitly sets a comma delimited list of the properties to fetch on the 'main' entity bean,
* to load a partial object.
* <p>
* Equivalent to {@link Query#select(String)}
*/
public Query<T> select(String fetchProperties) {
return query().select(fetchProperties);
}
/**
* Specifies a path to load including all its properties.
* <p>
* Equivalent to {@link Query#fetch(String)}
*/
public Query<T> fetch(String path) {
return query().fetch(path);
}
/**
* Additionally specifies a <code>FetchConfig</code> to specify a 'query join' and/or define the
* lazy loading query.
* <p>
* Equivalent to {@link Query#fetch(String, FetchConfig)}
*/
public Query<T> fetch(String path, FetchConfig joinConfig) {
return query().fetch(path, joinConfig);
}
/**
* Specifies a path to fetch with a specific list properties to include, to load a partial
* object.
* <p>
* Equivalent to {@link Query#fetch(String, String)}
*/
public Query<T> fetch(String path, String fetchProperties) {
return query().fetch(path, fetchProperties);
}
/**
* Additionally specifies a <code>FetchConfig</code> to use a separate query or lazy loading to
* load this path.
* <p>
* Equivalent to {@link Query#fetch(String, String, FetchConfig)}
*/
public Query<T> fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig) {
return query().fetch(assocProperty, fetchProperties, fetchConfig);
}
/**
* Adds expressions to the <code>where</code> clause with the ability to chain on the
* <code>ExpressionList</code>.
* <p>
* Equivalent to {@link Query#where()}
*/
public ExpressionList<T> where() {
return query().where();
}
/**
* Returns the <code>order by</code> clause so that you can append an ascending or descending
* property to the <code>order by</code> clause.
* <p>
* This is exactly the same as {@link #orderBy}.
* <p>
* Equivalent to {@link Query#order()}
*/
public OrderBy<T> order() {
return query().order();
}
/**
* Sets the <code>order by</code> clause, replacing the existing <code>order by</code> clause if
* there is one.
* <p>
* This is exactly the same as {@link #orderBy(String)}.
*/
public Query<T> order(String orderByClause) {
return query().order(orderByClause);
}
/**
* Returns the <code>order by</code> clause so that you can append an ascending or descending
* property to the <code>order by</code> clause.
* <p>
* This is exactly the same as {@link #order}.
* <p>
* Equivalent to {@link Query#orderBy()}
*/
public OrderBy<T> orderBy() {
return query().orderBy();
}
/**
* Set the <code>order by</code> clause replacing the existing <code>order by</code> clause if
* there is one.
* <p>
* This is exactly the same as {@link #order(String)}.
*/
public Query<T> orderBy(String orderByClause) {
return query().orderBy(orderByClause);
}
/**
* Sets the first row to return for this query.
* <p>
* Equivalent to {@link Query#setFirstRow(int)}
*/
public Query<T> setFirstRow(int firstRow) {
return query().setFirstRow(firstRow);
}
/**
* Sets the maximum number of rows to return in the query.
* <p>
* Equivalent to {@link Query#setMaxRows(int)}
*/
public Query<T> setMaxRows(int maxRows) {
return query().setMaxRows(maxRows);
}
/**
* Sets the ID value to query.
* <p>
* <p>
* Use this to perform a find byId query but with additional control over the query such as
* using select and fetch to control what parts of the object graph are returned.
* <p>
* Equivalent to {@link Query#setId(Object)}
*/
public Query<T> setId(Object id) {
return query().setId(id);
}
/**
* Create and return a new query based on the <code>RawSql</code>.
* <p>
* Equivalent to {@link Query#setRawSql(RawSql)}
*/
public Query<T> setRawSql(RawSql rawSql) {
return query().setRawSql(rawSql);
}
/**
* Create a query with explicit 'AutoTune' use.
*/
public Query<T> setAutoTune(boolean autoTune) {
return query().setAutoTune(autoTune);
}
/**
* Create a query with the select with "for update" specified.
* <p>
* <p>
* This will typically create row level database locks on the selected rows.
*/
public Query<T> setForUpdate(boolean forUpdate) {
return query().setForUpdate(forUpdate);
}
/**
* Create a query specifying whether the returned beans will be read-only.
*/
public Query<T> setReadOnly(boolean readOnly) {
return query().setReadOnly(readOnly);
}
/**
* Create a query specifying if the beans should be loaded into the L2 cache.
*/
public Query<T> setLoadBeanCache(boolean loadBeanCache) {
return query().setLoadBeanCache(loadBeanCache);
}
/**
* Create a query specifying if the L2 bean cache should be used.
*/
public Query<T> setUseCache(boolean useBeanCache) {
return query().setUseCache(useBeanCache);
}
/**
* Create a query specifying if the L2 query cache should be used.
*/
public Query<T> setUseQueryCache(boolean useQueryCache) {
return query().setUseQueryCache(useQueryCache);
}
}
}
@@ -1,42 +0,0 @@
package com.avaje.ebean.config;
/**
* API from creating and getting property values from an Immutable Compound
* Value Object.
* <p>
* A Compound Value object should contain multiple properties that are stored
* separately. If you only have a single scalar value you should instead look to
* use {@link ScalarTypeConverter}.
* </p>
* <p>
* For each property in the compound type you need to implement the
* {@link CompoundTypeProperty} interface. These must be returned from
* {@link #getProperties()} in the same order that the properties appear in the
* constructor.
* </p>
* <p>
* If your compound type is mutable then you should look to use the JPA Embedded
* annotation instead of implementing this interface.
* </p>
* <p>
* When using classpath search Ebean will detect and automatically register any
* implementations of this interface (along with detecting the entity classes
* etc).
* </p>
*
* @param <V> The type of the Value Object
* @author rbygrave
* @see ScalarTypeConverter
*/
public interface CompoundType<V> {
/**
* Create an instance of the compound type given its property values.
*/
V create(Object[] propertyValues);
/**
* Return the properties in the order they appear in the constructor.
*/
CompoundTypeProperty<V, ?>[] getProperties();
}
@@ -1,45 +0,0 @@
package com.avaje.ebean.config;
/**
* Represents a Property of a Compound Value Object.
* <p>
* For each property in a {@link CompoundType} you need an implementation of
* this CompoundTypeProperty interface.
* </p>
*
* @param <V> The type of the Compound value object
* @param <P> The type of the property
* @author rbygrave
* @see CompoundType
* @see ScalarTypeConverter
*/
public interface CompoundTypeProperty<V, P> {
/**
* The name of this property.
*/
String getName();
/**
* Return the property value from the containing compound value object.
*
* @param valueObject the compound value object
* @return the property value.
*/
P getValue(V valueObject);
/**
* This should <b>ONLY</b> be used when the persistence type is different from
* the logical type returned. It most cases just return 0 and Ebean will
* persist the logical type.
* <p>
* Typically this should be used when the logical type is long but the
* persistence type is java.sql.Timestamp. In this case return
* java.sql.Types.TIMESTAMP (rather than 0).
* </p>
*
* @return Return the java.sql.Type that you want to use to persist this
* property or 0 and Ebean will use the logical type.
*/
int getDbType();
}
@@ -41,4 +41,11 @@ public class MatchingNamingConvention extends AbstractNamingConvention {
public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
return dbColumnName;
}
@Override
public String getForeignKey(String prefix, String fkProperty) {
// add fkProperty as init caps
return prefix + fkProperty.substring(0, 1).toUpperCase() + fkProperty.substring(1);
}
}
@@ -100,6 +100,15 @@ public interface NamingConvention {
*/
boolean isUseForeignKeyPrefix();
/**
* Return the foreign key column given the local and foreign properties.
*
* @param prefix the local column used to prefix the fk column
* @param fkProperty the property name of the foreign key
* @return the foreign key column
*/
String getForeignKey(String prefix, String fkProperty);
/**
* Load setting from properties.
*/
@@ -100,6 +100,11 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
this.digitsCompressed = digitsCompressed;
}
@Override
public String getForeignKey(String prefix, String fkProperty) {
return prefix + "_" + toUnderscoreFromCamel(fkProperty);
}
/**
* Convert and return the string to underscore from camel case.
*/
@@ -1,49 +0,0 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.PersistBatch;
/**
* Microsoft SQL Server 2000 specific platform.
* <p>
* <ul>
* <li>supportsGetGeneratedKeys = false</li>
* <li>Use select @@IDENTITY to return the generated Id instead</li>
* <li>Uses LIMIT OFFSET clause</li>
* <li>Uses [ & ] for quoted identifiers</li>
* </ul>
* </p>
*/
public class MsSqlServer2000Platform extends DatabasePlatform {
public MsSqlServer2000Platform() {
super();
this.name = "mssqlserver2000";
this.persistBatchOnCascade = PersistBatch.NONE;
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
this.dbIdentity.setSupportsIdentity(true);
this.openQuote = "[";
this.closeQuote = "]";
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
dbTypeMap.put(DbType.BLOB, new DbPlatformType("image"));
dbTypeMap.put(DbType.CLOB, new DbPlatformType("text"));
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image"));
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text"));
dbTypeMap.put(DbType.DATE, new DbPlatformType("datetime"));
dbTypeMap.put(DbType.TIME, new DbPlatformType("datetime"));
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime"));
}
}
@@ -1,6 +1,10 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.db2;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.PlatformIdGenerator;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DB2Ddl;
import javax.sql.DataSource;
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.db2;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.dbplatform.SequenceIdGenerator;
import javax.sql.DataSource;
@@ -1,4 +1,8 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.db2;
import com.avaje.ebean.config.dbplatform.SqlLimitRequest;
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
import com.avaje.ebean.config.dbplatform.SqlLimiter;
public class Db2SqlLimiter implements SqlLimiter {
@@ -1,4 +1,7 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.h2;
import com.avaje.ebean.config.dbplatform.AbstractDbEncrypt;
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
/**
* H2 encryption support via encrypt decrypt function.
@@ -1,4 +1,6 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.h2;
import com.avaje.ebean.config.dbplatform.DbViewHistorySupport;
/**
* Runtime support for @History with H2.
@@ -1,4 +1,4 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.h2;
import org.h2.api.Trigger;
import org.slf4j.Logger;
@@ -1,6 +1,11 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.h2;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.config.dbplatform.PlatformIdGenerator;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
import javax.sql.DataSource;
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.h2;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.dbplatform.SequenceIdGenerator;
import javax.sql.DataSource;
@@ -1,6 +1,13 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.hsqldb;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.config.dbplatform.PlatformIdGenerator;
import com.avaje.ebean.config.dbplatform.h2.H2DbEncrypt;
import com.avaje.ebean.config.dbplatform.h2.H2SequenceIdGenerator;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.HsqldbDdl;
import javax.sql.DataSource;
@@ -1,4 +1,6 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.mysql;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
/**
* Support for blob, mediumblob or longblob selection based on the deployment
@@ -1,4 +1,6 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.mysql;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
/**
* Support for text, mediumtext or longtext selection based on the deployment
@@ -1,4 +1,7 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.mysql;
import com.avaje.ebean.config.dbplatform.AbstractDbEncrypt;
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
/**
* MySql aes_encrypt aes_decrypt based encryption support.
@@ -1,4 +1,6 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.mysql;
import com.avaje.ebean.config.dbplatform.DbViewHistorySupport;
/**
* Runtime support for @History with MySql.
@@ -1,6 +1,11 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.mysql;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.config.dbplatform.PlatformIdGenerator;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MySqlDdl;
import javax.sql.DataSource;
@@ -1,4 +1,7 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.oracle;
import com.avaje.ebean.config.dbplatform.AbstractDbEncrypt;
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
/**
* Oracle encryption support.
@@ -1,4 +1,6 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.oracle;
import com.avaje.ebean.config.dbplatform.DbStandardHistorySupport;
/**
* Oracle Total recall based history support.
@@ -1,6 +1,13 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.oracle;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.dbplatform.BasicSqlAnsiLimiter;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.config.dbplatform.PlatformIdGenerator;
import com.avaje.ebean.config.dbplatform.RownumSqlLimiter;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.Oracle10Ddl;
import javax.sql.DataSource;
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.oracle;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.dbplatform.SequenceIdGenerator;
import javax.sql.DataSource;
@@ -1,4 +1,6 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.postgres;
import com.avaje.ebean.config.dbplatform.IdType;
/**
* Postgres v8.3 specific platform.
@@ -1,4 +1,7 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.postgres;
import com.avaje.ebean.config.dbplatform.AbstractDbEncrypt;
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
/**
* Postgres pgp_sym_encrypt pgp_sym_decrypt based encryption support.
@@ -1,4 +1,6 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.postgres;
import com.avaje.ebean.config.dbplatform.DbViewHistorySupport;
/**
* Postgres support for history features.
@@ -1,7 +1,12 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.postgres;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.config.dbplatform.PlatformIdGenerator;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PostgresDdl;
@@ -40,7 +45,7 @@ public class PostgresPlatform extends DatabasePlatform {
this.openQuote = "\"";
this.closeQuote = "\"";
DbPlatformType dbTypeText = new DbPlatformType("text");
DbPlatformType dbTypeText = new DbPlatformType("text", false);
DbPlatformType dbBytea = new DbPlatformType("bytea", false);
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.postgres;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.dbplatform.SequenceIdGenerator;
import javax.sql.DataSource;
@@ -1,4 +1,8 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.sqlanywhere;
import com.avaje.ebean.config.dbplatform.SqlLimitRequest;
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
import com.avaje.ebean.config.dbplatform.SqlLimiter;
/**
* Use top xx and start at xx to limit sql results.
@@ -1,4 +1,9 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.sqlanywhere;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.IdType;
/**
* Sybase SQL Anywhere specific platform.
@@ -1,5 +1,9 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.sqlite;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.SQLiteDdl;
import java.sql.Types;
@@ -0,0 +1,11 @@
package com.avaje.ebean.config.dbplatform.sqlserver;
/**
* SQL Server platform using the older ROW_NUMBER() mechanism.
*/
public class SqlServer2005Platform extends SqlServerPlatform {
public SqlServer2005Platform() {
this.sqlLimiter = new SqlServer2005SqlLimiter();
}
}
@@ -1,20 +1,24 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.sqlserver;
import com.avaje.ebean.config.dbplatform.SqlLimitRequest;
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
import com.avaje.ebean.config.dbplatform.SqlLimiter;
/**
* Use top and row_number() function to limit sql results.
*/
public class MsSqlServer2005SqlLimiter implements SqlLimiter {
public class SqlServer2005SqlLimiter implements SqlLimiter {
final String rowNumberWindowAlias;
/**
* Specify the name of the rowNumberWindowAlias.
*/
public MsSqlServer2005SqlLimiter(String rowNumberWindowAlias) {
public SqlServer2005SqlLimiter(String rowNumberWindowAlias) {
this.rowNumberWindowAlias = rowNumberWindowAlias;
}
public MsSqlServer2005SqlLimiter() {
public SqlServer2005SqlLimiter() {
this("as limitresult");
}
@@ -31,11 +35,11 @@ public class MsSqlServer2005SqlLimiter implements SqlLimiter {
if (firstRow < 1) {
// just use top n
sb.append(" select ");
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(" top ").append(lastRow).append(" ");
sb.append("top ").append(lastRow).append(" ");
sb.append(request.getDbSql());
return new SqlLimitResponse(sb.toString(), false);
}
@@ -0,0 +1,51 @@
package com.avaje.ebean.config.dbplatform.sqlserver;
import com.avaje.ebean.config.dbplatform.SqlLimitRequest;
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
import com.avaje.ebean.config.dbplatform.SqlLimiter;
/**
* Use ANSI offset rows syntax or top n.
*/
public class SqlServer2012SqlLimiter implements SqlLimiter {
public SqlServer2012SqlLimiter() {
}
public SqlLimitResponse limit(SqlLimitRequest request) {
String dbSql = request.getDbSql();
StringBuilder sb = new StringBuilder(50 + dbSql.length());
int firstRow = request.getFirstRow();
int maxRows = request.getMaxRows();
if (firstRow < 1) {
// just use top n
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append("top ").append(maxRows).append(" ");
sb.append(dbSql);
return new SqlLimitResponse(sb.toString(), false);
}
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(dbSql);
if (firstRow > 0) {
sb.append(" ").append("offset");
sb.append(" ").append(firstRow).append(" rows");
}
if (maxRows > 0) {
sb.append(" fetch next ").append(maxRows).append(" rows only");
}
String sql = sb.toString();
return new SqlLimitResponse(sql, false);
}
}
@@ -0,0 +1,26 @@
package com.avaje.ebean.config.dbplatform.sqlserver;
import com.avaje.ebean.config.dbplatform.BasicSqlLimiter;
/**
* SQL Server 2012 style limiter for raw sql.
*/
public class SqlServerBasicSqlLimiter implements BasicSqlLimiter {
@Override
public String limit(String dbSql, int firstRow, int maxRows) {
StringBuilder sb = new StringBuilder(50 + dbSql.length());
sb.append(dbSql);
if (!dbSql.toLowerCase().contains("order by")) {
sb.append(" order by 1 ");
}
sb.append(" ").append("offset");
sb.append(" ").append(firstRow).append(" rows");
if (maxRows > 0) {
sb.append(" fetch next ").append(maxRows).append(" rows only");
}
return sb.toString();
}
}
@@ -1,29 +1,27 @@
package com.avaje.ebean.config.dbplatform;
package com.avaje.ebean.config.dbplatform.sqlserver;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MsSqlServerDdl;
/**
* Microsoft SQL Server 2005 specific platform.
* <p>
* <ul>
* <li>supportsGetGeneratedKeys = true</li>
* <li>Uses LIMIT OFFSET clause</li>
* <li>Uses [ & ] for quoted identifiers</li>
* </ul>
* </p>
* Microsoft SQL Server platform.
*/
public class MsSqlServer2005Platform extends DatabasePlatform {
public class SqlServerPlatform extends DatabasePlatform {
public MsSqlServer2005Platform() {
public SqlServerPlatform() {
super();
this.name = "mssqlserver2005";
this.name = "sqlserver";
// effectively disable persistBatchOnCascade mode for SQL Server
// due to lack of support for getGeneratedKeys in batch mode
this.persistBatchOnCascade = PersistBatch.NONE;
this.idInExpandedForm = true;
this.selectCountWithAlias = true;
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
this.sqlLimiter = new SqlServer2012SqlLimiter();
this.basicSqlLimiter = new SqlServerBasicSqlLimiter();
this.platformDdl = new MsSqlServerDdl(this);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
@@ -6,14 +6,14 @@ import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.config.DbMigrationConfig;
import com.avaje.ebean.config.Platform;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DB2Platform;
import com.avaje.ebean.config.dbplatform.db2.DB2Platform;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
import com.avaje.ebean.config.dbplatform.OraclePlatform;
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
import com.avaje.ebean.config.dbplatform.SQLitePlatform;
import com.avaje.ebean.config.dbplatform.h2.H2Platform;
import com.avaje.ebean.config.dbplatform.sqlserver.SqlServerPlatform;
import com.avaje.ebean.config.dbplatform.mysql.MySqlPlatform;
import com.avaje.ebean.config.dbplatform.oracle.OraclePlatform;
import com.avaje.ebean.config.dbplatform.postgres.PostgresPlatform;
import com.avaje.ebean.config.dbplatform.sqlite.SQLitePlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.migration.Migration;
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
@@ -526,7 +526,7 @@ public class DbMigration {
case ORACLE:
return new OraclePlatform();
case SQLSERVER:
return new MsSqlServer2005Platform();
return new SqlServerPlatform();
case DB2:
return new DB2Platform();
case SQLITE:
@@ -1,6 +1,6 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.H2HistoryTrigger;
import com.avaje.ebean.config.dbplatform.h2.H2HistoryTrigger;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.model.MTable;
@@ -9,7 +9,6 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.IndexDefinition;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
@@ -134,16 +133,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
}
}
@Override
public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) {
visitScalar(p);
}
@Override
public void visitCompound(BeanPropertyCompound p) {
// do nothing
}
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
@@ -3,7 +3,6 @@ package com.avaje.ebean.dbmigration.model.visitor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* Used to help mark PropertyVisitor methods that need to be implemented
@@ -44,16 +43,4 @@ public abstract class BaseTablePropertyVisitor implements BeanPropertyVisitor {
*/
public abstract void visitScalar(BeanProperty p);
/**
* Not required in that the scalar properties map to the columns.
*/
public void visitCompound(BeanPropertyCompound p) {
}
/**
* Override this method for scalar property inside a Immutable Compound Value object.
*/
public abstract void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p);
}
@@ -3,7 +3,6 @@ package com.avaje.ebean.dbmigration.model.visitor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* Used to visit a BeanProperty given the type of bean property it is.
@@ -45,14 +44,4 @@ public interface BeanPropertyVisitor {
*/
void visitScalar(BeanProperty p);
/**
* Visit a compound value object.
*/
void visitCompound(BeanPropertyCompound p);
/**
* Visit the scalar value inside a compound value object.
*/
void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p);
}
@@ -5,7 +5,6 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.InheritInfoVisitor;
@@ -103,16 +102,6 @@ public class VisitAllUsing {
pv.visitOneImported(assocOne);
}
} else if (p instanceof BeanPropertyCompound) {
// compound type
BeanPropertyCompound compound = (BeanPropertyCompound) p;
pv.visitCompound(compound);
BeanProperty[] properties = compound.getScalarProperties();
for (BeanProperty property : properties) {
pv.visitCompoundScalar(compound, property);
}
} else {
// simple scalar type
pv.visitScalar(p);
@@ -1,18 +1,17 @@
package com.avaje.ebeaninternal.server.core;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DB2Platform;
import com.avaje.ebean.config.dbplatform.db2.DB2Platform;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.HsqldbPlatform;
import com.avaje.ebean.config.dbplatform.MsSqlServer2000Platform;
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
import com.avaje.ebean.config.dbplatform.OraclePlatform;
import com.avaje.ebean.config.dbplatform.Postgres8Platform;
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
import com.avaje.ebean.config.dbplatform.SQLitePlatform;
import com.avaje.ebean.config.dbplatform.SqlAnywherePlatform;
import com.avaje.ebean.config.dbplatform.h2.H2Platform;
import com.avaje.ebean.config.dbplatform.hsqldb.HsqldbPlatform;
import com.avaje.ebean.config.dbplatform.sqlserver.SqlServerPlatform;
import com.avaje.ebean.config.dbplatform.mysql.MySqlPlatform;
import com.avaje.ebean.config.dbplatform.oracle.OraclePlatform;
import com.avaje.ebean.config.dbplatform.postgres.Postgres8Platform;
import com.avaje.ebean.config.dbplatform.postgres.PostgresPlatform;
import com.avaje.ebean.config.dbplatform.sqlite.SQLitePlatform;
import com.avaje.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform;
import com.avaje.ebean.dbmigration.DbOffline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -86,13 +85,7 @@ public class DatabasePlatformFactory {
return new OraclePlatform();
}
if (dbName.equals("sqlserver")) {
return new MsSqlServer2005Platform();
}
if (dbName.equals("sqlserver2005")) {
return new MsSqlServer2005Platform();
}
if (dbName.equals("sqlserver2000")) {
return new MsSqlServer2000Platform();
return new SqlServerPlatform();
}
if (dbName.equals("sqlanywhere")) {
return new SqlAnywherePlatform();
@@ -146,11 +139,7 @@ public class DatabasePlatformFactory {
if (dbProductName.contains("oracle")) {
return new OraclePlatform();
} else if (dbProductName.contains("microsoft")) {
if (majorVersion > 8) {
return new MsSqlServer2005Platform();
} else {
return new MsSqlServer2000Platform();
}
return new SqlServerPlatform();
} else if (dbProductName.contains("mysql")) {
return new MySqlPlatform();
} else if (dbProductName.contains("h2")) {
@@ -11,7 +11,7 @@ import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.TenantMode;
import com.avaje.ebean.config.UnderscoreNamingConvention;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.h2.H2Platform;
import com.avaje.ebean.dbmigration.DbOffline;
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
@@ -1,7 +1,6 @@
package com.avaje.ebeaninternal.server.core.bootup;
import com.avaje.ebean.annotation.DocStore;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.IdGenerator;
import com.avaje.ebean.config.ScalarTypeConverter;
import com.avaje.ebean.config.ServerConfig;
@@ -50,9 +49,6 @@ public class BootupClasses implements ClassFilter {
private final List<Class<? extends AttributeConverter<?, ?>>> attributeConverterList = new ArrayList<>();
private final List<Class<? extends CompoundType<?>>> compoundTypeList = new ArrayList<>();
// The following objects are instantiated on first request
// there is always a candidate list, that holds the class and an
// instance list, that holds the instance. Once a class is instantiated
@@ -347,13 +343,6 @@ public class BootupClasses implements ClassFilter {
return attributeConverterList;
}
/**
* Return the list of ScalarConverters found.
*/
public List<Class<? extends CompoundType<?>>> getCompoundTypes() {
return compoundTypeList;
}
@Override
public boolean isMatch(Class<?> cls) {
@@ -402,11 +391,6 @@ public class BootupClasses implements ClassFilter {
interesting = true;
}
if (CompoundType.class.isAssignableFrom(cls)) {
compoundTypeList.add((Class<? extends CompoundType<?>>) cls);
interesting = true;
}
if (IdGenerator.class.isAssignableFrom(cls)) {
idGeneratorCandidates.add((Class<? extends IdGenerator>) cls);
interesting = true;
@@ -343,7 +343,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
* List of the scalar properties excluding id and secondary table properties.
*/
private final BeanProperty[] propertiesBaseScalar;
private final BeanPropertyCompound[] propertiesBaseCompound;
private final BeanProperty[] propertiesTransient;
@@ -474,7 +473,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
this.propertiesTransient = listHelper.getTransients();
this.propertiesNonTransient = listHelper.getNonTransients();
this.propertiesBaseScalar = listHelper.getBaseScalar();
this.propertiesBaseCompound = listHelper.getBaseCompound();
this.propertiesEmbedded = listHelper.getEmbedded();
this.propertiesLocal = listHelper.getLocal();
this.propertiesMutable = listHelper.getMutable();
@@ -2956,16 +2954,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
return propertiesBaseScalar;
}
/**
* Return properties that are immutable compound value objects.
* <p>
* These are compound types but are not enhanced (Embedded are enhanced).
* </p>
*/
public BeanPropertyCompound[] propertiesBaseCompound() {
return propertiesBaseCompound;
}
/**
* Return the properties local to this type for inheritance.
*/
@@ -1,6 +1,7 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.config.EncryptKey;
import com.avaje.ebean.config.NamingConvention;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.cache.SpiCacheManager;
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
@@ -30,6 +31,11 @@ public interface BeanDescriptorMap {
*/
SpiCacheManager getCacheManager();
/**
* Return the naming convention.
*/
NamingConvention getNamingConvention();
/**
* Return the BeanDescriptor for a given class.
*/
@@ -1,175 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.json.EJson;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
import com.avaje.ebeaninternal.server.text.json.ReadJson;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
import com.avaje.ebeaninternal.server.type.CtCompoundPropertyElAdapter;
import com.avaje.ebeaninternal.server.type.CtCompoundType;
import java.io.IOException;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Property mapped to an Immutable Compound Value Object.
* <p>
* An Immutable Compound Value Object is similar to an Embedded bean but it
* doesn't require enhancement and MUST be treated as an Immutable type.
* </p>
*/
public class BeanPropertyCompound extends BeanProperty {
private final CtCompoundType<?> compoundType;
private final BeanProperty[] scalarProperties;
private final LinkedHashMap<String, BeanProperty> propertyMap = new LinkedHashMap<>();
private final LinkedHashMap<String, CtCompoundPropertyElAdapter> nonScalarMap = new LinkedHashMap<>();
/**
* Create the property.
*/
public BeanPropertyCompound(BeanDescriptor<?> descriptor, DeployBeanPropertyCompound deploy) {
super(descriptor, deploy);
this.compoundType = deploy.getCompoundType();
BeanPropertyCompoundRoot root = deploy.getFlatProperties();
this.scalarProperties = root.getScalarProperties();
for (BeanProperty scalarProperty : scalarProperties) {
propertyMap.put(scalarProperty.getName(), scalarProperty);
}
List<CtCompoundProperty> nonScalarPropsList = root.getNonScalarProperties();
for (CtCompoundProperty ctProp : nonScalarPropsList) {
CtCompoundPropertyElAdapter adapter = new CtCompoundPropertyElAdapter(ctProp);
nonScalarMap.put(ctProp.getRelativeName(), adapter);
}
}
@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);
}
// 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();
}
@Override
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
if (!isTransient) {
for (BeanProperty scalarProperty : scalarProperties) {
scalarProperty.appendSelect(ctx, subQuery);
}
}
}
public BeanProperty[] getScalarProperties() {
return scalarProperties;
}
@Override
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
Object v = compoundType.read(ctx.getDataReader());
setValue(bean, v);
return v;
}
/**
* Read the data from the resultSet effectively ignoring it and returning
* null.
*/
@Override
public Object read(DbReadContext ctx) throws SQLException {
return compoundType.read(ctx.getDataReader());
}
@Override
public void loadIgnore(DbReadContext ctx) {
compoundType.loadIgnore(ctx.getDataReader());
}
@Override
public void load(SqlBeanLoad sqlBeanLoad) {
sqlBeanLoad.load(this);
}
@Override
public Object pathGetNested(Object bean) {
return bean;
}
public void jsonWrite(WriteJson ctx, EntityBean bean) throws IOException {
if (!jsonSerialize) {
return;
}
Object value = getValueIntercept(bean);
if (value == null) {
ctx.writeNullField(name);
} else {
ctx.writeFieldName(name);
compoundType.jsonWrite(ctx, value, name);
}
}
@Override
public void jsonRead(ReadJson readJson, EntityBean bean) throws IOException {
if (!jsonDeserialize) {
return;
}
Map<String, Object> map = EJson.parseObject(readJson.getParser());
if (map == null) {
setValue(bean, null);
} else {
Object objValue = compoundType.jsonConvert(map);
setValue(bean, objValue);
}
}
}
@@ -1,80 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.properties.BeanPropertySetter;
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
import java.util.ArrayList;
import java.util.List;
/**
* Represents the root BeanProperty for properties of a compound type.
* <p>
* Holds all the scalar and non-scalar properties of the compound type. The
* scalar properties match to DB columns and the non-scalar ones are here solely
* to support EL expression language for nested compound types.
* </p>
*/
public class BeanPropertyCompoundRoot {
private final BeanPropertySetter setter;
private final String name;
private final String fullBeanName;
private final ArrayList<BeanPropertyCompoundScalar> propList;
private List<CtCompoundProperty> nonScalarProperties;
public BeanPropertyCompoundRoot(DeployBeanProperty deploy) {
this.fullBeanName = deploy.getFullBeanName();
this.name = deploy.getName();
this.setter = deploy.getSetter();
this.propList = new ArrayList<>();
}
public BeanProperty[] getScalarProperties() {
return propList.toArray(new BeanProperty[propList.size()]);
}
public void register(BeanPropertyCompoundScalar prop) {
propList.add(prop);
}
public List<CtCompoundProperty> getNonScalarProperties() {
return nonScalarProperties;
}
public void setNonScalarProperties(List<CtCompoundProperty> nonScalarProperties) {
this.nonScalarProperties = nonScalarProperties;
}
/**
* Set the value of the property without interception or
* PropertyChangeSupport.
*/
public void setRootValue(EntityBean bean, Object value) {
try {
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";
throw new RuntimeException(msg, ex);
}
}
/**
* Set the value of the property.
*/
public void setRootValueIntercept(EntityBean bean, Object value) {
try {
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";
throw new RuntimeException(msg, ex);
}
}
}
@@ -1,81 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
/**
* A BeanProperty owned by a Compound value object that maps to
* a real scalar type.
*/
public class BeanPropertyCompoundScalar extends BeanProperty {
private final BeanPropertyCompoundRoot rootProperty;
private final CtCompoundProperty ctProperty;
public BeanPropertyCompoundScalar(BeanPropertyCompoundRoot rootProperty, DeployBeanProperty scalarDeploy, CtCompoundProperty ctProperty) {
super(scalarDeploy);
this.rootProperty = rootProperty;
this.ctProperty = ctProperty;
}
/**
* Return one of the scalar values from a compound type.
*/
public Object getValueObject(Object compoundValue) {
return ctProperty.getValue(compoundValue);
}
@Override
public Object getValue(EntityBean valueObject) {
return ctProperty.getValue(valueObject);
}
@Override
public void setValue(EntityBean bean, Object value) {
setValueInCompound(bean, value, false);
}
public void setValueInCompound(EntityBean bean, Object value, boolean intercept) {
Object compoundValue = ctProperty.setValue(bean, value);
if (compoundValue != null) {
// we are at the top level and we have a compound value
// that we can set using the root property
if (intercept) {
rootProperty.setRootValueIntercept(bean, compoundValue);
} else {
rootProperty.setRootValue(bean, compoundValue);
}
}
}
/**
* No interception on embedded scalar values inside a CVO.
*/
@Override
public void setValueIntercept(EntityBean bean, Object value) {
setValueInCompound(bean, value, true);
}
/**
* No interception on embedded scalar values inside a CVO.
*/
@Override
public Object getValueIntercept(EntityBean bean) {
return getValue(bean);
}
@Override
public Object pathGetNested(Object bean) {
return pathGet(bean);
}
@Override
public Object pathGet(Object bean) {
return ctProperty.getValue(bean);
}
}
@@ -21,6 +21,8 @@ public class BeanTable {
private static final Logger logger = LoggerFactory.getLogger(BeanTable.class);
private final BeanDescriptorMap owner;
private final Class<?> beanType;
/**
@@ -34,6 +36,7 @@ public class BeanTable {
* Create the BeanTable.
*/
public BeanTable(DeployBeanTable mutable, BeanDescriptorMap owner) {
this.owner = owner;
this.beanType = mutable.getBeanType();
this.baseTable = InternString.intern(mutable.getBaseTable());
this.idProperties = mutable.createIdProperties(owner);
@@ -94,14 +97,13 @@ public class BeanTable {
String lc = prop.getDbColumn();
String fk = lc;
if (foreignKeyPrefix != null) {
fk = foreignKeyPrefix + "_" + fk;
fk = owner.getNamingConvention().getForeignKey(foreignKeyPrefix, fk);
}
if (complexKey) {
// just to copy the column name rather than prefix with the foreignKeyPrefix.
// I think that with complex keys this is the more common approach.
String msg = "On table[" + baseTable + "] foreign key column [" + lc + "]";
logger.debug(msg);
logger.debug("On table[{}] foreign key column [{}]", baseTable, lc);
fk = lc;
}
if (sqlFormulaSelect != null) {
@@ -1,100 +0,0 @@
package com.avaje.ebeaninternal.server.deploy.meta;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompoundRoot;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompoundScalar;
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
import com.avaje.ebeaninternal.server.type.CtCompoundType;
import com.avaje.ebeaninternal.server.type.CtCompoundTypeScalarList;
import com.avaje.ebeaninternal.server.type.ScalarType;
import java.util.Map.Entry;
/**
* Property mapped to a joined bean.
*/
public class DeployBeanPropertyCompound extends DeployBeanProperty {
private final CtCompoundType<?> compoundType;
private DeployBeanEmbedded deployEmbedded;
/**
* Create the property.
*/
public DeployBeanPropertyCompound(DeployBeanDescriptor<?> desc, Class<?> targetType, CtCompoundType<?> compoundType) {
super(desc, targetType, null, null);
this.compoundType = compoundType;
}
public BeanPropertyCompoundRoot getFlatProperties() {
// get a 'flat' list of all the scalar types, their relative property names
// and also set their matching dbColumn
// represents the root property
BeanPropertyCompoundRoot rootProperty = new BeanPropertyCompoundRoot(this);
// Walk the tree of a compound type collecting the
// scalar types and non-scalar properties
CtCompoundTypeScalarList ctMeta = new CtCompoundTypeScalarList();
compoundType.accumulateScalarTypes(null, ctMeta);
// for each of the scalar types inside a compound value object
// build a BeanPropertyCompoundScalar with appropriate deployment
// information.
for (Entry<String, ScalarType<?>> entry : ctMeta.entries()) {
String relativePropertyName = entry.getKey();
ScalarType<?> scalarType = entry.getValue();
CtCompoundProperty ctProp = ctMeta.getCompoundType(relativePropertyName);
String dbColumn = (getName() + "." + relativePropertyName).replace(".", "_");
dbColumn = getDbColumn(relativePropertyName, dbColumn);
DeployBeanProperty deploy = new DeployBeanProperty(null, scalarType.getType(), scalarType, null);
deploy.setScalarType(scalarType);
deploy.setDbColumn(dbColumn);
deploy.setName(relativePropertyName);
deploy.setDbInsertable(true);
deploy.setDbUpdateable(true);
deploy.setDbRead(true);
rootProperty.register(new BeanPropertyCompoundScalar(rootProperty, deploy, ctProp));
}
rootProperty.setNonScalarProperties(ctMeta.getNonScalarProperties());
return rootProperty;
}
private String getDbColumn(String propName, String defaultDbColumn) {
if (deployEmbedded == null) {
return defaultDbColumn;
}
String dbColumn = deployEmbedded.getPropertyColumnMap().get(propName);
return dbColumn == null ? defaultDbColumn : dbColumn;
}
/**
* Return the deploy information specifically for the deployment
* of Embedded beans.
*/
public DeployBeanEmbedded getDeployEmbedded() {
// deployment should be single threaded
if (deployEmbedded == null) {
deployEmbedded = new DeployBeanEmbedded();
}
return deployEmbedded;
}
public CtCompoundType<?> getCompoundType() {
return compoundType;
}
}
@@ -6,7 +6,6 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.BeanPropertySimpleCollection;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
@@ -57,8 +56,6 @@ public class DeployBeanPropertyLists {
private final List<BeanProperty> baseScalar = new ArrayList<>();
private final List<BeanPropertyCompound> baseCompound = new ArrayList<>();
private final List<BeanProperty> transients = new ArrayList<>();
private final List<BeanProperty> nonTransients = new ArrayList<>();
@@ -219,12 +216,8 @@ public class DeployBeanPropertyLists {
} else if (prop.isTenantId()) {
tenant = prop;
}
if (prop instanceof BeanPropertyCompound) {
baseCompound.add((BeanPropertyCompound) prop);
} else {
if (!prop.isAggregation()) {
baseScalar.add(prop);
}
if (!prop.isAggregation()) {
baseScalar.add(prop);
}
}
}
@@ -246,10 +239,6 @@ public class DeployBeanPropertyLists {
return baseScalar.toArray(new BeanProperty[baseScalar.size()]);
}
public BeanPropertyCompound[] getBaseCompound() {
return baseCompound.toArray(new BeanPropertyCompound[baseCompound.size()]);
}
public BeanProperty getId() {
if (ids.size() > 1) {
String msg = "Issue with bean "+desc+". Ebean does not support multiple @Id properties. You need to convert to using an @EmbeddedId."
@@ -440,10 +429,6 @@ public class DeployBeanPropertyLists {
return new BeanPropertyAssocMany(desc, (DeployBeanPropertyAssocMany) deployProp);
}
if (deployProp instanceof DeployBeanPropertyCompound) {
return new BeanPropertyCompound(desc, (DeployBeanPropertyCompound) deployProp);
}
return new BeanProperty(desc, deployProp);
}
}
@@ -156,12 +156,11 @@ public class AnnotationFields extends AnnotationParser {
// determine the JDBC type using Lob/Temporal
// otherwise based on the property Class
Lob lob = get(prop, Lob.class);
Temporal temporal = get(prop, Temporal.class);
if (temporal != null) {
readTemporal(temporal, prop);
} else if (lob != null) {
} else if (get(prop, Lob.class) != null) {
util.setLobType(prop);
}
@@ -275,15 +274,17 @@ public class AnnotationFields extends AnnotationParser {
prop.setNullable(false);
}
// take the max size of all @Size annotations
int maxSize = -1;
for (Size size : getAll(prop, Size.class)) {
if (size.max() < Integer.MAX_VALUE) {
maxSize = Math.max(maxSize, size.max());
if (!prop.isLob()) {
// take the max size of all @Size annotations
int maxSize = -1;
for (Size size : getAll(prop, Size.class)) {
if (size.max() < Integer.MAX_VALUE) {
maxSize = Math.max(maxSize, size.max());
}
}
}
if (maxSize != -1) {
if (maxSize != -1) {
prop.setDbLength(maxSize);
}
}
}
@@ -11,12 +11,9 @@ 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.TypeManager;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -260,33 +257,11 @@ public class DeployCreateProperties {
return new DeployBeanProperty(desc, propertyType, scalarType, null);
}
CtCompoundType<?> compoundType = typeManager.getCompoundType(propertyType);
if (compoundType != null) {
return new DeployBeanPropertyCompound(desc, propertyType, compoundType);
}
if (isTransientField(field)) {
// return with no ScalarType (still support JSON features)
return new DeployBeanProperty(desc, propertyType, null, null);
}
try {
CheckImmutableResponse checkImmutable = typeManager.checkImmutable(propertyType);
if (checkImmutable.isImmutable()) {
if (checkImmutable.isCompoundType()) {
// use reflection to support compound immutable value objects
typeManager.recursiveCreateScalarDataReader(propertyType);
compoundType = typeManager.getCompoundType(propertyType);
if (compoundType != null) {
return new DeployBeanPropertyCompound(desc, propertyType, compoundType);
}
} else {
// use reflection to support simple immutable value objects
scalarType = typeManager.recursiveCreateScalarTypes(propertyType);
return new DeployBeanProperty(desc, propertyType, scalarType, null);
}
}
return new DeployBeanPropertyAssocOne(desc, propertyType);
} catch (Exception e) {
@@ -20,7 +20,6 @@ import com.avaje.ebean.config.TableName;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
import com.avaje.ebeaninternal.server.type.DataEncryptSupport;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.type.ScalarTypeArrayList;
@@ -176,10 +175,6 @@ public class DeployUtil {
// this will be an Enum type...
return;
}
if (property instanceof DeployBeanPropertyCompound) {
// compound properties have a CvoInternalType instead
return;
}
ScalarType<?> scalarType = getScalarType(property);
if (scalarType != null) {
@@ -1,59 +0,0 @@
package com.avaje.ebeaninternal.server.persist.dmlbind;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
/**
* Bindable for a Immutable Compound value object.
*/
public class BindableCompound implements Bindable {
private final BindableProperty[] items;
private final BeanPropertyCompound compound;
public BindableCompound(BeanPropertyCompound embProp, List<BindableProperty> list) {
this.compound = embProp;
this.items = list.toArray(new BindableProperty[list.size()]);
}
public String toString() {
return "BindableCompound " + compound + " items:" + Arrays.toString(items);
}
@Override
public boolean isDraftOnly() {
return false;
}
public void dmlAppend(GenerateDmlRequest request) {
for (BindableProperty item : items) {
item.dmlAppend(request);
}
}
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
if (request.isAddToUpdate(compound)) {
list.add(this);
}
}
public void dmlBind(BindableRequest bindRequest, EntityBean bean) throws SQLException {
// get the compound type value
Object valueObject = compound.getValue(bean);
// bind each of the underlying scalar values for this compound type
for (BindableProperty item : items) {
item.dmlBindObject(bindRequest, valueObject);
}
}
}
@@ -2,10 +2,8 @@ package com.avaje.ebeaninternal.server.persist.dmlbind;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.persist.dml.DmlMode;
import java.util.ArrayList;
import java.util.List;
/**
@@ -28,24 +26,7 @@ public class FactoryBaseProperties {
*/
public void create(List<Bindable> list, BeanDescriptor<?> desc, DmlMode mode, boolean withLobs) {
add(desc.propertiesBaseScalar(), list, mode, withLobs);
BeanPropertyCompound[] compoundProps = desc.propertiesBaseCompound();
for (BeanPropertyCompound compoundProp : compoundProps) {
BeanProperty[] props = compoundProp.getScalarProperties();
List<BindableProperty> newList = new ArrayList<>(props.length);
addCompound(props, newList, mode, withLobs);
BindableCompound compoundBindable = new BindableCompound(compoundProp, newList);
list.add(compoundBindable);
}
}
private void add(BeanProperty[] props, List<Bindable> list, DmlMode mode, boolean withLobs) {
for (BeanProperty prop : props) {
for (BeanProperty prop : desc.propertiesBaseScalar()) {
Bindable item = factoryProperty.create(prop, mode, withLobs);
if (item != null) {
list.add(item);
@@ -53,15 +34,4 @@ public class FactoryBaseProperties {
}
}
private void addCompound(BeanProperty[] props, List<BindableProperty> list, DmlMode mode, boolean withLobs) {
for (BeanProperty prop : props) {
BindableProperty item = (BindableProperty) factoryProperty.create(prop, mode, withLobs);
if (item != null) {
list.add(item);
}
}
}
}
@@ -457,7 +457,6 @@ public class SqlTreeBuilder {
// normal simple properties of the bean
selectProps.add(desc.propertiesBaseScalar());
selectProps.add(desc.propertiesBaseCompound());
selectProps.add(desc.propertiesEmbedded());
BeanPropertyAssocOne<?>[] propertiesOne = desc.propertiesOne();
@@ -1,82 +0,0 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.CompoundTypeProperty;
import java.time.Period;
/**
* Compound type for Period value type.
* <p>
* Persists the Period into 3 separate integer columns for years, months and days.
* </p>
*/
public class CompoundTypePeriod implements CompoundType<Period> {
final CompoundTypeProperty[] properties = new CompoundTypeProperty[3];
public CompoundTypePeriod() {
properties[0] = new CTPeriodYear();
properties[1] = new CTPeriodMonth();
properties[2] = new CTPeriodDay();
}
@Override
public Period create(Object[] propertyValues) {
return Period.of((Integer) propertyValues[0], (Integer) propertyValues[1], (Integer) propertyValues[2]);
}
@Override
@SuppressWarnings("unchecked")
public CompoundTypeProperty<Period, ?>[] getProperties() {
return properties;
}
static class CTPeriodYear implements CompoundTypeProperty<Period, Integer> {
public String getName() {
return "years";
}
public Integer getValue(Period valueObject) {
return valueObject.getYears();
}
public int getDbType() {
return 0;
}
}
static class CTPeriodMonth implements CompoundTypeProperty<Period, Integer> {
public String getName() {
return "months";
}
public Integer getValue(Period valueObject) {
return valueObject.getMonths();
}
public int getDbType() {
return 0;
}
}
static class CTPeriodDay implements CompoundTypeProperty<Period, Integer> {
public String getName() {
return "days";
}
public Integer getValue(Period valueObject) {
return valueObject.getDays();
}
public int getDbType() {
return 0;
}
}
}
@@ -1,80 +0,0 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.config.CompoundTypeProperty;
/**
* Wraps a CompoundTypeProperty with it's type and parent for nested compound
* types.
*/
public class CtCompoundProperty {
private final String relativeName;
private final CtCompoundProperty parent;
private final CtCompoundType<?> compoundType;
@SuppressWarnings({"rawtypes"})
private final CompoundTypeProperty property;
public CtCompoundProperty(String relativeName, CtCompoundProperty parent, CtCompoundType<?> ctType,
CompoundTypeProperty<?, ?> 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;
}
if (parent != null) {
valueObject = parent.getValue(valueObject);
}
return property.getValue(valueObject);
}
/**
* 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;
}
}
}
@@ -1,153 +0,0 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.StringParser;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
/**
* Adapter for CtCompoundProperty to ElPropertyValue.
* <p>
* This is used for non-scalar properties of a Compound Value Object. These only
* occur in nested compound types.
* </p>
*
* @author rbygrave
*/
public class CtCompoundPropertyElAdapter implements ElPropertyValue {
private final CtCompoundProperty prop;
private int deployOrder;
public CtCompoundPropertyElAdapter(CtCompoundProperty prop) {
this.prop = prop;
}
public void setDeployOrder(int deployOrder) {
this.deployOrder = deployOrder;
}
@Override
public boolean isAggregation() {
return false;
}
@Override
public Object convert(Object value) {
return value;
}
@Override
public Object pathGetNested(Object bean) {
return bean;
}
@Override
public Object pathGet(Object bean) {
return prop.getValue(bean);
}
@Override
public void pathSet(Object bean, Object value) {
prop.setValue(bean, value);
}
public String getAssocIdExpression(String prefix, String operator) {
throw new RuntimeException("Not Supported or Expected");
}
@Override
public String getAssocIsEmpty(SpiExpressionRequest request, String path) {
throw new RuntimeException("Not Supported or Expected");
}
public Object[] getAssocIdValues(EntityBean bean) {
throw new RuntimeException("Not Supported or Expected");
}
public String getAssocIdInExpr(String prefix) {
throw new RuntimeException("Not Supported or Expected");
}
public String getAssocIdInValueExpr(int size) {
throw new RuntimeException("Not Supported or Expected");
}
public BeanProperty getBeanProperty() {
return null;
}
public StringParser getStringParser() {
return null;
}
public boolean isDbEncrypted() {
return false;
}
public boolean isLocalEncrypted() {
return false;
}
@Override
public boolean isAssocMany() {
return false;
}
@Override
public boolean isAssocId() {
return false;
}
public boolean isAssocProperty() {
return false;
}
public boolean isDateTimeCapable() {
return false;
}
public int getJdbcType() {
return 0;
}
public Object parseDateTime(long systemTimeMillis) {
throw new RuntimeException("Not Supported or Expected");
}
@Override
public boolean containsFormulaWithJoin() {
return false;
}
public boolean containsMany() {
return false;
}
public boolean containsManySince(String sinceProperty) {
return containsMany();
}
public String getDbColumn() {
return null;
}
public String getElPlaceholder(boolean encrypted) {
return null;
}
public String getElPrefix() {
return null;
}
public String getName() {
return prop.getPropertyName();
}
public String getElName() {
return prop.getPropertyName();
}
}
@@ -1,201 +0,0 @@
package com.avaje.ebeaninternal.server.type;
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".
*/
public final class CtCompoundType<V> implements ScalarDataReader<V> {
private final Class<V> cvoClass;
private final CompoundType<V> cvoType;
private final ScalarDataReader<Object>[] propReaders;
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;
}
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;
}
// 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);
}
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);
}
public void loadIgnore(DataReader dataReader) {
for (ScalarDataReader<Object> propReader : propReaders) {
propReader.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);
}
}
/**
* 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;
}
}
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);
ctx.endAssocOne();
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void jsonWriteProps(WriteJson ctx, Object valueObject) throws IOException {
ctx.gen().writeStartObject();
for (int i = 0; i < properties.length; i++) {
String propName = properties[i].getName();
Object value = properties[i].getValue((V) valueObject);
if (propReaders[i] instanceof CtCompoundType<?>) {
ctx.writeFieldName(propName);
((CtCompoundType) propReaders[i]).jsonWrite(ctx, value, propName);
} else {
ctx.writeFieldName(propName);
((ScalarType) propReaders[i]).jsonWrite(ctx.gen(), value);
}
}
ctx.gen().writeEndObject();
}
}
@@ -1,67 +0,0 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.config.CompoundTypeProperty;
import com.avaje.ebeaninternal.server.query.SplitName;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
/**
* Used to build a flat list of all the scalar types nested in a compound type.
*/
public final class CtCompoundTypeScalarList {
private final LinkedHashMap<String, ScalarType<?>> scalarProps = new LinkedHashMap<>();
private final LinkedHashMap<String, CtCompoundProperty> compoundProperties = new LinkedHashMap<>();
/**
* Return the list of non-scalar properties. These occur when compound types are nested.
*/
public List<CtCompoundProperty> getNonScalarProperties() {
List<CtCompoundProperty> nonScalarProps = new ArrayList<>();
for (String propKey : compoundProperties.keySet()) {
if (!scalarProps.containsKey(propKey)) {
nonScalarProps.add(compoundProperties.get(propKey));
}
}
return nonScalarProps;
}
/**
* Register a property with it's associated compound type and relative name.
*/
public void addCompoundProperty(String propName, CtCompoundType<?> t, CompoundTypeProperty<?, ?> prop) {
CtCompoundProperty parent = null;
String[] split = SplitName.split(propName);
if (split[0] != null) {
parent = compoundProperties.get(split[0]);
}
CtCompoundProperty p = new CtCompoundProperty(propName, parent, t, prop);
compoundProperties.put(propName, p);
}
/**
* Register a scalarType used in the compound type with its given property name.
*/
public void addScalarType(String propName, ScalarType<?> scalar) {
scalarProps.put(propName, scalar);
}
public CtCompoundProperty getCompoundType(String propName) {
return compoundProperties.get(propName);
}
public Set<Entry<String, ScalarType<?>>> entries() {
return scalarProps.entrySet();
}
}
@@ -4,8 +4,6 @@ import com.avaje.ebean.annotation.DbArray;
import com.avaje.ebean.annotation.DbEnumType;
import com.avaje.ebean.annotation.DbEnumValue;
import com.avaje.ebean.annotation.EnumValue;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.CompoundTypeProperty;
import com.avaje.ebean.config.JsonConfig;
import com.avaje.ebean.config.Platform;
import com.avaje.ebean.config.ScalarTypeConverter;
@@ -15,14 +13,6 @@ import com.avaje.ebean.config.dbplatform.DbPlatformType;
import com.avaje.ebean.dbmigration.DbOffline;
import com.avaje.ebean.plugin.ExtraTypeFactory;
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
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;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -57,27 +47,12 @@ import java.time.Month;
import java.time.MonthDay;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Period;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Currency;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -86,12 +61,10 @@ import java.util.concurrent.ConcurrentHashMap;
* Manages the list of ScalarType that is available.
* </p>
*/
public final class DefaultTypeManager implements TypeManager, KnownImmutable {
public final class DefaultTypeManager implements TypeManager {
private static final Logger logger = LoggerFactory.getLogger(DefaultTypeManager.class);
private final ConcurrentHashMap<Class<?>, CtCompoundType<?>> compoundTypeMap;
private final ConcurrentHashMap<Class<?>, ScalarType<?>> typeMap;
private final ConcurrentHashMap<Integer, ScalarType<?>> nativeMap;
@@ -150,12 +123,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
private final List<ScalarType<?>> customScalarTypes = new ArrayList<>();
private final CheckImmutable checkImmutable;
private final ImmutableMetaFactory immutableMetaFactory = new ImmutableMetaFactory();
private final ReflectionBasedTypeBuilder reflectScalarBuilder;
private final JsonConfig.DateTime jsonDateTime;
private final Object objectMapper;
@@ -198,10 +165,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
this.java7Present = config.getClassLoadConfig().isJava7Present();
this.jsonDateTime = config.getJsonDateTime();
this.checkImmutable = new CheckImmutable(this);
this.reflectScalarBuilder = new ReflectionBasedTypeBuilder(this);
this.compoundTypeMap = new ConcurrentHashMap<>();
this.typeMap = new ConcurrentHashMap<>();
this.nativeMap = new ConcurrentHashMap<>();
@@ -225,7 +188,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
initialiseCustomScalarTypes(jsonDateTime, bootupClasses);
initialiseScalarConverters(bootupClasses);
initialiseAttributeConverters(bootupClasses);
initialiseCompoundTypes(bootupClasses);
}
}
@@ -279,53 +241,12 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
return scalarDataReader != null;
}
public CheckImmutableResponse checkImmutable(Class<?> cls) {
return checkImmutable.checkImmutable(cls);
}
private ScalarType<?> register(ScalarType<?> st) {
add(st);
logger.debug("Registering ScalarType for " + st.getType() + " implemented using reflection");
return st;
}
public ScalarDataReader<?> recursiveCreateScalarDataReader(Class<?> cls) {
ScalarDataReader<?> scalarReader = getScalarDataReader(cls);
if (scalarReader != null) {
return scalarReader;
}
ImmutableMeta meta = immutableMetaFactory.createImmutableMeta(cls);
if (!meta.isCompoundType()) {
return register(reflectScalarBuilder.buildScalarType(meta));
}
ReflectionBasedCompoundType compoundType = reflectScalarBuilder.buildCompound(meta);
Class<?> compoundTypeClass = compoundType.getCompoundType();
return createCompoundScalarDataReader(compoundTypeClass, compoundType, " using reflection");
}
public ScalarType<?> recursiveCreateScalarTypes(Class<?> cls) {
ScalarType<?> scalarType = getScalarType(cls);
if (scalarType != null) {
return scalarType;
}
ImmutableMeta meta = immutableMetaFactory.createImmutableMeta(cls);
if (!meta.isCompoundType()) {
return register(reflectScalarBuilder.buildScalarType(meta));
}
throw new RuntimeException("Not allowed compound types here");
}
/**
* Register a custom ScalarType.
*/
@@ -360,10 +281,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
}
}
public CtCompoundType<?> getCompoundType(Class<?> type) {
return compoundTypeMap.get(type);
}
/**
* Return the ScalarType for the given jdbc type as per java.sql.Types.
*/
@@ -401,29 +318,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
return null;
}
private ScalarDataReader<?> getScalarDataReader(Class<?> propertyType, int sqlType) {
if (sqlType == 0) {
return recursiveCreateScalarDataReader(propertyType);
}
for (ScalarType<?> customScalarType : customScalarTypes) {
if (sqlType == customScalarType.getJdbcType() && (propertyType.equals(customScalarType.getType()))) {
return customScalarType;
}
}
String msg = "Unable to find a custom ScalarType with type [" + propertyType + "] and java.sql.Type [" + sqlType + "]";
throw new RuntimeException(msg);
}
private ScalarDataReader<?> getScalarDataReader(Class<?> type) {
ScalarDataReader<?> reader = typeMap.get(type);
if (reader == null) {
reader = compoundTypeMap.get(type);
}
return reader;
return typeMap.get(type);
}
@Override
@@ -857,83 +753,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
}
}
private void initialiseCompoundTypes(BootupClasses bootupClasses) {
List<Class<? extends CompoundType<?>>> compoundTypes = bootupClasses.getCompoundTypes();
for (Class<? extends CompoundType<?>> compoundType1 : compoundTypes) {
Class<?> type = compoundType1;
try {
Class<?>[] paramTypes = TypeReflectHelper.getParams(type, CompoundType.class);
if (paramTypes.length != 1) {
throw new RuntimeException("Expecting 1 generic paramter type but got " + Arrays.toString(paramTypes) + " for " + type);
}
Class<?> compoundTypeClass = paramTypes[0];
CompoundType<?> compoundType = (CompoundType<?>) type.newInstance();
createCompoundScalarDataReader(compoundTypeClass, compoundType, "");
} catch (Exception e) {
String msg = "Error initialising component " + type;
throw new RuntimeException(msg, e);
}
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private CtCompoundType createCompoundScalarDataReader(Class<?> compoundTypeClass, CompoundType<?> compoundType, String info) {
CtCompoundType<?> ctCompoundType = compoundTypeMap.get(compoundTypeClass);
if (ctCompoundType != null) {
logger.info("Already registered compound type " + compoundTypeClass);
return ctCompoundType;
}
CompoundTypeProperty<?, ?>[] cprops = compoundType.getProperties();
ScalarDataReader[] dataReaders = new ScalarDataReader[cprops.length];
for (int i = 0; i < cprops.length; i++) {
Class<?> propertyType = getCompoundPropertyType(cprops[i]);
ScalarDataReader<?> scalarDataReader = getScalarDataReader(propertyType, cprops[i].getDbType());
if (scalarDataReader == null) {
throw new RuntimeException("Could not find ScalarDataReader for " + propertyType);
}
dataReaders[i] = scalarDataReader;
}
CtCompoundType ctType = new CtCompoundType(compoundTypeClass, compoundType, dataReaders);
logger.debug("Registering CompoundType " + compoundTypeClass + " " + info);
compoundTypeMap.put(compoundTypeClass, ctType);
return ctType;
}
/**
* Return the property type for a given property of a compound type.
*/
private Class<?> getCompoundPropertyType(CompoundTypeProperty<?, ?> prop) {
if (prop instanceof ReflectionBasedCompoundTypeProperty) {
return ((ReflectionBasedCompoundTypeProperty) prop).getPropertyType();
}
// determine the types from generic parameter types using reflection
Class<?>[] propParamTypes = TypeReflectHelper.getParams(prop.getClass(), CompoundTypeProperty.class);
if (propParamTypes.length != 2) {
throw new RuntimeException("Expecting 2 generic paramter types but got " + Arrays.toString(propParamTypes) + " for " + prop.getClass());
}
return propParamTypes[1];
}
/**
* Add support for Jackson's JsonNode mapping to Clob, Blob, Varchar, JSON and JSONB.
*/
@@ -983,8 +802,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
typeMap.put(ZoneId.class, new ScalarTypeZoneId());
typeMap.put(ZoneOffset.class, new ScalarTypeZoneOffset());
createCompoundScalarDataReader(Period.class, new CompoundTypePeriod(), "");
boolean localTimeNanos = config.isLocalTimeWithNanos();
typeMap.put(java.time.LocalTime.class, (localTimeNanos) ? new ScalarTypeLocalTimeWithNanos() : new ScalarTypeLocalTime());
@@ -1,95 +0,0 @@
package com.avaje.ebeaninternal.server.type;
import java.util.HashMap;
import java.util.Map;
/**
* Used to build Immutable Compound Value objects.
* <p>
* The individual values are collected for a given type and when they have all
* been collected then the immutable compound value object is created and
* returned.
* </p>
*/
public final class ImmutableCompoundTypeBuilder {
private static final ThreadLocal<ImmutableCompoundTypeBuilder> local = new ThreadLocal<ImmutableCompoundTypeBuilder>() {
protected synchronized ImmutableCompoundTypeBuilder initialValue() {
return new ImmutableCompoundTypeBuilder();
}
};
private final Map<Class<?>, Entry> entryMap = new HashMap<>();
/**
* Clear the cache of partial compound objects.
*/
public static void clear() {
local.get().entryMap.clear();
}
/**
* Set the value for the property of a compound type.
* <p>
* If this is the last value required for the compound type then the
* compound type is created and returned, otherwise null is returned (and we
* need more values set).
* </p>
*/
public static Object set(CtCompoundType<?> ct, String propName, Object value) {
return local.get().setValue(ct, propName, value);
}
private Object setValue(CtCompoundType<?> ct, String propName, Object value) {
Entry e = getEntry(ct);
Object compoundValue = e.set(propName, value);
if (compoundValue != null) {
removeEntry(ct);
}
return compoundValue;
}
/**
* Once we have built a compound value we remove the entry.
*/
private void removeEntry(CtCompoundType<?> ct) {
entryMap.remove(ct.getCompoundTypeClass());
}
/**
* Get the Entry which contains the values collected so far for this type.
*/
private Entry getEntry(CtCompoundType<?> ct) {
Entry e = entryMap.get(ct.getCompoundTypeClass());
if (e == null) {
e = new Entry(ct);
entryMap.put(ct.getCompoundTypeClass(), e);
}
return e;
}
/**
* Holds the values collected so far for a given compound type.
*/
private static class Entry {
private final CtCompoundType<?> ct;
private final Map<String, Object> valueMap;
private Entry(CtCompoundType<?> ct) {
this.ct = ct;
this.valueMap = new HashMap<>();
}
private Object set(String propName, Object value) {
// collect the values...
valueMap.put(propName, value);
// when got all the values this returns the
// compound value, otherwise null
return ct.create(valueMap);
}
}
}
@@ -22,9 +22,4 @@ public interface ScalarDataReader<T> {
*/
void bind(DataBind b, T value) throws SQLException;
/**
* Accumulate all the scalar types used by an immutable compound value type.
*/
void accumulateScalarTypes(String propName, CtCompoundTypeScalarList list);
}
@@ -73,8 +73,4 @@ public abstract class ScalarTypeBase<T> implements ScalarType<T> {
reader.incrementPos(1);
}
public void accumulateScalarTypes(String propName, CtCompoundTypeScalarList list) {
list.addScalarType(propName, this);
}
}
@@ -121,10 +121,6 @@ public class ScalarTypeBytesEncrypted implements ScalarType<byte[]> {
return baseType.toJdbcType(value);
}
public void accumulateScalarTypes(String propName, CtCompoundTypeScalarList list) {
baseType.accumulateScalarTypes(propName, list);
}
public byte[] readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
@@ -137,11 +137,6 @@ public class ScalarTypeEncryptedWrapper<T> implements ScalarType<T> {
return wrapped.toJdbcType(value);
}
@Override
public void accumulateScalarTypes(String propName, CtCompoundTypeScalarList list) {
wrapped.accumulateScalarTypes(propName, list);
}
@Override
public T jsonRead(JsonParser parser) throws IOException {
return wrapped.jsonRead(parser);
@@ -183,11 +183,6 @@ public class ScalarTypeWrapper<B, S> implements ScalarType<B> {
return scalarType.toJdbcType(sv);
}
@Override
public void accumulateScalarTypes(String propName, CtCompoundTypeScalarList list) {
list.addScalarType(propName, this);
}
public ScalarType<?> getScalarType() {
return this;
}
@@ -1,7 +1,6 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.annotation.DbArray;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
import java.lang.reflect.Type;
@@ -10,21 +9,6 @@ import java.lang.reflect.Type;
*/
public interface TypeManager {
/**
* Check if the type is immutable using reflection.
*/
CheckImmutableResponse checkImmutable(Class<?> cls);
/**
* Create ScalarDataReader's for the Immutable compound type.
*/
ScalarDataReader<?> recursiveCreateScalarDataReader(Class<?> cls);
/**
* Create ScalarTypes for this Immutable Value Object type.
*/
ScalarType<?> recursiveCreateScalarTypes(Class<?> cls);
/**
* Register a ScalarType with the system.
*/
@@ -35,11 +19,6 @@ public interface TypeManager {
*/
void addEnumType(ScalarType<?> type, Class<? extends Enum> myEnumClass);
/**
* Return the Internal CompoundType handler for a given compound type.
*/
CtCompoundType<?> getCompoundType(Class<?> type);
/**
* Return the ScalarType for a given jdbc type.
*
@@ -1,128 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class CheckImmutable {
private static final Logger logger = LoggerFactory.getLogger(CheckImmutable.class);
private final KnownImmutable knownImmutable;
public CheckImmutable(KnownImmutable knownImmutable) {
this.knownImmutable = knownImmutable;
}
public CheckImmutableResponse checkImmutable(Class<?> cls) {
CheckImmutableResponse res = new CheckImmutableResponse();
isImmutable(cls, res);
if (res.isImmutable()) {
res.setCompoundType(isCompoundType(cls));
}
return res;
}
private boolean isCompoundType(Class<?> cls) {
int maxLength = 0;
Constructor<?> chosen = null;
// find the constructor with the most number of parameters
Constructor<?>[] constructors = cls.getConstructors();
for (Constructor<?> constructor : constructors) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
if (parameterTypes.length > maxLength) {
maxLength = parameterTypes.length;
chosen = constructor;
}
}
logger.debug("checkImmutable " + cls + " constructor " + chosen);
return maxLength > 1;
}
private boolean isImmutable(Class<?> cls, CheckImmutableResponse res) {
if (knownImmutable.isKnownImmutable(cls)) {
return true;
}
if (cls.isArray()) {
return false;
}
if (hasDefaultConstructor(cls)) {
// must not have a default constructor to be considered immutable
res.setReasonNotImmutable(cls + " has a default constructor");
return false;
}
// check super class
Class<?> superClass = cls.getSuperclass();
if (!isImmutable(superClass, res)) {
res.setReasonNotImmutable("Super not Immutable " + superClass);
return false;
}
if (!hasAllFinalFields(cls, res)) {
return false;
}
// Lets hope we didn't forget something
return true;
}
private boolean hasAllFinalFields(Class<?> cls, CheckImmutableResponse res) {
// Check all fields defined in the class for type and if they are final
Field[] objFields = cls.getDeclaredFields();
for (Field objField : objFields) {
if (!Modifier.isStatic(objField.getModifiers())) {
if (!Modifier.isFinal(objField.getModifiers())) {
res.setReasonNotImmutable("Non final field " + cls + "." + objField.getName());
return false;
}
if (!isImmutable(objField.getType(), res)) {
res.setReasonNotImmutable("Non Immutable field type " + objField.getType());
return false;
}
}
}
return true;
}
private boolean hasDefaultConstructor(Class<?> cls) {
Class<?>[] noParams = new Class<?>[0];
try {
cls.getDeclaredConstructor(noParams);
return true;
} catch (SecurityException e) {
// this is ok
return false;
} catch (NoSuchMethodException e) {
// this is expected for our IVO's
return false;
}
}
}
@@ -1,36 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
public class CheckImmutableResponse {
private boolean immutable = true;
private String reasonNotImmutable;
private boolean compoundType;
public String toString() {
if (immutable) {
return "immutable";
} else {
return "not immutable due to:" + reasonNotImmutable;
}
}
public boolean isCompoundType() {
return compoundType;
}
public void setCompoundType(boolean compoundType) {
this.compoundType = compoundType;
}
public void setReasonNotImmutable(String error) {
this.immutable = false;
this.reasonNotImmutable = error;
}
public boolean isImmutable() {
return immutable;
}
}
@@ -1,30 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ImmutableMeta {
private final Constructor<?> constructor;
private final Method[] readers;
public ImmutableMeta(Constructor<?> constructor, Method[] readers) {
this.constructor = constructor;
this.readers = readers;
}
public Constructor<?> getConstructor() {
return constructor;
}
public Method[] getReaders() {
return readers;
}
public boolean isCompoundType() {
return readers.length > 1;
}
}
@@ -1,221 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
public class ImmutableMetaFactory {
private static final Logger logger = LoggerFactory.getLogger(ImmutableMetaFactory.class);
public ImmutableMeta createImmutableMeta(Class<?> cls) {
ScoreConstructor[] scoreConstructors = scoreConstructors(cls);
ArrayList<RuntimeException> errors = new ArrayList<>();
// search the constructors in score order ...
// ... we need to find a set of readers for each
// ... type in the constructor
for (ScoreConstructor scoreConstructor : scoreConstructors) {
Constructor<?> constructor = scoreConstructor.constructor;
try {
Method[] getters = findGetters(cls, constructor);
return new ImmutableMeta(constructor, getters);
} catch (NoSuchMethodException e) {
String msg = "Error finding getter method on " + cls + " with constructor " + constructor;
errors.add(new RuntimeException(msg, e));
}
}
String msg = "Was unable to use reflection to find a constructor and appropriate getters for" +
"immutable type " + cls + ". The errors while looking for the getter methods follow:";
logger.error(msg);
for (RuntimeException runtimeException : errors) {
logger.error("Error with " + cls, runtimeException);
}
msg = "Unable to use reflection to build ImmutableMeta for " + cls
+ ". Associated Errors trying to find a constructor and getter methods have been logged";
throw new RuntimeException(msg);
}
private ScoreConstructor getScore(Constructor<?> c) {
Class<?>[] parameterTypes = c.getParameterTypes();
int score = -1000 * parameterTypes.length;
for (Class<?> parameterType : parameterTypes) {
if (parameterType.equals(String.class)) {
// string is very generic and we would prefer
// a more specific type if that was available
score = score + 1;
} else if (parameterType.equals(BigDecimal.class)) {
score = score - 10;
} else if (parameterType.equals(Timestamp.class)) {
score = score - 10;
} else if (parameterType.equals(double.class)) {
score = score - 9;
} else if (parameterType.equals(Double.class)) {
score = score - 8;
} else if (parameterType.equals(float.class)) {
score = score - 7;
} else if (parameterType.equals(Float.class)) {
score = score - 6;
} else if (parameterType.equals(long.class)) {
score = score - 5;
} else if (parameterType.equals(Long.class)) {
score = score - 4;
} else if (parameterType.equals(int.class)) {
score = score - 3;
} else if (parameterType.equals(Integer.class)) {
score = score - 2;
}
}
return new ScoreConstructor(score, c);
}
private ScoreConstructor[] scoreConstructors(Class<?> cls) {
// find the constructor with the most number of parameters
int maxParamCount = 0;
Constructor<?>[] constructors = cls.getConstructors();
ScoreConstructor[] score = new ScoreConstructor[constructors.length];
for (int i = 0; i < constructors.length; i++) {
score[i] = getScore(constructors[i]);
if (score[i].hasDuplicateParamTypes()) {
String msg = "Duplicate parameter types in " + score[i].constructor;
throw new IllegalStateException(msg);
}
if (score[i].getParamCount() > maxParamCount) {
maxParamCount = score[i].getParamCount();
}
}
// filter out any constructors with less parameters than the max
ArrayList<ScoreConstructor> list = new ArrayList<>();
for (ScoreConstructor aScore : score) {
if (aScore.getParamCount() == maxParamCount) {
list.add(aScore);
}
}
score = list.toArray(new ScoreConstructor[list.size()]);
// sort into score ascending order
Arrays.sort(score);
return score;
}
private Method[] findGetters(Class<?> cls, Constructor<?> c) throws NoSuchMethodException {
Method[] methods = cls.getMethods();
Class<?>[] paramTypes = c.getParameterTypes();
Method[] readers = new Method[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
Method getter = findGetter(paramTypes[i], methods);
if (getter == null && paramTypes.length == 1 && paramTypes[i].equals(String.class)) {
getter = findToString(cls);
}
if (getter == null) {
throw new NoSuchMethodException("Get Method not found for " + paramTypes[i] + " in " + cls);
}
readers[i] = getter;
}
return readers;
}
private Method findToString(Class<?> cls) throws NoSuchMethodException {
try {
return cls.getDeclaredMethod("toString", new Class<?>[0]);
} catch (SecurityException e) {
throw new NoSuchMethodException("SecurityException " + e + " trying to find toString method on " + cls);
}
}
private Method findGetter(Class<?> paramType, Method[] methods) {
for (Method method : methods) {
if (!Modifier.isStatic(method.getModifiers())) {
if (method.getParameterTypes().length == 0) {
// could be a getter
String methName = method.getName();
if (!methName.equals("hashCode") && !methName.equals("toString")) {
Class<?> returnType = method.getReturnType();
if (paramType.equals(returnType)) {
return method;
}
}
}
}
}
return null;
}
private static class ScoreConstructor implements Comparable<ScoreConstructor> {
final int score;
final Constructor<?> constructor;
private ScoreConstructor(int score, Constructor<?> constructor) {
this.score = score;
this.constructor = constructor;
}
@Override
public boolean equals(Object obj) {
// remove FindBugs warning
return obj == this;
}
public int compareTo(ScoreConstructor o) {
return (score < o.score ? -1 : (score == o.score ? 0 : 1));
}
public int getParamCount() {
return constructor.getParameterTypes().length;
}
public boolean hasDuplicateParamTypes() {
Class<?>[] parameterTypes = constructor.getParameterTypes();
if (parameterTypes.length < 2) {
return false;
}
HashSet<Class<?>> set = new HashSet<>();
for (Class<?> parameterType : parameterTypes) {
if (!set.add(parameterType)) {
return true;
}
}
return false;
}
}
}
@@ -1,6 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
public interface KnownImmutable {
boolean isKnownImmutable(Class<?> cls);
}
@@ -1,46 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.CompoundTypeProperty;
import java.lang.reflect.Constructor;
import java.util.Arrays;
@SuppressWarnings({"rawtypes"})
public class ReflectionBasedCompoundType implements CompoundType {
private final Constructor<?> constructor;
private final ReflectionBasedCompoundTypeProperty[] props;
public ReflectionBasedCompoundType(Constructor<?> constructor, ReflectionBasedCompoundTypeProperty[] props) {
this.constructor = constructor;
this.props = props;
}
public String toString() {
return "ReflectionBasedCompoundType " + constructor + " " + Arrays.toString(props);
}
public Object create(Object[] propertyValues) {
try {
return constructor.newInstance(propertyValues);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public CompoundTypeProperty[] getProperties() {
return props;
}
public Class<?> getPropertyType(int i) {
return props[i].getPropertyType();
}
public Class<?> getCompoundType() {
return constructor.getDeclaringClass();
}
}
@@ -1,50 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import com.avaje.ebean.config.CompoundTypeProperty;
import java.lang.reflect.Method;
@SuppressWarnings({"rawtypes"})
public class ReflectionBasedCompoundTypeProperty implements CompoundTypeProperty {
private static final Object[] NO_ARGS = new Object[0];
private final Method reader;
private final String name;
private final Class<?> propertyType;
public ReflectionBasedCompoundTypeProperty(String name, Method reader, Class<?> propertyType) {
this.name = name;
this.reader = reader;
this.propertyType = propertyType;
}
public String toString() {
return name;
}
public int getDbType() {
return 0;
}
public String getName() {
return name;
}
public Object getValue(Object valueObject) {
try {
return reader.invoke(valueObject, NO_ARGS);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Class<?> getPropertyType() {
return propertyType;
}
}
@@ -1,49 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import com.avaje.ebean.config.ScalarTypeConverter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@SuppressWarnings({"rawtypes"})
public class ReflectionBasedScalarTypeConverter implements ScalarTypeConverter {
private static final Object[] NO_ARGS = new Object[0];
private final Constructor<?> constructor;
private final Method reader;
public ReflectionBasedScalarTypeConverter(Constructor<?> constructor, Method reader) {
this.constructor = constructor;
this.reader = reader;
}
public Object getNullValue() {
return null;
}
public Object unwrapValue(Object beanType) {
if (beanType == null) {
return null;
}
try {
return reader.invoke(beanType, NO_ARGS);
} catch (Exception e) {
String msg = "Error invoking read method " + reader.getName()
+ " on " + beanType.getClass().getName();
throw new RuntimeException(msg);
}
}
public Object wrapValue(Object scalarType) {
try {
return constructor.newInstance(scalarType);
} catch (Exception e) {
String msg = "Error invoking constructor " + constructor + " with " + scalarType;
throw new RuntimeException(msg);
}
}
}
@@ -1,78 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.type.ScalarTypeWrapper;
import com.avaje.ebeaninternal.server.type.TypeManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectionBasedTypeBuilder {
private final TypeManager typeManager;
public ReflectionBasedTypeBuilder(TypeManager typeManager) {
this.typeManager = typeManager;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public ScalarType<?> buildScalarType(ImmutableMeta meta) {
if (meta.isCompoundType()) {
throw new RuntimeException("Must be scalar");
}
Constructor<?> constructor = meta.getConstructor();
Class<?> logicalType = constructor.getDeclaringClass();
Method[] readers = meta.getReaders();
Class<?> returnType = readers[0].getReturnType();
ScalarType<?> scalarType = typeManager.recursiveCreateScalarTypes(returnType);
ReflectionBasedScalarTypeConverter r = new ReflectionBasedScalarTypeConverter(constructor, readers[0]);
return new ScalarTypeWrapper(logicalType, scalarType, r);
}
public ReflectionBasedCompoundType buildCompound(ImmutableMeta meta) {
Constructor<?> constructor = meta.getConstructor();
Method[] readers = meta.getReaders();
ReflectionBasedCompoundTypeProperty[] props = new ReflectionBasedCompoundTypeProperty[readers.length];
for (int i = 0; i < readers.length; i++) {
Class<?> returnType = readers[i].getReturnType();
// ensure that return type is also a ScalarDataReader
typeManager.recursiveCreateScalarDataReader(returnType);
String name = getPropertyName(readers[i]);
props[i] = new ReflectionBasedCompoundTypeProperty(name, readers[i], returnType);
}
return new ReflectionBasedCompoundType(constructor, props);
}
private String getPropertyName(Method method) {
String name = method.getName();
if (name.startsWith("is")) {
return lowerFirstChar(name.substring(2));
} else if (name.startsWith("get")) {
return lowerFirstChar(name.substring(3));
}
String msg = "Expecting method " + name + " to start with is or get "
+ " so as to follow bean specification?";
throw new RuntimeException(msg);
}
private String lowerFirstChar(String name) {
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
}
}
@@ -1 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
+29
View File
@@ -0,0 +1,29 @@
package com.avaje;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.EbeanServer;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws SQLException {
EbeanServer ms = Ebean.getServer("ms");
DataSource dataSource = ms.getPluginApi().getDataSource();
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("select next VALUE for j2_seq");
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
Object val = resultSet.getObject(1);
System.out.println(""+val);
}
connection.close();
}
}
@@ -52,7 +52,7 @@ public class BaseTestCase {
* so tests that do this need to be skipped for SQL Server.
*/
public boolean isMsSqlServer() {
return platformName().startsWith("mssqlserver");
return platformName().startsWith("sqlserver");
}
public boolean isH2() {
@@ -5,8 +5,8 @@ import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.TenantDataSourceProvider;
import com.avaje.ebean.config.TenantMode;
import com.avaje.ebean.config.TenantSchemaProvider;
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
import com.avaje.ebean.config.dbplatform.mysql.MySqlPlatform;
import com.avaje.ebean.config.dbplatform.postgres.PostgresPlatform;
import org.junit.Test;
import org.mockito.Mockito;
@@ -15,4 +15,14 @@ public class MatchingNamingConventionTest {
String col = namingConvention.getColumnFromProperty(null, fkCol);
assertThat(col).isEqualTo(fkCol);
}
}
@Test
public void getForeignKey() {
String fk = namingConvention.getForeignKey("billingAddress", "id");
assertThat(fk).isEqualTo("billingAddressId");
fk = namingConvention.getForeignKey("billingAddress", "remoteIdProperty");
assertThat(fk).isEqualTo("billingAddressRemoteIdProperty");
}
}
@@ -17,4 +17,13 @@ public class UnderscoreNamingConventionTest {
assertThat(col).isEqualTo(fkCol);
}
}
@Test
public void getForeignKey() {
String fk = namingConvention.getForeignKey("billing_address", "id");
assertThat(fk).isEqualTo("billing_address_id");
fk = namingConvention.getForeignKey("billing_address", "remoteIdProperty");
assertThat(fk).isEqualTo("billing_address_remote_id_property");
}
}
@@ -2,6 +2,8 @@ package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.DbTypeConfig;
import com.avaje.ebean.config.Platform;
import com.avaje.ebean.config.dbplatform.h2.H2Platform;
import com.avaje.ebean.config.dbplatform.postgres.PostgresPlatform;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -1,5 +1,6 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.dbplatform.postgres.PostgresPlatform;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -1,5 +1,6 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.dbplatform.h2.H2Platform;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import org.junit.Test;
@@ -22,4 +23,4 @@ public class H2PlatformTest {
assertThat(ddl.convert("bit", false)).isEqualTo("bit");
}
}
}
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.dbplatform.mysql.MySqlHistorySupport;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -2,6 +2,7 @@ package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.DbTypeConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.mysql.MySqlPlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import org.junit.Test;
@@ -2,6 +2,7 @@ package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.DbTypeConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.oracle.OraclePlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import org.junit.Test;
@@ -1,5 +1,6 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.dbplatform.postgres.PostgresHistorySupport;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.DbTypeConfig;
import com.avaje.ebean.config.dbplatform.postgres.PostgresPlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import org.junit.Test;
@@ -3,8 +3,8 @@ package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
import com.avaje.ebean.config.dbplatform.h2.H2Platform;
import com.avaje.ebean.config.dbplatform.postgres.PostgresPlatform;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.model.CurrentModel;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
@@ -142,4 +142,4 @@ public class BaseDdlHandlerTest extends BaseTestCase {
assertThat(write.dropAll().getBuffer()).isEqualTo(rollbackLast);
}
}
}
@@ -2,8 +2,8 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.OraclePlatform;
import com.avaje.ebean.config.dbplatform.h2.H2Platform;
import com.avaje.ebean.config.dbplatform.oracle.OraclePlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.ddlgeneration.Helper;
import com.avaje.ebean.dbmigration.migration.AddTableComment;
@@ -146,4 +146,4 @@ public class BaseTableDdlTest {
return createTable;
}
}
}

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