Compare commits

..
Author SHA1 Message Date
rob bygrave d432854b82 [maven-release-plugin] prepare release ebean-10.3.2 2017-06-25 16:01:37 +12:00
rob bygrave 93582c8ea3 Downgrade postgres jdbc driver for commit and continue test 2017-06-25 15:54:14 +12:00
rob bygrave 520d35b1d6 #963 - NullPointerException on no version provided (when setVersion(null) is used) 2017-06-25 14:44:13 +12:00
rob bygrave 8ca3599cbf #1046 Bump DB migration to 10.1.9 - fix for Checksum mismatch does not stop migration 2017-06-25 14:29:46 +12:00
rob bygrave 283ae74219 Update javadoc on ScalarTypeConverter. Should look to officially deprecate this in favor of AttributeConverter. 2017-06-24 11:35:58 +12:00
rob bygrave cebd3f92a4 #1045 - MySql - DbMigration generate wrong comment syntax - should be alter table comment = syntax 2017-06-24 11:23:21 +12:00
rob bygrave 4b2481d3ea #1039 Fix for - reset of dirty flag on L2 cached entities after lazy load 2017-06-23 23:20:17 +12:00
rob bygrave f1f2a416d3 No effective change - reformat only 2017-06-23 23:19:22 +12:00
rob bygrave 74dd97a55f No effective change 2017-06-23 23:18:57 +12:00
rob bygrave 3f04f7f363 Merge branch 'master' of https://github.com/SamhammerAG/ebean into SamhammerAG-master 2017-06-23 19:52:55 +12:00
rob bygrave 800f854a12 #1043 Additional test for RawSql with upper case SQL 2017-06-23 19:46:47 +12:00
rob bygrave bef9e6d54f Merge branch 'master' of github.com:ebean-orm/ebean 2017-06-23 19:43:45 +12:00
Tigran_DadaiantsandRob Bygrave 0e4c0ae6c3 #1043 RawSql should automatically map upper-case column alias to lower-case bean property (#1044) 2017-06-23 19:43:15 +12:00
rob bygrave a0ea9887df No effective change - remove unused imports 2017-06-23 19:37:24 +12:00
Roland PramlandRob Bygrave 0413c22e6e no effective code change - fixed warnings about serialization, override, raw-types (#1032) 2017-06-23 19:33:03 +12:00
rob bygrave 989ae44a6d Merge branch 'pr/id-in-as-collection' of https://github.com/FOCONIS/ebean into FOCONIS-pr/id-in-as-collection 2017-06-23 19:28:25 +12:00
rob bygrave 100d314e63 #1035 Update for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB
If use Modify mode we need to listen for both adds and removes to support sorting (can't rely on undoDelete() due to ordering)
2017-06-19 23:34:44 +12:00
rob bygrave dbf4e99187 #1035 tests for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB 2017-06-19 23:32:58 +12:00
Roland PramlandRob Bygrave 7b8a85106c FIX: deleting and adding same bean in beanCollection leads to deletion in DB (#1035) 2017-06-19 22:50:20 +12:00
rob bygrave 58c5f01e2b #1042 - JtaTransaction is TenantMode.DB aware 2017-06-19 22:28:15 +12:00
Roland PramlandRob Bygrave bc74d35651 FIX: correct behavior of "startsWith, "contains" etc (#1031)
* FIX: correct behavior of "startsWith" if string contains "like"-wildcards

* Removed likeClasues with disabled escaping in database platforms as bind values are properly escaped now.
2017-06-19 22:21:26 +12:00
Roland PramlandRob Bygrave a1f95bf25e Pr/id in as collection2 (#1034)
* ENH: Changed  idIn(List) to idIn(Collection)

* ADD: sanity checks in IdBinder & special case if ID-list is empty
2017-06-19 22:05:56 +12:00
rob bygrave c454e1f8a7 No effective change - add test 2017-06-19 21:53:35 +12:00
Koen De GrooteandRob Bygrave 5a3669e1db Noticed that this boolean parameter was ignored. (#1041)
After some quick analysis, implemented that way it probably should be used.

Of course, this could have been on purpose, please advise.
2017-06-19 21:39:58 +12:00
rob bygrave 7a2e0b3695 Bump to the later agent 2017-06-19 21:34:18 +12:00
AWoelfel ce6d6269cd Step to reproduce reset of dirty flag on L2 cached entities after lazy load 2017-06-08 15:07:32 +02:00
Roland Praml 7d800b7080 ENH: Changed idIn(List) to idIn(Collection) 2017-05-29 15:22:48 +02:00
rob bygrave 136154e247 [maven-release-plugin] prepare for next development iteration 2017-05-21 21:56:29 +12:00
86 changed files with 673 additions and 131 deletions
+6 -6
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>10.3.1</version>
<version>10.3.2</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -17,7 +17,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-10.3.1</tag>
<tag>ebean-10.3.2</tag>
</scm>
<dependencies>
@@ -67,7 +67,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-dbmigration</artifactId>
<version>10.1.8</version>
<version>10.1.9</version>
</dependency>
<dependency>
@@ -130,7 +130,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1212.jre7</version>
<version>9.4.1212</version>
<scope>provided</scope>
</dependency>
@@ -160,7 +160,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>10.1.7</version>
<version>10.3.1</version>
<scope>test</scope>
</dependency>
@@ -225,7 +225,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>10.1.7</version>
<version>10.3.1</version>
<executions>
<execution>
<id>test</id>
@@ -10,6 +10,7 @@ import javax.persistence.PessimisticLockException;
* </p>
*/
public class AcquireLockException extends PessimisticLockException {
private static final long serialVersionUID = -8585962352965876691L;
/**
* Create with a message and cause.
@@ -6,6 +6,7 @@ import javax.persistence.PersistenceException;
* Thrown when a foreign key constraint is enforced.
*/
public class DataIntegrityException extends PersistenceException {
private static final long serialVersionUID = -6740171949170180970L;
/**
* Create with a message and cause.
@@ -4,6 +4,7 @@ package io.ebean;
* Thrown when a duplicate is attempted on a unique constraint.
*/
public class DuplicateKeyException extends DataIntegrityException {
private static final long serialVersionUID = -4771932723285724817L;
/**
* Create with a message and cause.
@@ -7,7 +7,6 @@ import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
@@ -308,9 +307,9 @@ public interface ExpressionFactory {
Expression idIn(Object... idValues);
/**
* Id IN a list of Id values.
* Id IN a collection of Id values.
*/
Expression idIn(List<?> idList);
Expression idIn(Collection<?> idCollection);
/**
* All Equal - Map containing property names and their values.
+2 -2
View File
@@ -836,9 +836,9 @@ public interface ExpressionList<T> {
ExpressionList<T> idIn(Object... idValues);
/**
* Id IN a list of id values.
* Id IN a collection of id values.
*/
ExpressionList<T> idIn(List<?> idValues);
ExpressionList<T> idIn(Collection<?> idValues);
/**
* Id Equal to - ID property is equal to the value.
+4 -4
View File
@@ -6,22 +6,22 @@ package io.ebean;
public enum LikeType {
/**
* You need to put in your own wildcards.
* You need to put in your own wildcards - no escaping is performed.
*/
RAW,
/**
* The % wildcard is added to the end of the search word.
* The % wildcard is added to the end of the search word and search word is escaped.
*/
STARTS_WITH,
/**
* The % wildcard is added to the beginning of the search word.
* The % wildcard is added to the beginning of the search word and search word is escaped.
*/
ENDS_WITH,
/**
* The % wildcard is added to the beginning and end of the search word.
* The % wildcard is added to the beginning and end of the search word and search word is escaped.
*/
CONTAINS,
+1
View File
@@ -129,6 +129,7 @@ public interface Transaction extends AutoCloseable {
/**
* Synonym for end() to support AutoClosable.
*/
@Override
void close();
/**
@@ -47,8 +47,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected ModifyHolder<E> modifyHolder;
protected ModifyListenMode modifyListenMode;
protected boolean modifyAddListening;
protected boolean modifyRemoveListening;
protected boolean modifyListening;
/**
@@ -148,9 +147,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
public void setModifyListening(ModifyListenMode mode) {
this.modifyListenMode = mode;
this.modifyAddListening = ModifyListenMode.ALL.equals(mode);
this.modifyRemoveListening = modifyAddListening || ModifyListenMode.REMOVALS.equals(mode);
this.modifyListening = modifyRemoveListening || modifyAddListening;
this.modifyListening = mode != null && ModifyListenMode.NONE != mode;
if (modifyListening) {
// lose any existing modifications
modifyHolder = null;
@@ -173,14 +170,14 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
@Override
public void modifyAddition(E bean) {
if (modifyAddListening) {
if (modifyListening) {
getModifyHolder().modifyAddition(bean);
}
}
@Override
public void modifyRemoval(Object bean) {
if (modifyRemoveListening) {
if (modifyListening) {
getModifyHolder().modifyRemoval(bean);
}
}
+9 -9
View File
@@ -232,7 +232,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public void add(int index, E element) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
modifyAddition(element);
}
list.add(index, element);
@@ -247,7 +247,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
if (list.add(o)) {
modifyAddition(o);
return true;
@@ -262,7 +262,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
@@ -273,7 +273,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean addAll(int index, Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
@@ -286,7 +286,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
// TODO: when clear() and not initialised could be more clever
// and fetch just the Id's
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
for (E aList : list) {
getModifyHolder().modifyRemoval(aList);
}
@@ -380,7 +380,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public E remove(int index) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
E o = list.remove(index);
modifyRemoval(o);
return o;
@@ -392,7 +392,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean isRemove = list.remove(o);
if (isRemove) {
modifyRemoval(o);
@@ -406,7 +406,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
for (Object bean : beans) {
if (list.remove(bean)) {
@@ -424,7 +424,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean retainAll(Collection<?> retainBeans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
Iterator<E> it = list.iterator();
while (it.hasNext()) {
+2 -2
View File
@@ -211,7 +211,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
// add all beans to the removal list
for (E bean : map.values()) {
modifyRemoval(bean);
@@ -313,7 +313,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
public E remove(Object key) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
E o = map.remove(key);
modifyRemoval(o);
return o;
+6 -6
View File
@@ -210,7 +210,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
if (set.add(o)) {
modifyAddition(o);
return true;
@@ -225,7 +225,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean addAll(Collection<? extends E> addCollection) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
boolean changed = false;
for (E bean : addCollection) {
if (set.add(bean)) {
@@ -243,7 +243,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
for (E bean : set) {
modifyRemoval(bean);
}
@@ -285,7 +285,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
if (set.remove(o)) {
modifyRemoval(o);
return true;
@@ -299,7 +299,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
for (Object bean : beans) {
if (set.remove(bean)) {
@@ -316,7 +316,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean retainAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
Iterator<?> it = set.iterator();
while (it.hasNext()) {
@@ -44,21 +44,29 @@ class ModifyHolder<E> implements Serializable {
}
}
private boolean undoDeletion(E bean) {
return (bean != null) && modifyDeletions.remove(bean);
}
void modifyAddition(E bean) {
if (bean != null) {
// If it is to delete then just remove the deletion
if (!modifyDeletions.remove(bean)) {
if (!undoDeletion(bean)) {
// Insert
modifyAdditions.add(bean);
}
}
}
private boolean undoAddition(Object bean) {
return (bean != null) && modifyAdditions.remove(bean);
}
@SuppressWarnings("unchecked")
void modifyRemoval(Object bean) {
if (bean != null) {
// If it is to be added then just remove the addition
if (!modifyAdditions.remove(bean)) {
if (!undoAddition(bean)) {
modifyDeletions.add((E) bean);
}
}
@@ -7,6 +7,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Properties;
/**
* Configuration for the DB migration processing.
@@ -443,7 +444,7 @@ public class DbMigrationConfig {
/**
* Create the MigrationRunner to run migrations if necessary.
*/
public MigrationRunner createRunner(ClassLoader classLoader) {
public MigrationRunner createRunner(ClassLoader classLoader, Properties properties) {
MigrationConfig runnerConfig = new MigrationConfig();
runnerConfig.setMetaTable(metaTable);
@@ -454,6 +455,9 @@ public class DbMigrationConfig {
runnerConfig.setDbUsername(getDbUsername());
runnerConfig.setDbPassword(getDbPassword());
runnerConfig.setClassLoader(classLoader);
if (properties != null) {
runnerConfig.load(properties);
}
return new MigrationRunner(runnerConfig);
}
}
@@ -1,27 +1,24 @@
package io.ebean.config;
/**
* Matches the functionality of javax.persistence.AttributeConverter
* <p>
* In general AttributeConverter should be used in preference to this
* ScalarTypeConverter as it is JPA standard and offers the same functionality.
* </p>
* <p>
* For Ebean we will look to deprecate this interface in preference to AttributeConverter.
* </p>
* <p>
* Used to convert between a value object and a known scalar type. The value
* object is the logical type used in your application and the scalar type is
* the value used to persist than to the DB.
* </p>
* <p>
* The Value object should be immutable and scalar (aka not compound) and
* converts to and from a known scalar type which Ebean will use to persist the
* value.
* </p>
* <p>
* This is an easier alternative to implementing the
* io.ebean.server.type.ScalarType interface.
* </p>
* <p>
* Note that Ebean will automatically try to detect Immutable Scalar Value
* Objects and automatically support them via reflection. This however would not
* be appropriate when the logical type is different from the type you wish to
* use for persistence - for example, if the logical type was long and you
* wanted to use java.sql.Timestamp for persistence. In this case you would want
* to implement this interface rather than let Ebean automatically support that
* type via reflection.
* </p>
*
* @param <B> The value object type.
* @param <S> The scalar object type that is used to persist the value object.
@@ -2755,7 +2755,7 @@ public class ServerConfig {
*/
public DataSource runDbMigration(DataSource dataSource) {
if (migrationConfig.isRunMigration()) {
MigrationRunner runner = migrationConfig.createRunner(getClassLoadConfig().getClassLoader());
MigrationRunner runner = migrationConfig.createRunner(getClassLoadConfig().getClassLoader(), properties);
runner.run(dataSource);
}
return dataSource;
@@ -174,6 +174,8 @@ public class DatabasePlatform {
protected boolean supportsNativeIlike;
protected SqlExceptionTranslator exceptionTranslator = new SqlCodeTranslator();
protected char[] specialLikeCharacters = { '%', '_' };
/**
* Instantiates a new database platform.
@@ -617,4 +619,37 @@ public class DatabasePlatform {
logger.error("Error closing resultSet", e);
}
}
/**
* Escapes the like string for this DB-Platform
*/
public String escapeLikeString(String value) {
StringBuilder sb = null;
for (int i = 0; i < value.length(); i++) {
char ch = value.charAt(i);
boolean escaped = false;
for (char escapeChar: specialLikeCharacters) {
if (ch == escapeChar) {
if (sb == null) {
sb = new StringBuilder(value.substring(0, i));
}
escapeLikeCharacter(escapeChar, sb);
escaped = true;
break;
}
}
if (!escaped && sb != null) {
sb.append(ch);
}
}
if (sb == null) {
return value;
} else {
return sb.toString();
}
}
protected void escapeLikeCharacter(char ch, StringBuilder sb) {
sb.append('\\').append(ch);
}
}
@@ -40,10 +40,6 @@ public class H2Platform extends DatabasePlatform {
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
// like ? escape'' not working in the latest version H2 so just using no
// escape clause for now noting that backslash is an escape char for like in H2
this.likeClause = "like ?";
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
}
@@ -30,7 +30,6 @@ public class MySqlPlatform extends DatabasePlatform {
super();
this.platform = Platform.MYSQL;
this.useExtraTransactionOnIterateSecondaryQueries = true;
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.dbEncrypt = new MySqlDbEncrypt();
this.platformDdl = new MySqlDdl(this);
@@ -28,7 +28,6 @@ public class PostgresPlatform extends DatabasePlatform {
super();
this.platform = Platform.POSTGRES;
this.supportsNativeIlike = true;
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.blobDbType = Types.LONGVARBINARY;
this.clobDbType = Types.VARCHAR;
@@ -41,6 +41,8 @@ public class SqlServerPlatform extends DatabasePlatform {
this.openQuote = "[";
this.closeQuote = "]";
this.specialLikeCharacters = new char[] { '%', '_', '[' };
this.likeClause = "like ? COLLATE Latin1_General_BIN";
booleanDbType = Types.INTEGER;
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
@@ -63,4 +65,9 @@ public class SqlServerPlatform extends DatabasePlatform {
}
@Override
protected void escapeLikeCharacter(char ch, StringBuilder sb) {
sb.append('[').append(ch).append(']');
}
}
@@ -101,4 +101,11 @@ public class MySqlDdl extends PlatformDdl {
apply.append(" comment='").append(tableComment).append("'");
}
/**
* Add table comment as a separate statement (from the create table statement).
*/
@Override
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException {
apply.append(String.format("alter table %s comment = '%s'", tableName, tableComment)).endOfStatement();
}
}
+6 -1
View File
@@ -158,7 +158,12 @@ public class EJson {
if (list == null) {
return null;
}
return ((ModifyAwareList) list).asSet();
if (modifyAware) {
return ((ModifyAwareList) list).asSet();
} else {
return new LinkedHashSet<>(list);
}
}
/**
@@ -12,7 +12,7 @@ public class CamelCaseHelper {
String[] vals = underscore.split("_");
if (vals.length == 1) {
return underscore;
return isUpperCase(underscore) ? underscore.toLowerCase() : underscore;
}
StringBuilder result = new StringBuilder();
@@ -29,4 +29,13 @@ public class CamelCaseHelper {
return result.toString();
}
private static boolean isUpperCase(String underscore) {
for (int i = 0; i < underscore.length(); i++) {
if (Character.isLowerCase(underscore.charAt(i))) {
return false;
}
}
return true;
}
}
@@ -65,4 +65,9 @@ public interface SpiExpressionRequest {
* Append a DB Like clause.
*/
void appendLike();
/**
* Escapes a string to use it as exact match in Like clause.
*/
String escapeLikeString(String value);
}
@@ -161,6 +161,7 @@ public interface SpiQuery<T> extends Query<T> {
/**
* Return the ForUpdate mode.
*/
@Override
ForUpdate getForUpdateMode();
/**
@@ -96,6 +96,14 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
public String getDBLikeClause() {
return ebeanServer.getDatabasePlatform().getLikeClause();
}
/**
* Return the database platform escaped like string.
*/
@Override
public String escapeLikeString(String value) {
return ebeanServer.getDatabasePlatform().escapeLikeString(value);
}
@Override
public void executeSecondaryQueries(boolean forEach) {
@@ -985,6 +985,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
docStoreUpdates.queueIndex(beanDescriptor.getDocStoreQueueId(), idValue);
}
}
break;
default:
break;
}
@@ -123,6 +123,11 @@ public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
* Return the Database platform like clause.
*/
String getDBLikeClause();
/**
* Escapes a string to use it as exact match in Like clause.
*/
String escapeLikeString(String value);
/**
* Mark the underlying transaction as not being query only.
@@ -16,8 +16,10 @@ public enum ManyType {
private final boolean map;
@SuppressWarnings("rawtypes")
private final Class<? extends Collection> type;
@SuppressWarnings("rawtypes")
ManyType(boolean map, Class<? extends Collection> type) {
this.map = map;
this.type = type;
@@ -31,6 +33,7 @@ public enum ManyType {
* Returns List.class or Set.class and null for Map.
* Not intended to be called for maps.
*/
@SuppressWarnings("rawtypes")
public Class<? extends Collection> getCollectionType() {
return type;
}
@@ -29,6 +29,9 @@ public class GeneratedCounter implements GeneratedProperty {
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
Number currVal = (Number) prop.getValue(bean);
if (currVal == null) {
throw new IllegalStateException("version property has been set to null on bean: " + bean);
}
Integer nextVal = currVal.intValue() + 1;
return BasicTypeConverter.convert(nextVal, numberType);
}
@@ -25,8 +25,11 @@ public class GeneratedCounterInteger implements GeneratedProperty {
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
Integer i = (Integer) prop.getValue(bean);
return i + 1;
Integer val = (Integer) prop.getValue(bean);
if (val == null) {
throw new IllegalStateException("version property has been set to null on bean: " + bean);
}
return val + 1;
}
/**
@@ -25,8 +25,11 @@ public class GeneratedCounterLong implements GeneratedProperty {
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
Long i = (Long) prop.getValue(bean);
return i + 1;
Long val = (Long) prop.getValue(bean);
if (val == null) {
throw new IllegalStateException("version property has been set to null on bean: " + bean);
}
return val + 1;
}
/**
@@ -172,6 +172,9 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public String getIdInValueExprDelete(int size) {
if (size <= 0) {
throw new IndexOutOfBoundsException("The size must be at least 1");
}
if (!idInExpandedForm) {
return getIdInValueExpr(size);
}
@@ -199,7 +202,9 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public String getIdInValueExpr(int size) {
if (size <= 0) {
throw new IndexOutOfBoundsException("The size must be at least 1");
}
StringBuilder sb = new StringBuilder();
if (!idInExpandedForm) {
@@ -130,6 +130,9 @@ public final class IdBinderSimple implements IdBinder {
@Override
public String getIdInValueExpr(int size) {
if (size <= 0) {
throw new IndexOutOfBoundsException("The size must be at least 1");
}
StringBuilder sb = new StringBuilder(2 * size + 10);
sb.append(" in");
sb.append(" (?");
@@ -18,7 +18,6 @@ import io.ebeaninternal.api.SpiQuery;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
@@ -448,11 +447,11 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
}
/**
* Id IN a list of id values.
* Id IN a collection of id values.
*/
@Override
public Expression idIn(List<?> idList) {
return new IdInExpression(idList);
public Expression idIn(Collection<?> idCollection) {
return new IdInExpression(idCollection);
}
/**
@@ -770,8 +770,8 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
@Override
public ExpressionList<T> idIn(List<?> idList) {
add(expr.idIn(idList));
public ExpressionList<T> idIn(Collection<?> idCollection) {
add(expr.idIn(idCollection));
return this;
}
@@ -93,6 +93,11 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
sql.append(" ");
}
@Override
public String escapeLikeString(String value) {
return queryRequest.escapeLikeString(value);
}
/**
* Increments the parameter index and returns that value.
*/
@@ -10,7 +10,7 @@ import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import java.io.IOException;
import java.util.List;
import java.util.Collection;
import java.util.Map;
/**
@@ -66,7 +66,7 @@ public interface DocQueryContext {
/**
* Write an Id in expression.
*/
void writeIds(List<?> idList) throws IOException;
void writeIds(Collection<?> idCollection) throws IOException;
/**
* Write an Id equals expression.
@@ -10,6 +10,8 @@ import io.ebean.Query;
import io.ebeaninternal.api.SpiExpressionList;
import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -95,7 +97,7 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
}
@Override
public ExpressionList<T> idIn(List<?> idValues) {
public ExpressionList<T> idIn(Collection<?> idValues) {
throw new PersistenceException(notAllowedMessage);
}
@@ -9,17 +9,18 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.id.IdBinder;
import java.io.IOException;
import java.util.List;
import java.util.Collection;
import java.util.Iterator;
/**
* Slightly redundant as Query.setId() ultimately also does the same job.
*/
public class IdInExpression extends NonPrepareExpression {
private final List<?> idList;
private final Collection<?> idCollection;
public IdInExpression(List<?> idList) {
this.idList = idList;
public IdInExpression(Collection<?> idCollection) {
this.idCollection = idCollection;
}
@Override
@@ -33,7 +34,7 @@ public class IdInExpression extends NonPrepareExpression {
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.writeIds(idList);
context.writeIds(idCollection);
}
@Override
@@ -50,8 +51,8 @@ public class IdInExpression extends NonPrepareExpression {
BeanDescriptor<?> descriptor = r.getBeanDescriptor();
IdBinder idBinder = descriptor.getIdBinder();
for (Object anIdList : idList) {
idBinder.addIdInBindValue(request, anIdList);
for (Object id : idCollection) {
idBinder.addIdInBindValue(request, id);
}
}
@@ -63,10 +64,13 @@ public class IdInExpression extends NonPrepareExpression {
DefaultExpressionRequest r = (DefaultExpressionRequest) request;
BeanDescriptor<?> descriptor = r.getBeanDescriptor();
IdBinder idBinder = descriptor.getIdBinder();
request.append(descriptor.getIdBinder().getBindIdInSql(null));
String inClause = idBinder.getIdInValueExpr(idList.size());
request.append(inClause);
if (idCollection.size() == 0) {
request.append("1=0"); // append false for this stage
} else {
request.append(descriptor.getIdBinder().getBindIdInSql(null));
String inClause = idBinder.getIdInValueExpr(idCollection.size());
request.append(inClause);
}
}
@Override
@@ -75,10 +79,13 @@ public class IdInExpression extends NonPrepareExpression {
DefaultExpressionRequest r = (DefaultExpressionRequest) request;
BeanDescriptor<?> descriptor = r.getBeanDescriptor();
IdBinder idBinder = descriptor.getIdBinder();
request.append(descriptor.getIdBinderInLHSSql());
String inClause = idBinder.getIdInValueExpr(idList.size());
request.append(inClause);
if (idCollection.size() == 0) {
request.append("1=0"); // append false for this stage
} else {
request.append(descriptor.getIdBinderInLHSSql());
String inClause = idBinder.getIdInValueExpr(idCollection.size());
request.append(inClause);
}
}
/**
@@ -86,13 +93,13 @@ public class IdInExpression extends NonPrepareExpression {
*/
@Override
public void queryPlanHash(HashQueryPlanBuilder builder) {
builder.add(IdInExpression.class).add(idList.size());
builder.bind(idList.size());
builder.add(IdInExpression.class).add(idCollection.size());
builder.bind(idCollection.size());
}
@Override
public int queryBindHash() {
return idList.hashCode();
return idCollection.hashCode();
}
@Override
@@ -102,17 +109,19 @@ public class IdInExpression extends NonPrepareExpression {
}
IdInExpression that = (IdInExpression) other;
return this.idList.size() == that.idList.size();
return this.idCollection.size() == that.idCollection.size();
}
@Override
public boolean isSameByBind(SpiExpression other) {
IdInExpression that = (IdInExpression) other;
if (this.idList.size() != that.idList.size()) {
if (this.idCollection.size() != that.idCollection.size()) {
return false;
}
for (int i = 0; i < idList.size(); i++) {
if (!idList.get(i).equals(that.idList.get(i))) {
Iterator<?> it = that.idCollection.iterator();
for (Object id1 : idCollection) {
Object id2 = it.next();
if (!id1.equals(id2)) {
return false;
}
}
@@ -568,7 +568,7 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
}
@Override
public ExpressionList<T> idIn(List<?> idValues) {
public ExpressionList<T> idIn(Collection<?> idValues) {
return exprList.idIn(idValues);
}
@@ -34,8 +34,7 @@ class LikeExpression extends AbstractValueExpression {
String encryptKey = prop.getBeanProperty().getEncryptKey().getStringValue();
request.addBindEncryptKey(encryptKey);
}
String bindValue = getValue(strValue(), caseInsensitive, type);
String bindValue = getValue(strValue(), caseInsensitive, type, request);
request.addBindValue(bindValue);
}
@@ -92,13 +91,15 @@ class LikeExpression extends AbstractValueExpression {
return strValue().equals(that.strValue());
}
private static String getValue(String value, boolean caseInsensitive, LikeType type) {
private static String getValue(String value, boolean caseInsensitive, LikeType type, SpiExpressionRequest request) {
if (caseInsensitive) {
value = value.toLowerCase();
}
if (type == LikeType.RAW) {
return value;
}
value = request.escapeLikeString(value);
switch (type) {
case RAW:
return value;
case STARTS_WITH:
return value + "%";
case ENDS_WITH:
@@ -7,7 +7,8 @@ import java.sql.SQLException;
* Holds the first SQLException found when executing a JDBC batch.
*/
public class BatchedSqlException extends Exception {
private static final long serialVersionUID = -4374631080253580648L;
private SQLException cause;
BatchedSqlException(String message, SQLException cause) {
@@ -135,6 +135,10 @@ class SqlTreeNodeBean implements SqlTreeNode {
pathMap = createPathMap(prefix, desc);
}
protected boolean isRoot() {
return false;
}
@Override
public ScalarType<?> getSingleAttributeScalarType() {
if (properties == null || properties.length == 0) {
@@ -316,6 +320,10 @@ class SqlTreeNodeBean implements SqlTreeNode {
aChildren.load(ctx, localBean, contextBean);
}
if (queryMode.equals(Mode.LAZYLOAD_MANY) && isRoot()) {
return contextBean;
}
if (!lazyLoadMany && localBean != null) {
ctx.setCurrentPrefix(prefix, pathMap);
if (readId && !temporalVersions) {
@@ -25,6 +25,11 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean {
this.includeJoin = includeJoin;
}
@Override
protected boolean isRoot() {
return true;
}
/**
* Append the property columns to the buffer.
*/
@@ -18,7 +18,7 @@ public class DJsonScalar {
this.typeManager = typeManager;
}
@SuppressWarnings("unchecked")
@SuppressWarnings({ "unchecked", "rawtypes" })
public void write(JsonGenerator gen, Object value) throws IOException {
if (value instanceof String) {
@@ -198,7 +198,7 @@ public class ReadJson {
* If there is a JsonReadBeanVisitor registered to the current path then
* call it's visit method with the bean and unmappedProperties.
*/
@SuppressWarnings(value = "unchecked")
@SuppressWarnings({ "unchecked", "rawtypes" })
public void beanVisitor(Object bean, Map<String, Object> unmappedProperties) {
if (visitorMap != null) {
JsonReadBeanVisitor visitor = visitorMap.get(pathStack.peekWithNull());
@@ -646,6 +646,7 @@ public class JdbcTransaction implements SpiTransaction {
}
}
@Override
public PersistenceException translate(String message, SQLException cause) {
if (manager != null) {
return manager.translate(message, cause);
@@ -28,11 +28,6 @@ public class JtaTransactionManager implements ExternalTransactionManager {
private static final String EBEAN_TXN_RESOURCE = "EBEAN_TXN_RESOURCE";
/**
* The data source.
*/
private DataSource dataSource;
/**
* The Ebean transaction manager.
*/
@@ -59,10 +54,16 @@ public class JtaTransactionManager implements ExternalTransactionManager {
// the public API and hence the Object type and casting here
this.transactionManager = (TransactionManager) txnMgr;
this.dataSource = transactionManager.getDataSource();
this.serverName = transactionManager.getServerName();
}
/**
* Return the current dataSource taking into account multi-tenancy.
*/
private DataSource dataSource() {
return transactionManager.getDataSource();
}
private TransactionSynchronizationRegistry getSyncRegistry() {
try {
InitialContext ctx = new InitialContext();
@@ -121,7 +122,7 @@ public class JtaTransactionManager implements ExternalTransactionManager {
// "wrap" it in a Ebean specific JtaTransaction
String txnId = String.valueOf(System.currentTimeMillis());
JtaTransaction newTrans = new JtaTransaction(txnId, true, ut, dataSource, transactionManager);
JtaTransaction newTrans = new JtaTransaction(txnId, true, ut, dataSource(), transactionManager);
// create and register transaction listener
JtaTxnListener txnListener = createJtaTxnListener(newTrans);
@@ -19,6 +19,7 @@ import java.util.UUID;
/**
* Type mapped for DB ARRAY type (Postgres only effectively).
*/
@SuppressWarnings("rawtypes")
public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> implements ScalarTypeArray {
private static ScalarTypeArrayList UUID = new ScalarTypeArrayList("uuid", DocPropertyType.UUID, ArrayElementConverter.UUID);
@@ -75,6 +76,7 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> implemen
/**
* Return the DB column definition for DDL generation.
*/
@Override
public String getDbColumnDefn() {
return arrayType + "[]";
}
@@ -48,11 +48,13 @@ class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
}
}
@SuppressWarnings("rawtypes")
private ScalarTypeArrayListH2(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter converter) {
super(arrayType, docPropertyType, converter);
}
@Override
@SuppressWarnings("rawtypes")
public void bind(DataBind bind, List value) throws SQLException {
if (value == null) {
bind.setNull(Types.ARRAY);
@@ -75,6 +75,7 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements
/**
* Return the DB column definition for DDL generation.
*/
@Override
public String getDbColumnDefn() {
return arrayType + "[]";
}
@@ -61,6 +61,7 @@ public class ScalarTypeJsonList {
/**
* Base class for List handling.
*/
@SuppressWarnings("rawtypes")
private abstract static class Base extends ScalarTypeJsonCollection<List> {
public Base(int dbType, DocPropertyType docType) {
@@ -135,6 +136,7 @@ public class ScalarTypeJsonList {
this.pgType = pgType;
}
@SuppressWarnings("rawtypes")
@Override
public void bind(DataBind bind, List value) throws SQLException {
@@ -21,6 +21,7 @@ import java.util.Map;
/**
* Type which maps Map<String,Object> to various DB types (Clob, Varchar, Blob) in JSON format.
*/
@SuppressWarnings("rawtypes")
public abstract class ScalarTypeJsonMap extends ScalarTypeBase<Map> {
private static final ScalarTypeJsonMap CLOB = new ScalarTypeJsonMap.Clob();
@@ -17,6 +17,7 @@ public abstract class ScalarTypeJsonMapPostgres extends ScalarTypeJsonMap {
this.postgresType = postgresType;
}
@SuppressWarnings("rawtypes")
@Override
public void bind(DataBind bind, Map value) throws SQLException {
@@ -67,6 +67,7 @@ public class ScalarTypeJsonObjectMapper {
/**
* Type for Sets wrapping the ObjectMapper Set as a ModifyAwareSet.
*/
@SuppressWarnings("rawtypes")
private static class OmSet extends Base<Set> {
public OmSet(ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) {
@@ -84,6 +85,7 @@ public class ScalarTypeJsonObjectMapper {
/**
* Type for Lists wrapping the ObjectMapper List as a ModifyAwareList.
*/
@SuppressWarnings("rawtypes")
private static class OmList extends Base<List> {
public OmList(ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) {
@@ -101,6 +103,7 @@ public class ScalarTypeJsonObjectMapper {
/**
* Type for Map wrapping the ObjectMapper Map as a ModifyAwareMap.
*/
@SuppressWarnings("rawtypes")
private static class OmMap extends Base<Map> {
public OmMap(ObjectMapper objectMapper, Type type, int dbType, String pgType) {
@@ -64,6 +64,7 @@ public class ScalarTypeJsonSet {
/**
* Base class for List handling.
*/
@SuppressWarnings("rawtypes")
private abstract static class Base extends ScalarTypeJsonCollection<Set> {
public Base(int dbType, DocPropertyType docPropertyType) {
@@ -142,6 +143,7 @@ public class ScalarTypeJsonSet {
this.pgType = pgType;
}
@SuppressWarnings("rawtypes")
@Override
public void bind(DataBind bind, Set value) throws SQLException {
@@ -1,6 +1,5 @@
package io.ebean;
import io.ebean.DRawSqlColumnsParser;
import io.ebean.RawSql.ColumnMapping;
import io.ebean.RawSql.ColumnMapping.Column;
import junit.framework.TestCase;
@@ -5,6 +5,8 @@ import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -12,9 +14,9 @@ import static org.assertj.core.api.Assertions.assertThat;
public class BeanListTest {
Object object1 = new Object();
Object object2 = new Object();
Object object3 = new Object();
private Object object1 = new Object();
private Object object2 = new Object();
private Object object3 = new Object();
@NotNull
private List<Object> all() {
@@ -33,6 +35,30 @@ public class BeanListTest {
return some;
}
@Test
public void test_setModifyListening_null() throws Exception {
BeanList<Object> list = new BeanList<>();
list.setModifyListening(null);
// act
list.addAll(all());
assertThat(list.getModifyAdditions()).isNull();
}
@Test
public void test_setModifyListening_none() throws Exception {
BeanList<Object> list = new BeanList<>();
list.setModifyListening(BeanCollection.ModifyListenMode.NONE);
// act
list.addAll(all());
assertThat(list.getModifyAdditions()).isNull();
}
@Test
public void testAdd() throws Exception {
@@ -67,6 +93,47 @@ public class BeanListTest {
assertThat(list.getModifyRemovals()).isEmpty();
}
@Test
public void test_removals_DeleteThenAddBack_expect_noChange() throws Exception {
BeanList<Object> list = new BeanList<>(some());
list.setModifyListening(BeanCollection.ModifyListenMode.REMOVALS);
// act
list.remove(object2);
assertThat(list.getModifyRemovals()).isNotEmpty();
list.add(object2);
assertThat(list.getModifyRemovals()).isEmpty();
assertThat(list.getModifyAdditions()).isEmpty();
}
@Test
public void test_sort_whenAll_expect_noChange() throws Exception {
BeanList<Object> list = new BeanList<>(all());
list.setModifyListening(BeanCollection.ModifyListenMode.ALL);
// act
Collections.sort(list, Comparator.comparingInt(Object::hashCode));
assertThat(list.getModifyRemovals()).isEmpty();
assertThat(list.getModifyAdditions()).isEmpty();
}
@Test
public void test_sort_whenRemovals_expect_noChange() throws Exception {
BeanList<Object> list = new BeanList<>(all());
list.setModifyListening(BeanCollection.ModifyListenMode.REMOVALS);
// act
Collections.sort(list, Comparator.comparingInt(Object::hashCode));
assertThat(list.getModifyRemovals()).isEmpty();
assertThat(list.getModifyAdditions()).isEmpty();
}
@Test
public void testAdd_given_someAlreadyIn() throws Exception {
@@ -3,6 +3,7 @@ package io.ebean.dbmigration.ddlgeneration.platform;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.h2.H2Platform;
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
import io.ebean.config.dbplatform.oracle.OraclePlatform;
import io.ebean.dbmigration.ddlgeneration.DdlWrite;
import io.ebean.dbmigration.ddlgeneration.Helper;
@@ -93,6 +94,23 @@ public class BaseTableDdlTest {
assertThat(ddl).contains("comment on table mytab is 'my comment'");
}
@Test
public void testAddTableComment_mysql() throws IOException {
BaseTableDdl ddlGen = new BaseTableDdl(serverConfig, new MySqlPlatform().getPlatformDdl());
DdlWrite write = new DdlWrite();
AddTableComment addTableComment = new AddTableComment();
addTableComment.setName("mytab");
addTableComment.setComment("my comment");
ddlGen.generate(write, addTableComment);
String ddl = write.apply().getBuffer();
assertThat(ddl).contains("alter table mytab comment = 'my comment'");
}
@Test
public void testGenerate() throws Exception {
@@ -16,6 +16,7 @@ import java.io.StringReader;
import java.nio.file.Files;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -301,4 +302,13 @@ public class EJsonTests {
assertTrue(modAware.isMarkedDirty());
}
}
@Test
public void parseSet_when_not_modifyAware() throws IOException {
String jsonInput = "[{\"name\":\"rob\",\"age\":12},{\"name\":\"jim\",\"age\":42}]";
Set set = EJson.parseSet(jsonInput, false);
assertTrue(set instanceof LinkedHashSet);
}
}
@@ -25,7 +25,7 @@ public class CamelCaseHelperTest {
assertEquals(CamelCaseHelper.toCamelFromUnderscore("helloThere"), "helloThere");
assertEquals(CamelCaseHelper.toCamelFromUnderscore("helloThereJim"), "helloThereJim");
assertEquals(CamelCaseHelper.toCamelFromUnderscore("hello"), "hello");
assertEquals(CamelCaseHelper.toCamelFromUnderscore("HELLO"), "HELLO");
assertEquals(CamelCaseHelper.toCamelFromUnderscore("HELLO"), "hello");
}
}
@@ -0,0 +1,35 @@
package io.ebeaninternal.server.deploy.generatedproperty;
import io.ebean.BaseTestCase;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.BeanProperty;
import org.junit.Test;
import org.tests.model.basic.Customer;
import static org.assertj.core.api.Assertions.assertThat;
public class GeneratedCounterLongTest extends BaseTestCase {
private GeneratedCounterLong counter = new GeneratedCounterLong();
private BeanProperty version = getBeanDescriptor(Customer.class).getBeanProperty("version");
@Test(expected = IllegalStateException.class)
public void when_null_expect_IllegalStateException() throws Exception {
Customer customer = new Customer();
counter.getUpdateValue(version, (EntityBean)customer, System.currentTimeMillis());
}
@Test
public void when_set_expect_incremented() throws Exception {
Customer customer = new Customer();
customer.setVersion(7L);
Object value = counter.getUpdateValue(version, (EntityBean) customer, System.currentTimeMillis());
assertThat(value).isEqualTo(8L);
}
}
@@ -78,4 +78,9 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest {
public void appendLike() {
}
@Override
public String escapeLikeString(String value) {
return value;
}
}
@@ -3,7 +3,6 @@ package io.ebeaninternal.server.text.json;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.h2.H2Platform;
import io.ebeaninternal.server.core.bootup.BootupClasses;
import io.ebeaninternal.server.type.DefaultTypeManager;
@@ -0,0 +1,63 @@
package org.tests.cache;
import io.ebean.BaseTestCase;
import io.ebean.BeanState;
import io.ebean.Ebean;
import io.ebean.Transaction;
import org.junit.Test;
import org.tests.model.basic.L2CachedLazyDirtFlagResetBean;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class TestL2DirtyFlagOnLazyLoad extends BaseTestCase {
@Test
public void dirtyFlag_reset_after_lazy() {
//PREPARE
Transaction tx0 = Ebean.beginTransaction();
L2CachedLazyDirtFlagResetBean bean = new L2CachedLazyDirtFlagResetBean();
bean.setName("findById");
Ebean.save(bean);
//bean.save();
tx0.commit();
// clearAll() caches via the ServerCacheManager ...
// Clear all the caches on the default/primary EbeanServer
server().getServerCacheManager().clearAll();
//TEST
Transaction tx1 = Ebean.beginTransaction();
// load (and dont touch any related entity)
L2CachedLazyDirtFlagResetBean bean1 = Ebean.find(L2CachedLazyDirtFlagResetBean.class, bean.getId());
tx1.commit();
Transaction tx2 = Ebean.beginTransaction();
// load (and modify)
L2CachedLazyDirtFlagResetBean bean2 = Ebean.find(L2CachedLazyDirtFlagResetBean.class, bean.getId());
assertNotNull(bean2);
assertEquals("findById", bean2.getName());
bean2.setName("something");
BeanState beanState = Ebean.getBeanState(bean2);
assertTrue(beanState.isDirty());
//bean2.getChildren().size();
bean2.someRichObjectMethod();
assertTrue(beanState.isDirty());
Ebean.update(bean2);
tx2.commit();
Transaction tx3 = Ebean.beginTransaction();
// validation
L2CachedLazyDirtFlagResetBean bean3 = Ebean.find(L2CachedLazyDirtFlagResetBean.class, bean.getId());
assertEquals("something", bean3.getName());
tx3.rollback();
}
}
@@ -14,6 +14,7 @@ import java.util.List;
@CacheBeanTuning(maxSecsToLive = 45)
@Entity
public class Article extends BasicDomain {
private static final long serialVersionUID = -7181090513848918784L;
String name;
@@ -16,6 +16,7 @@ import java.util.Set;
@Inheritance
@DiscriminatorValue("C")
public class Car extends Vehicle {
private static final long serialVersionUID = -65427345082456523L;
public enum Size {
SMALL("S"),
@@ -0,0 +1,51 @@
package org.tests.model.basic;
import io.ebean.annotation.Cache;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
/**
* Cached bean for testing caching implementation.
*/
@Cache
@Entity
@Table(name = "l2_cached_lazy_dirt_flag_reset_bean")
public class L2CachedLazyDirtFlagResetBean {
public Long getId() {
return id;
}
@Id
Long id;
String name;
public List<L2CachedLazyDirtFlagResetBeanChild> getChildren() {
return children;
}
@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")
List<L2CachedLazyDirtFlagResetBeanChild> children;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Long> someRichObjectMethod() {
List<Long> result = new ArrayList<Long>();
if(this.children != null) {
for (L2CachedLazyDirtFlagResetBeanChild relation : this.children) {
result.add(relation.getId());
}
}
return result;
}
}
@@ -0,0 +1,23 @@
package org.tests.model.basic;
import javax.persistence.*;
@Entity
@Table(name = "l2_cached_lazy_dirt_flag_reset_bean_child")
public class L2CachedLazyDirtFlagResetBeanChild {
@Id
Long id;
@ManyToOne
@Column(nullable = false)
L2CachedLazyDirtFlagResetBean parent;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
@@ -4,10 +4,12 @@ import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Version;
import java.io.Serializable;
import java.util.UUID;
@Entity
public class OEngine {
public class OEngine implements Serializable {
private static final long serialVersionUID = 1L;
@@ -5,10 +5,12 @@ import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Version;
import java.io.Serializable;
import java.util.UUID;
@Entity
public class OGearBox {
public class OGearBox implements Serializable {
private static final long serialVersionUID = 1L;
@@ -1,5 +1,7 @@
package org.tests.model.basic;
import java.io.Serializable;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
@@ -11,7 +13,8 @@ import javax.persistence.Inheritance;
@Inheritance
@DiscriminatorColumn(name = "my_type", length = 3, discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue("1")
public class TIntRoot {
public class TIntRoot implements Serializable {
private static final long serialVersionUID = -7057502590435806504L;
@Id
Integer id;
@@ -1,11 +1,14 @@
package org.tests.model.basic;
import java.io.Serializable;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.persistence.Version;
@MappedSuperclass
public class TMappedSuper2 {
public class TMappedSuper2 implements Serializable {
private static final long serialVersionUID = 325282672490816821L;
String something;
@@ -12,6 +12,7 @@ import javax.persistence.ManyToOne;
@Inheritance
@DiscriminatorValue("T")
public class Truck extends Vehicle {
private static final long serialVersionUID = 9195535931523211134L;
public enum Size {
SMALL("S"),
@@ -11,6 +11,7 @@ import javax.persistence.Inheritance;
@Inheritance
@DiscriminatorValue("O")
public class CInhOne extends CInhRoot {
private static final long serialVersionUID = -3933815364935720317L;
private String driver;
@@ -12,6 +12,7 @@ import javax.persistence.Inheritance;
@Inheritance
@DiscriminatorColumn(length = 3)
public abstract class CInhRoot extends BasicDomain {
private static final long serialVersionUID = -4673953370819311120L;
private String licenseNumber;
@@ -11,6 +11,7 @@ import javax.persistence.Inheritance;
@Inheritance
@DiscriminatorValue("T")
public class CInhTwo extends CInhRoot {
private static final long serialVersionUID = -8528396890675473212L;
private String action;
@@ -7,7 +7,8 @@ import javax.persistence.Entity;
@Entity
public class OCompany extends BasicDomain {
private static final long serialVersionUID = 6733591692223352686L;
@Column(length = 50, unique = true)
public String corpId;
@@ -9,7 +9,8 @@ import javax.persistence.OneToOne;
@Entity
public class ORoadShowMsg extends BasicDomain {
private static final long serialVersionUID = -1555123312818834212L;
@OneToOne(cascade = CascadeType.ALL, optional = false)
@JoinColumn()//(name = "corp_id", nullable = false, referencedColumnName = "corp_id")
public OCompany company;
@@ -3,10 +3,12 @@ package org.tests.model.selfref;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.util.UUID;
@MappedSuperclass
public abstract class BaseResourceFile {
public abstract class BaseResourceFile implements Serializable {
private static final long serialVersionUID = 1L;
@@ -0,0 +1,82 @@
package org.tests.query.other;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class TestLikeEscaping extends BaseTestCase {
@Test
public void testLikeEscaping() {
ResetBasicData.reset();
// Mysql, PgSql, H2 special chars: "_" "%"
// MsSql special chars: "_" "%" "[" AND different Quoting!
Ebean.save(ResetBasicData.createCustomer("Paul % Percentage", "*Star", "[none]", 0, null));
Ebean.save(ResetBasicData.createCustomer("(none)", "More * Star", "[none]", 0, null));
Ebean.save(ResetBasicData.createCustomer("Paul %% Doublepercentage", "|Pipeway", "[other]", 1, null));
Ebean.save(ResetBasicData.createCustomer("_Udo Underscore", "|Pipeway", "[other]", 1, null));
assertThat(Ebean.find(Customer.class)
.where().contains("name", "Paul %%").findCount()
).isEqualTo(1);
assertThat(Ebean.find(Customer.class)
.where().startsWith("name", "_").findCount()
).isEqualTo(1);
assertThat(Ebean.find(Customer.class)
.where().startsWith("name", "_u").findCount()
).isEqualTo(0);
assertThat(Ebean.find(Customer.class)
.where().istartsWith("name", "_U").findCount()
).isEqualTo(1);
assertThat(Ebean.find(Customer.class)
.where().startsWith("shippingAddress.line1", "|p").findCount()
).isEqualTo(0);
assertThat(Ebean.find(Customer.class)
.where().startsWith("shippingAddress.line1", "|P").findCount()
).isEqualTo(2);
assertThat(Ebean.find(Customer.class)
.where().endsWith("billingAddress.line1", "]").findCount()
).isEqualTo(4);
assertThat(Ebean.find(Customer.class)
.where().endsWith("billingAddress.line1", "[none]").findCount()
).isEqualTo(2);
assertThat(Ebean.find(Customer.class)
.where().startsWith("billingAddress.line1", "[none]").findCount()
).isEqualTo(2);
assertThat(Ebean.find(Customer.class)
.where().contains("billingAddress.line1", "[none]").findCount()
).isEqualTo(2);
assertThat(Ebean.find(Customer.class)
.where().contains("shippingAddress.line1", "*").findCount()
).isEqualTo(2);
assertThat(Ebean.find(Customer.class)
.where().startsWith("shippingAddress.line1", "*").findCount()
).isEqualTo(1);
assertThat(Ebean.find(Customer.class)
.where().endsWith("shippingAddress.line1", "*").findCount()
).isEqualTo(0);
}
}
@@ -60,6 +60,21 @@ public class TestRawSqlOrmQuery extends BaseTestCase {
Assert.assertNotNull(list);
}
@Test
public void test_upperCaseSql() {
ResetBasicData.reset();
RawSql rawSql = RawSqlBuilder.parse("select id, NAME from O_CUSTOMER ").create();
Query<Customer> query = Ebean.find(Customer.class);
query.setRawSql(rawSql);
query.where().ilike("name", "r%");
List<Customer> list = query.findList();
Assert.assertNotNull(list);
}
@Test
public void testFirstRowsMaxRows() throws InterruptedException, ExecutionException {
@@ -1,5 +1,7 @@
package org.tests.sp.model;
import java.io.Serializable;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@@ -7,7 +9,8 @@ import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
@MappedSuperclass
public abstract class IdEntity {
public abstract class IdEntity implements Serializable {
private static final long serialVersionUID = 7804145008732783678L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
+1 -1
View File
@@ -86,7 +86,7 @@
<!--<logger name="io.ebean.cache.QUERY" level="TRACE"/>-->
<!--<logger name="io.ebean.cache.BEAN" level="TRACE"/>-->
<!--<logger name="io.ebean.cache.NATKEY" level="TRACE"/>-->
<!--<logger name="io.ebean.cache.COLL" level="DEBUG"/>-->
<!--<logger name="io.ebean.cache.COLL" level="TRACE"/>-->
<!--<logger name="org.avaje.classpath" level="INFO"/>-->