HHH-7380 - union subclass support

This commit is contained in:
Strong Liu 2012-11-28 18:12:57 +08:00
parent 73f9df1bb5
commit 9b3e6a3714
16 changed files with 316 additions and 52 deletions

View File

@ -88,7 +88,7 @@ public class DefaultIdentifierGeneratorFactory implements MutableIdentifierGener
register( "enhanced-sequence", SequenceStyleGenerator.class );
register( "enhanced-table", TableGenerator.class );
}
@Override
public void register(String strategy, Class generatorClass) {
LOG.debugf( "Registering IdentifierGenerator strategy [%s] -> [%s]", strategy, generatorClass.getName() );
final Class previous = generatorStrategyToClassNameMap.put( strategy, generatorClass );

View File

@ -37,6 +37,7 @@ public final class StringHelper {
private static final int ALIAS_TRUNCATE_LENGTH = 10;
public static final String WHITESPACE = " \n\r\f\t";
public static final String [] EMPTY_STRINGS = new String[0];
private StringHelper() { /* static methods only - hide constructor */
}

View File

@ -347,6 +347,14 @@ public final class ArrayHelper {
return true;
}
public static boolean isEmpty(final Object[] arrays) {
return arrays == null || arrays.length == 0;
}
public static boolean isNotEmpty(final Object[] arrays) {
return !isEmpty( arrays );
}
/**
* Compare 2 arrays only at the first level
*/

View File

@ -854,15 +854,17 @@ public class Binder {
final boolean hasPrimaryKeyJoinColumns = CollectionHelper.isNotEmpty( primaryKeyJoinColumnSources );
final List<Column> superEntityBindingPrimaryKeyColumns = superEntityBinding.getPrimaryTable().getPrimaryKey().getColumns();
for ( int i = 0; i < superEntityBindingPrimaryKeyColumns.size(); i++ ) {
for ( int i = 0, size = superEntityBindingPrimaryKeyColumns.size(); i < size; i++ ) {
Column superEntityBindingPrimaryKeyColumn = superEntityBindingPrimaryKeyColumns.get( i );
PrimaryKeyJoinColumnSource primaryKeyJoinColumnSource = hasPrimaryKeyJoinColumns && i < primaryKeyJoinColumnSources
.size() ? primaryKeyJoinColumnSources.get( i ) : null;
final String columnName;
if ( primaryKeyJoinColumnSource != null && StringHelper.isNotEmpty( primaryKeyJoinColumnSource.getColumnName() ) ) {
columnName = bindingContext().getNamingStrategy().columnName( primaryKeyJoinColumnSource.getColumnName() );
} else {
columnName = superEntityBindingPrimaryKeyColumn.getColumnName().getText();
columnName = bindingContext().getNamingStrategy()
.columnName( primaryKeyJoinColumnSource.getColumnName() );
}
else {
columnName = superEntityBindingPrimaryKeyColumn.getColumnName().getText();
}
Column column = entityBinding.getPrimaryTable().locateOrCreateColumn( columnName );
column.setCheckCondition( superEntityBindingPrimaryKeyColumn.getCheckCondition() );
@ -873,12 +875,10 @@ public class Binder {
column.setReadFragment( superEntityBindingPrimaryKeyColumn.getReadFragment() );
column.setWriteFragment( superEntityBindingPrimaryKeyColumn.getWriteFragment() );
column.setUnique( superEntityBindingPrimaryKeyColumn.isUnique() );
final String sqlType;
if(primaryKeyJoinColumnSource!=null && StringHelper.isNotEmpty( primaryKeyJoinColumnSource.getColumnDefinition() )){
sqlType = primaryKeyJoinColumnSource.getColumnDefinition();
} else {
sqlType = superEntityBindingPrimaryKeyColumn.getSqlType();
}
final String sqlType = getSqlTypeFromPrimaryKeyJoinColumnSourceIfExist(
superEntityBindingPrimaryKeyColumn,
primaryKeyJoinColumnSource
);
column.setSqlType( sqlType );
column.setSize( superEntityBindingPrimaryKeyColumn.getSize() );
column.setJdbcDataType( superEntityBindingPrimaryKeyColumn.getJdbcDataType() );
@ -889,6 +889,14 @@ public class Binder {
}
}
private String getSqlTypeFromPrimaryKeyJoinColumnSourceIfExist(Column superEntityBindingPrimaryKeyColumn, PrimaryKeyJoinColumnSource primaryKeyJoinColumnSource) {
final boolean isColumnDefOverrided = primaryKeyJoinColumnSource != null && StringHelper.isNotEmpty(
primaryKeyJoinColumnSource.getColumnDefinition()
);
return isColumnDefOverrided ? primaryKeyJoinColumnSource.getColumnDefinition() : superEntityBindingPrimaryKeyColumn
.getSqlType();
}
/**
* Binding a single entity hierarchy.
*

View File

@ -195,7 +195,7 @@ public class EntitySourceImpl implements EntitySource {
}
@Override
public List<String> getSynchronizedTableNames() {
public String[] getSynchronizedTableNames() {
return entityClass.getSynchronizedTableNames();
}

View File

@ -81,7 +81,7 @@ public class EntityClass extends ConfiguredClass {
private final String explicitEntityName;
private final String customLoaderQueryName;
private final List<String> synchronizedTableNames;
private final String[] synchronizedTableNames;
private final int batchSize;
private boolean isImmutable;
@ -215,7 +215,7 @@ public class EntityClass extends ConfiguredClass {
return customDelete;
}
public List<String> getSynchronizedTableNames() {
public String[] getSynchronizedTableNames() {
return synchronizedTableNames;
}
@ -495,16 +495,15 @@ public class EntityClass extends ConfiguredClass {
return customLoader;
}
private List<String> determineSynchronizedTableNames() {
private String[] determineSynchronizedTableNames() {
final AnnotationInstance synchronizeAnnotation = JandexHelper.getSingleAnnotation(
getClassInfo(), HibernateDotNames.SYNCHRONIZE
);
if ( synchronizeAnnotation != null ) {
final String[] tableNames = synchronizeAnnotation.value().asStringArray();
return Arrays.asList( tableNames );
return synchronizeAnnotation.value().asStringArray();
}
else {
return Collections.emptyList();
return StringHelper.EMPTY_STRINGS;
}
}

View File

@ -31,6 +31,7 @@ import java.util.Set;
import org.hibernate.EntityMode;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jaxb.spi.Origin;
import org.hibernate.jaxb.spi.hbm.EntityElement;
import org.hibernate.jaxb.spi.hbm.JaxbAnyElement;
@ -444,12 +445,18 @@ public abstract class AbstractEntitySourceImpl
}
@Override
public List<String> getSynchronizedTableNames() {
List<String> tableNames = new ArrayList<String>();
for ( JaxbSynchronizeElement synchronizeElement : entityElement.getSynchronize() ) {
tableNames.add( synchronizeElement.getTable() );
public String[] getSynchronizedTableNames() {
if ( CollectionHelper.isEmpty( entityElement.getSynchronize() ) ) {
return StringHelper.EMPTY_STRINGS;
}
else {
final int size = entityElement.getSynchronize().size();
final String[] synchronizedTableNames = new String[size];
for ( int i = 0; i < size; i++ ) {
synchronizedTableNames[i] = entityElement.getSynchronize().get( i ).getTable();
}
return synchronizedTableNames;
}
return tableNames;
}
@Override

View File

@ -34,7 +34,9 @@ import java.util.Set;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.ValueHolder;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.JoinedIterable;
import org.hibernate.internal.util.collections.JoinedIterator;
import org.hibernate.internal.util.collections.SingletonIterator;
@ -102,7 +104,7 @@ public class EntityBinding extends AbstractAttributeBindingContainer {
private CustomSQL customUpdate;
private CustomSQL customDelete;
private Set<String> synchronizedTableNames = new HashSet<String>();
private String[] synchronizedTableNames = StringHelper.EMPTY_STRINGS;
private Map<String, AttributeBinding> attributeBindingMap = new HashMap<String, AttributeBinding>();
private List<JpaCallbackSource> jpaCallbackClasses = new ArrayList<JpaCallbackSource>();
@ -435,12 +437,12 @@ public class EntityBinding extends AbstractAttributeBindingContainer {
this.isAbstract = isAbstract;
}
public Set<String> getSynchronizedTableNames() {
public String[] getSynchronizedTableNames() {
return synchronizedTableNames;
}
public void addSynchronizedTableNames(java.util.Collection<String> synchronizedTableNames) {
this.synchronizedTableNames.addAll( synchronizedTableNames );
public void addSynchronizedTableNames(String [] synchronizedTableNames) {
this.synchronizedTableNames = ArrayHelper.join( this.synchronizedTableNames, synchronizedTableNames );
}
public String getEntityName() {

View File

@ -72,11 +72,20 @@ public abstract class AbstractTableSpecification implements TableSpecification {
public Column locateColumn(String name) {
final Identifier identifier = Identifier.toIdentifier( name );
if ( valueMap.containsKey( identifier ) ) {
return (Column) valueMap.get( identifier );
Value value = valueMap.get( identifier );
return Column.class.isInstance( value ) ? Column.class.cast( value ) : null;
}
return null;
}
@Override
public boolean hasValue(Value value) {
//shortcut
if ( this != value.getTable() ) {
return false;
}
return valueMap.containsValue( value );
}
@Override
public Column createColumn(String name) {
@ -95,7 +104,10 @@ public abstract class AbstractTableSpecification implements TableSpecification {
public DerivedValue locateOrCreateDerivedValue(String fragment) {
final Identifier identifier = Identifier.toIdentifier( fragment );
if ( valueMap.containsKey( identifier ) ) {
return (DerivedValue) valueMap.get( identifier );
Value value = valueMap.get( identifier );
if ( DerivedValue.class.isInstance( value ) ) {
return DerivedValue.class.cast( value );
}
}
final DerivedValue value = new DerivedValue( this, valueList.size(), fragment );
valueMap.put( identifier, value );

View File

@ -284,6 +284,7 @@ public class Table extends AbstractTableSpecification implements Exportable {
*/
public Iterable<Column> sortedColumns() {
final Set<Column> sortedColumns = new LinkedHashSet<Column>();
// Adding primary key columns.
sortedColumns.addAll( getPrimaryKey().getColumns() );
// Adding foreign key columns.

View File

@ -41,6 +41,8 @@ public interface ValueContainer {
*/
public List<Value> values();
public boolean hasValue(Value value);
/**
* Get a qualifier which can be used to qualify {@link Value values} belonging to this container in
* their logging.

View File

@ -184,9 +184,9 @@ public interface EntitySource extends SubclassEntityContainer, AttributeSourceCo
/**
* Obtain any additional table names on which to synchronize (auto flushing) this entity.
*
* @return Additional synchronized table names.
* @return Additional synchronized table names or 0 sized String array, never return null.
*/
public List<String> getSynchronizedTableNames();
public String[] getSynchronizedTableNames();
/**
* Get the actual discriminator value in case of a single table inheritance

View File

@ -504,7 +504,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
spaces = ArrayHelper.join(
qualifiedTableNames,
ArrayHelper.toStringArray( entityBinding.getSynchronizedTableNames() )
entityBinding.getSynchronizedTableNames()
);
final boolean lazyAvailable = isInstrumented();

View File

@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import org.hibernate.AssertionFailure;
@ -52,7 +53,11 @@ import org.hibernate.mapping.Column;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Subclass;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.spi.binding.CustomSQL;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.InheritanceType;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.sql.SelectFragment;
import org.hibernate.sql.SimpleSelect;
import org.hibernate.type.StandardBasicTypes;
@ -241,6 +246,30 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
postConstruct(mapping);
}
private static class CustomSQLMetadata {
final boolean[] callable;
final String[] sqls;
final ExecuteUpdateResultCheckStyle[] checkStyles;
CustomSQLMetadata(String sql, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
this.callable = new boolean[] { callable };
this.sqls = new String[] { sql };
this.checkStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
}
}
private CustomSQLMetadata parse(CustomSQL customSql) {
final String sql = customSql.getSql();
final boolean callable = sql != null && customSql.isCallable();
final ExecuteUpdateResultCheckStyle checkStyle = sql == null
? ExecuteUpdateResultCheckStyle.COUNT
: customSql.getCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
: customSql.getCheckStyle();
return new CustomSQLMetadata( sql, callable, checkStyle );
}
@SuppressWarnings( {"UnusedDeclaration"})
public UnionSubclassEntityPersister(
final EntityBinding entityBinding,
@ -249,16 +278,122 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
final SessionFactoryImplementor factory,
final Mapping mapping) throws HibernateException {
super(entityBinding, cacheAccessStrategy, naturalIdRegionAccessStrategy, factory );
// TODO: implement!!! initializing final fields to null to make compiler happy.
subquery = null;
if ( getIdentifierGenerator() instanceof IdentityGenerator ) {
throw new MappingException(
"Cannot use identity column key generation with <union-subclass> mapping for: " +
getEntityName()
);
}
tableName = entityBinding.getPrimaryTable().getQualifiedName( factory.getDialect() );
subclassClosure = null;
spaces = null;
subclassSpaces = null;
discriminatorValue = null;
discriminatorSQLValue = null;
constraintOrderedTableNames = null;
constraintOrderedKeyColumnNames = null;
//Custom SQL
{
CustomSQLMetadata customSQLMetadata;
{
customSQLMetadata = parse( entityBinding.getCustomInsert() );
customSQLInsert = customSQLMetadata.sqls;
insertCallable = customSQLMetadata.callable;
insertResultCheckStyles = customSQLMetadata.checkStyles;
}
{
customSQLMetadata = parse( entityBinding.getCustomUpdate() );
customSQLUpdate = customSQLMetadata.sqls;
updateCallable = customSQLMetadata.callable;
updateResultCheckStyles = customSQLMetadata.checkStyles;
}
{
customSQLMetadata = parse( entityBinding.getCustomDelete() );
customSQLDelete = customSQLMetadata.sqls;
deleteCallable = customSQLMetadata.callable;
deleteResultCheckStyles = customSQLMetadata.checkStyles;
}
}
//discriminator
{
discriminatorValue = entityBinding.getSubEntityBindingId();
discriminatorSQLValue = String.valueOf( discriminatorValue );
}
// PROPERTIES
int subclassSpan = entityBinding.getSubEntityBindingClosureSpan() + 1;
subclassClosure = new String[subclassSpan];
subclassClosure[0] = getEntityName();
// SUBCLASSES
subclassByDiscriminatorValue.put(
entityBinding.getSubEntityBindingId(),
entityBinding.getEntityName()
);
if ( entityBinding.isPolymorphic() ) {
Iterable<EntityBinding> iter = entityBinding.getPreOrderSubEntityBindingClosure();
int k=1;
for(EntityBinding subEntityBinding : iter){
subclassClosure[k++] = subEntityBinding.getEntityName();
subclassByDiscriminatorValue.put( subEntityBinding.getSubEntityBindingId(), subEntityBinding.getEntityName() );
}
}
//SPACES
//TODO: i'm not sure, but perhaps we should exclude
// abstract denormalized tables?
int spacesSize = 1 + entityBinding.getSynchronizedTableNames().length;
spaces = new String[spacesSize];
spaces[0] = tableName;
String[] synchronizedTableNames = entityBinding.getSynchronizedTableNames();
System.arraycopy( synchronizedTableNames, 0, spaces, 1, spacesSize );
HashSet<String> subclassTables = new HashSet<String>();
Iterable<EntityBinding> iter = entityBinding.getPreOrderSubEntityBindingClosure();
for ( EntityBinding subEntityBinding : iter ) {
subclassTables.add( subEntityBinding.getPrimaryTable().getQualifiedName( factory.getDialect() ) );
}
subclassSpaces = ArrayHelper.toStringArray( subclassTables );
subquery = generateSubquery( entityBinding );
if ( isMultiTable() ) {
int idColumnSpan = getIdentifierColumnSpan();
ArrayList<String> tableNames = new ArrayList<String>();
ArrayList<String[]> keyColumns = new ArrayList<String[]>();
if ( !isAbstract() ) {
tableNames.add( tableName );
keyColumns.add( getIdentifierColumnNames() );
}
Iterator<EntityBinding> siter = new JoinedIterator<EntityBinding>(
new SingletonIterator<EntityBinding>( entityBinding ),
iter.iterator()
);
while ( siter.hasNext() ) {
EntityBinding eb = siter.next();
TableSpecification tab = eb.getPrimaryTable();
if ( isNotAbstractUnionTable( eb ) ) {
String tableName = tab.getQualifiedName( factory.getDialect() );
tableNames.add( tableName );
String[] key = new String[idColumnSpan];
List<org.hibernate.metamodel.spi.relational.Column> columns = tab.getPrimaryKey().getColumns();
for ( int k = 0; k < idColumnSpan; k++ ) {
key[k] = columns.get( k ).getColumnName().getText( factory.getDialect() );
}
keyColumns.add( key );
}
}
constraintOrderedTableNames = ArrayHelper.toStringArray( tableNames );
constraintOrderedKeyColumnNames = ArrayHelper.to2DStringArray( keyColumns );
}
else {
constraintOrderedTableNames = new String[] { tableName };
constraintOrderedKeyColumnNames = new String[][] { getIdentifierColumnNames() };
}
initLockers();
initSubclassPropertyAliasesMap(entityBinding);
postConstruct(mapping);
}
public Serializable[] getQuerySpaces() {
@ -407,6 +542,78 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
return new int[ getPropertySpan() ];
}
private boolean isNotAbstractUnionTable(EntityBinding entityBinding) {
return !entityBinding.isAbstract() && entityBinding.getHierarchyDetails()
.getInheritanceType() != InheritanceType.TABLE_PER_CLASS;
}
protected String generateSubquery(EntityBinding entityBinding){
Dialect dialect = getFactory().getDialect();
Settings settings = getFactory().getSettings();
if ( !entityBinding.hasSubEntityBindings() ) {
return entityBinding.getPrimaryTable().getQualifiedName( dialect );
}
HashSet<org.hibernate.metamodel.spi.relational.Column> columns = new LinkedHashSet<org.hibernate.metamodel.spi.relational.Column>();
Iterable<EntityBinding> subEntityBindings = entityBinding.getPreOrderSubEntityBindingClosure();
Iterator<EntityBinding> siter = new JoinedIterator<EntityBinding>(
new SingletonIterator<EntityBinding>(entityBinding),
subEntityBindings.iterator()
);
while ( siter.hasNext() ) {
EntityBinding eb = siter.next();
if ( isNotAbstractUnionTable( eb ) ) {
TableSpecification table = entityBinding.getPrimaryTable();
for ( Value v : table.values() ) {
if ( org.hibernate.metamodel.spi.relational.Column.class.isInstance( v ) ) {
columns.add( org.hibernate.metamodel.spi.relational.Column.class.cast( v ) );
}
}
}
}
StringBuilder buf = new StringBuilder()
.append("( ");
siter = new JoinedIterator<EntityBinding>(
new SingletonIterator<EntityBinding>(entityBinding),
subEntityBindings.iterator()
);
while ( siter.hasNext() ) {
EntityBinding eb = siter.next();
TableSpecification table = eb.getPrimaryTable();
if ( isNotAbstractUnionTable( eb )) {
//TODO: move to .sql package!!
buf.append("select ");
for(org.hibernate.metamodel.spi.relational.Column column : columns){
if(!table.hasValue( column )){
buf.append( dialect.getSelectClauseNullString(column.getJdbcDataType().getTypeCode()) )
.append(" as ");
}
buf.append( column.getColumnName().getText( dialect ) );
buf.append( ", " );
}
buf.append( eb.getSubEntityBindingId() )
.append( " as clazz_" );
buf.append(" from ")
.append( table.getQualifiedName( dialect ));
buf.append(" union ");
if ( dialect.supportsUnionAll() ) {
buf.append("all ");
}
}
}
if ( buf.length() > 2 ) {
//chop the last union (all)
buf.setLength( buf.length() - ( dialect.supportsUnionAll() ? 11 : 7 ) );
}
return buf.append(" )").toString();
}
protected String generateSubquery(PersistentClass model, Mapping mapping) {
Dialect dialect = getFactory().getDialect();
@ -426,7 +633,9 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
Table table = (Table) titer.next();
if ( !table.isAbstractUnionTable() ) {
Iterator citer = table.getColumnIterator();
while ( citer.hasNext() ) columns.add( citer.next() );
while ( citer.hasNext() ) {
columns.add( citer.next() );
}
}
}
@ -479,12 +688,16 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
}
protected String[] getSubclassTableKeyColumns(int j) {
if (j!=0) throw new AssertionFailure("only one table");
if ( j != 0 ) {
throw new AssertionFailure( "only one table" );
}
return getIdentifierColumnNames();
}
public String getSubclassTableName(int j) {
if (j!=0) throw new AssertionFailure("only one table");
if ( j != 0 ) {
throw new AssertionFailure( "only one table" );
}
return tableName;
}
@ -493,7 +706,9 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
}
protected boolean isClassOrSuperclassTable(int j) {
if (j!=0) throw new AssertionFailure("only one table");
if ( j != 0 ) {
throw new AssertionFailure( "only one table" );
}
return true;
}

View File

@ -32,6 +32,7 @@ import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.id.EntityIdentifierNature;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.internal.MetadataBuilderImpl;
@ -119,8 +120,7 @@ public class AssertSourcesTest extends BaseUnitTestCase {
assertFalse( entitySource.getSecondaryTables().iterator().hasNext() );
assertTrue(
entitySource.getSynchronizedTableNames() == null
|| entitySource.getSynchronizedTableNames().isEmpty()
ArrayHelper.isEmpty( entitySource.getSynchronizedTableNames() )
);
IdentifierSource identifierSource = entitySource.getIdentifierSource();

View File

@ -47,17 +47,26 @@ public class SynchronizeBindingTest extends BaseAnnotationBindingTestCase {
@Resources(annotatedClasses = TestEntityWithSynchronizeAnnotation.class)
public void testSynchronizeAnnotation() {
EntityBinding binding = getEntityBinding( TestEntityWithSynchronizeAnnotation.class );
Set<String> synchronizedTableNames = binding.getSynchronizedTableNames();
assertEquals( "Wrong number of synced tables", 2, synchronizedTableNames.size() );
assertTrue( "Table name missing", synchronizedTableNames.contains( "Foo" ) );
assertTrue( "Table name missing", synchronizedTableNames.contains( "Bar" ) );
String [] synchronizedTableNames = binding.getSynchronizedTableNames();
assertEquals( "Wrong number of synced tables", 2, synchronizedTableNames.length );
assertTrue( "Table name missing", contains( synchronizedTableNames, "Foo" ) );
assertTrue( "Table name missing", contains( synchronizedTableNames, "Bar" ) );
}
private boolean contains(String[] arrays, String key) {
for ( String s : arrays ) {
if ( key.equals( s ) ) {
return true;
}
}
return false;
}
@Test
@Resources(annotatedClasses = TestEntity.class)
public void testNoSynchronizeAnnotation() {
EntityBinding binding = getEntityBinding( TestEntity.class );
assertTrue( "There should be no cache binding", binding.getSynchronizedTableNames().size() == 0 );
assertTrue( "There should be no cache binding", binding.getSynchronizedTableNames().length == 0 );
}
@Entity