merge master

This commit is contained in:
Strong Liu 2013-05-06 22:55:00 +08:00
commit b9249e548a
1412 changed files with 65170 additions and 48984 deletions

View File

@ -8,18 +8,20 @@ contributing to a minimum, there are a few guidelines we ask that you mind.
If you are just getting started with Git, GitHub and/or contributing to Hibernate via
GitHub there are a few pre-requisite steps.
* Make sure you have signed a [Contributor License Aggrement](https://cla.jboss.org) (CLA) for the Hibernate project
* Make sure you have a [Hibernate Jira account](https://hibernate.onjira.com)
* Make sure you have a [GitHub account](https://github.com/signup/free)
* [Fork](http://help.github.com/fork-a-repo) the Hibernate repository. As discussed in
the linked page, this also includes:
* [Set](https://help.github.com/articles/set-up-git) up your local git install
* Clone your fork
* See the wiki pages for setting up your IDE, whether you use [IntelliJ IDEA](https://community.jboss.org/wiki/ContributingToHibernateUsingIntelliJ)
or [Eclipse](https://community.jboss.org/wiki/ContributingToHibernateUsingEclipse).
## Create the working (topic) branch
Create a "topic" branch on which you will work. The convention is to name the branch
using the JIRA issue key. If there is not already a Jira issue covering the work you
want to do, create one. Assuming you will be working from the master branch and working
Create a [topic branch](http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches) on which you
will work. The convention is to name the branch using the JIRA issue key. If there is not already a Jira issue
covering the work you want to do, create one. Assuming you will be working from the master branch and working
on the Jira HHH-123 : `git checkout -b HHH-123 master`
@ -39,7 +41,7 @@ appreciated btw), please use rebasing rather than merging. Merging creates
"merge commits" that really muck up the project timeline._
## Submit
* Sign the [Contributor License Agreement](https://cla.jboss.org/index.seam).
* Push your changes to a topic branch in your fork of the repository.
* If you have not already, sign the [Contributor License Agreement](https://cla.jboss.org).
* Push your changes to the topic branch in your fork of the repository.
* Initiate a [pull request](http://help.github.com/send-pull-requests/)
* Update the Jira issue, adding a comment inclusing a link to the created pull request

View File

@ -348,14 +348,30 @@ subprojects { subProject ->
ignoreFailures = true
}
// exclude generated sources
checkstyleMain.exclude '**/generated-src/**'
// unfortunately this nice easy approach does not seem to work : http://forums.gradle.org/gradle/topics/specify_excludes_to_checkstyle_task
//checkstyleMain.exclude '**/generated-src/**'
checkstyleMain.exclude '**/org/hibernate/hql/internal/antlr/**'
checkstyleMain.exclude '**/org/hibernate/hql/internal/antlr/*'
checkstyleMain.exclude '**/org/hibernate/sql/ordering/antlr/*'
checkstyleMain.exclude '**/*_$logger*'
checkstyleMain.exclude '**/org/hibernate/internal/jaxb/**'
// because cfg package is a mess mainly from annotation stuff
checkstyleMain.exclude '**/org/hibernate/cfg/**'
checkstyleMain.exclude '**/org/hibernate/cfg/*'
findbugs {
sourceSets = [ subProject.sourceSets.main, subProject.sourceSets.test ]
ignoreFailures = true
}
// exclude generated sources
// unfortunately this nice easy approach does not seem to work : http://forums.gradle.org/gradle/topics/specify_excludes_to_checkstyle_task
//findbugsMain.exclude '**/generated-src/**'
findbugsMain.exclude '**/org/hibernate/hql/internal/antlr/**'
findbugsMain.exclude '**/org/hibernate/hql/internal/antlr/*'
findbugsMain.exclude '**/org/hibernate/sql/ordering/antlr/*'
findbugsMain.exclude '**/*_$logger*'
findbugsMain.exclude '**/org/hibernate/internal/jaxb/**'
buildDashboard.dependsOn check
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -129,7 +129,10 @@ public class Jdk {
try {
final File javaCommand = getJavaExecutable();
Process javaProcess = Runtime.getRuntime().exec( javaCommand.getAbsolutePath() + " -version" );
// Fix build for e.g. windows when path to java command contains spaces
// Using the array for Runtime.exec will make sure that arguments with spaces get quoted
Process javaProcess = Runtime.getRuntime().exec( new String[]{javaCommand.getAbsolutePath(), "-version"} );
try {
version = extractVersion( new BufferedReader( new InputStreamReader( javaProcess.getErrorStream() ) ) );

View File

@ -5,6 +5,68 @@ match the actual issue resolution (i.e. a bug might not be a bug). Please
refer to the particular case on JIRA using the issue tracking number to learn
more about each case.
Changes in version 4.3.0.Beta2 (2013.05.02)
------------------------------------------------------------------------------------------------------------------------
https://hibernate.atlassian.net/browse/HHH/fixforversion/13052
** Sub-task
* [HHH-7617] - Gradle eclipse task missing src paths and test source generation
* [HHH-7943] - C3P0, Proxool, ehcache, and infinispan services for OSGi
* [HHH-7944] - Envers OSGi support
* [HHH-7993] - Support jar scanning in OSGi
* [HHH-7995] - Auto-discovery of Hibernate extension points in OSGi
* [HHH-8141] - Upgrade to Gradle 1.5
* [HHH-8142] - Create a 'compile' task that performs all copmpilations
* [HHH-8143] - Create a 'generateSources' task that performs all generation tasks
* [HHH-8145] - Add MaxPermSize to test configuration
* [HHH-8146] - Update to use maven-publishing plugin
* [HHH-8147] - Update to use distribution plugin for createing release bundles
* [HHH-8151] - Consolidate defining "java language level" in one place
* [HHH-8152] - General cleanup
* [HHH-8156] - Apply new Gradle plugins
* [HHH-8160] - Integrate with Aries JPA 2.1 branch
** Bug
* [HHH-5845] - Lazy Loading of audited entites with revision type 'delete'
* [HHH-7357] - Incorrect exception translation when using Oracle
* [HHH-7478] - ConcurrentModificationException when adding a BeforeTransactionCompletionProcess from with a PostInsertEventListener for an @Audited entity
* [HHH-7880] - SessionFactory.openStatelessSession() does not respect tenant identifier from CurrentTenantIdentifierResolver
* [HHH-7974] - Session.getTenantIdentifier() not callable without active transaction
* [HHH-8049] - Initialization error with <dynamic-component> mapping
* [HHH-8084] - LobMergeTest fails on oracle
* [HHH-8103] - Oracle LOB ordering not working with SequenceIdentityGenerator
* [HHH-8137] - Javadoc generation is currently not playing nicely with Java7 javadoc changes
* [HHH-8171] - Auditing of collections of embeddables only supporting single element changes
* [HHH-8173] - AvailableSettings constants for javax.persistence.schema-generation contain space
* [HHH-8178] - Natural IDs generating one UniqueKey per Column
* [HHH-8182] - Correct intermittent UpgradeLockTest failures
* [HHH-8189] - Audit records are not rolled back when transaction is rolled back
* [HHH-8207] - Locale conversion is broken
* [HHH-8215] - Windows Build with Eclipse does not work
** Deprecation
* [HHH-8170] - Deprecate Hibernate @ForeignKey in favor of JPA 2.1 introduced @ForeignKey annotation
** Improvement
* [HHH-7605] - Provide details "An entity copy was already assigned to a different entity."
* [HHH-7908] - Logging level checking.
* [HHH-8138] - Log SQLException in DatabaseTarget with cause of schema export CREATE statement failure
* [HHH-8159] - Apply fixups indicated by analysis tools
* [HHH-8162] - Make unique constraint handling on schema update configurable
* [HHH-8167] - Adding @NotNull to a @ManyToOne association with @JoinColumnsOrFormulas leads to ClassCastException
* [HHH-8180] - Improve performance of logging level checks
* [HHH-8183] - Also support synonyms for schema validation
** New Feature
* [HHH-8157] - Adding DBAllocator labels for new DBs
* [HHH-8163] - Deprecate @IndexColumn and add @ListIndexBase
** Task
* [HHH-8164] - Deprecate @Sort in favor of @SortNatural and @SortComparator
* [HHH-8175] - Add support for Postgresql 9.2, Postgres Plus 9.2 and IBM DB2 10.1
* [HHH-8186] - Type in docs? Caching section nonstrict != nontrict
* [HHH-8212] - Add CLA ref to CONTRIBUTING.md
Changes in version 4.3.0.Beta1 (2012.07.12)
------------------------------------------------------------------------------------------------------------------------

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.service.jdbc.connections.internal;
package org.hibernate.c3p0.internal;
import java.sql.Connection;
import java.sql.SQLException;
@ -31,6 +31,7 @@ import java.util.Properties;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.DataSources;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
@ -56,22 +57,25 @@ import org.hibernate.service.spi.Stoppable;
public class C3P0ConnectionProvider
implements ConnectionProvider, Configurable, Stoppable, ServiceRegistryAwareService {
private static final C3P0MessageLogger LOG = Logger.getMessageLogger(C3P0MessageLogger.class, C3P0ConnectionProvider.class.getName());
private static final C3P0MessageLogger LOG = Logger.getMessageLogger(
C3P0MessageLogger.class,
C3P0ConnectionProvider.class.getName()
);
//swaldman 2006-08-28: define c3p0-style configuration parameters for properties with
// hibernate-specific overrides to detect and warn about conflicting
// declarations
private final static String C3P0_STYLE_MIN_POOL_SIZE = "c3p0.minPoolSize";
private final static String C3P0_STYLE_MAX_POOL_SIZE = "c3p0.maxPoolSize";
private final static String C3P0_STYLE_MAX_IDLE_TIME = "c3p0.maxIdleTime";
private final static String C3P0_STYLE_MAX_STATEMENTS = "c3p0.maxStatements";
private final static String C3P0_STYLE_ACQUIRE_INCREMENT = "c3p0.acquireIncrement";
private final static String C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD = "c3p0.idleConnectionTestPeriod";
private static final String C3P0_STYLE_MIN_POOL_SIZE = "c3p0.minPoolSize";
private static final String C3P0_STYLE_MAX_POOL_SIZE = "c3p0.maxPoolSize";
private static final String C3P0_STYLE_MAX_IDLE_TIME = "c3p0.maxIdleTime";
private static final String C3P0_STYLE_MAX_STATEMENTS = "c3p0.maxStatements";
private static final String C3P0_STYLE_ACQUIRE_INCREMENT = "c3p0.acquireIncrement";
private static final String C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD = "c3p0.idleConnectionTestPeriod";
//swaldman 2006-08-28: define c3p0-style configuration parameters for initialPoolSize, which
// hibernate sensibly lets default to minPoolSize, but we'll let users
// override it with the c3p0-style property if they want.
private final static String C3P0_STYLE_INITIAL_POOL_SIZE = "c3p0.initialPoolSize";
private static final String C3P0_STYLE_INITIAL_POOL_SIZE = "c3p0.initialPoolSize";
private DataSource ds;
private Integer isolation;
@ -105,7 +109,7 @@ public class C3P0ConnectionProvider
}
@Override
@SuppressWarnings( {"unchecked"})
@SuppressWarnings({"unchecked"})
public <T> T unwrap(Class<T> unwrapType) {
if ( ConnectionProvider.class.equals( unwrapType ) ||
C3P0ConnectionProvider.class.isAssignableFrom( unwrapType ) ) {
@ -120,46 +124,46 @@ public class C3P0ConnectionProvider
}
@Override
@SuppressWarnings( {"unchecked"})
@SuppressWarnings({"unchecked"})
public void configure(Map props) {
String jdbcDriverClass = (String) props.get( Environment.DRIVER );
String jdbcUrl = (String) props.get( Environment.URL );
Properties connectionProps = ConnectionProviderInitiator.getConnectionProperties( props );
final String jdbcDriverClass = (String) props.get( Environment.DRIVER );
final String jdbcUrl = (String) props.get( Environment.URL );
final Properties connectionProps = ConnectionProviderInitiator.getConnectionProperties( props );
LOG.c3p0UsingDriver(jdbcDriverClass, jdbcUrl);
LOG.connectionProperties(ConfigurationHelper.maskOut(connectionProps, "password"));
LOG.c3p0UsingDriver( jdbcDriverClass, jdbcUrl );
LOG.connectionProperties( ConfigurationHelper.maskOut( connectionProps, "password" ) );
autocommit = ConfigurationHelper.getBoolean( Environment.AUTOCOMMIT, props );
LOG.autoCommitMode( autocommit );
if (jdbcDriverClass == null) {
LOG.jdbcDriverNotSpecified(Environment.DRIVER);
if ( jdbcDriverClass == null ) {
LOG.jdbcDriverNotSpecified( Environment.DRIVER );
}
else {
try {
serviceRegistry.getService( ClassLoaderService.class ).classForName( jdbcDriverClass );
}
catch ( ClassLoadingException e ) {
throw new ClassLoadingException( LOG.jdbcDriverNotFound(jdbcDriverClass), e );
catch (ClassLoadingException e) {
throw new ClassLoadingException( LOG.jdbcDriverNotFound( jdbcDriverClass ), e );
}
}
try {
//swaldman 2004-02-07: modify to allow null values to signify fall through to c3p0 PoolConfig defaults
Integer minPoolSize = ConfigurationHelper.getInteger( Environment.C3P0_MIN_SIZE, props );
Integer maxPoolSize = ConfigurationHelper.getInteger( Environment.C3P0_MAX_SIZE, props );
Integer maxIdleTime = ConfigurationHelper.getInteger( Environment.C3P0_TIMEOUT, props );
Integer maxStatements = ConfigurationHelper.getInteger( Environment.C3P0_MAX_STATEMENTS, props );
Integer acquireIncrement = ConfigurationHelper.getInteger( Environment.C3P0_ACQUIRE_INCREMENT, props );
Integer idleTestPeriod = ConfigurationHelper.getInteger( Environment.C3P0_IDLE_TEST_PERIOD, props );
final Integer minPoolSize = ConfigurationHelper.getInteger( Environment.C3P0_MIN_SIZE, props );
final Integer maxPoolSize = ConfigurationHelper.getInteger( Environment.C3P0_MAX_SIZE, props );
final Integer maxIdleTime = ConfigurationHelper.getInteger( Environment.C3P0_TIMEOUT, props );
final Integer maxStatements = ConfigurationHelper.getInteger( Environment.C3P0_MAX_STATEMENTS, props );
final Integer acquireIncrement = ConfigurationHelper.getInteger( Environment.C3P0_ACQUIRE_INCREMENT, props );
final Integer idleTestPeriod = ConfigurationHelper.getInteger( Environment.C3P0_IDLE_TEST_PERIOD, props );
Properties c3props = new Properties();
final Properties c3props = new Properties();
// turn hibernate.c3p0.* into c3p0.*, so c3p0
// gets a chance to see all hibernate.c3p0.*
for ( Object o : props.keySet() ) {
if ( ! String.class.isInstance( o ) ) {
if ( !String.class.isInstance( o ) ) {
continue;
}
final String key = (String) o;
@ -182,63 +186,62 @@ public class C3P0ConnectionProvider
Environment.C3P0_ACQUIRE_INCREMENT, C3P0_STYLE_ACQUIRE_INCREMENT, props, c3props, acquireIncrement
);
setOverwriteProperty(
Environment.C3P0_IDLE_TEST_PERIOD, C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD, props, c3props, idleTestPeriod
Environment.C3P0_IDLE_TEST_PERIOD,
C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD,
props,
c3props,
idleTestPeriod
);
// revert to traditional hibernate behavior of setting initialPoolSize to minPoolSize
// unless otherwise specified with a c3p0.*-style parameter.
Integer initialPoolSize = ConfigurationHelper.getInteger( C3P0_STYLE_INITIAL_POOL_SIZE, props );
final Integer initialPoolSize = ConfigurationHelper.getInteger( C3P0_STYLE_INITIAL_POOL_SIZE, props );
if ( initialPoolSize == null && minPoolSize != null ) {
c3props.put( C3P0_STYLE_INITIAL_POOL_SIZE, String.valueOf( minPoolSize ).trim() );
}
/*DataSource unpooled = DataSources.unpooledDataSource(
jdbcUrl, props.getProperty(Environment.USER), props.getProperty(Environment.PASS)
);*/
DataSource unpooled = DataSources.unpooledDataSource( jdbcUrl, connectionProps );
final DataSource unpooled = DataSources.unpooledDataSource( jdbcUrl, connectionProps );
Map allProps = new HashMap();
final Map allProps = new HashMap();
allProps.putAll( props );
allProps.putAll( c3props );
ds = DataSources.pooledDataSource( unpooled, allProps );
}
catch ( Exception e ) {
LOG.error(LOG.unableToInstantiateC3p0ConnectionPool(), e);
throw new HibernateException(LOG.unableToInstantiateC3p0ConnectionPool(), e);
catch (Exception e) {
LOG.error( LOG.unableToInstantiateC3p0ConnectionPool(), e );
throw new HibernateException( LOG.unableToInstantiateC3p0ConnectionPool(), e );
}
String i = (String) props.get( Environment.ISOLATION );
if (i == null) isolation = null;
final String i = (String) props.get( Environment.ISOLATION );
if ( i == null ) {
isolation = null;
}
else {
isolation = Integer.valueOf( i );
LOG.jdbcIsolationLevel(Environment.isolationLevelToString(isolation));
LOG.jdbcIsolationLevel( Environment.isolationLevelToString( isolation ) );
}
}
public void close() {
try {
DataSources.destroy( ds );
}
catch ( SQLException sqle ) {
LOG.unableToDestroyC3p0ConnectionPool(sqle);
}
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
private void setOverwriteProperty(String hibernateStyleKey, String c3p0StyleKey, Map hibp, Properties c3p, Integer value) {
private void setOverwriteProperty(
String hibernateStyleKey,
String c3p0StyleKey,
Map hibp,
Properties c3p,
Integer value) {
if ( value != null ) {
String peeledC3p0Key = c3p0StyleKey.substring(5);
final String peeledC3p0Key = c3p0StyleKey.substring( 5 );
c3p.put( peeledC3p0Key, String.valueOf( value ).trim() );
if ( hibp.containsKey( c3p0StyleKey ) ) {
warnPropertyConflict( hibernateStyleKey, c3p0StyleKey );
}
String longC3p0StyleKey = "hibernate." + c3p0StyleKey;
final String longC3p0StyleKey = "hibernate." + c3p0StyleKey;
if ( hibp.containsKey( longC3p0StyleKey ) ) {
warnPropertyConflict( hibernateStyleKey, longC3p0StyleKey );
}
@ -246,12 +249,27 @@ public class C3P0ConnectionProvider
}
private void warnPropertyConflict(String hibernateStyle, String c3p0Style) {
LOG.bothHibernateAndC3p0StylesSet(hibernateStyle, c3p0Style, hibernateStyle, c3p0Style);
LOG.bothHibernateAndC3p0StylesSet( hibernateStyle, c3p0Style );
}
@Override
public void stop() {
close();
try {
DataSources.destroy( ds );
}
catch (SQLException sqle) {
LOG.unableToDestroyC3p0ConnectionPool( sqle );
}
}
/**
* Close the provider.
*
* @deprecated Use {@link #stop} instead
*/
@Deprecated
public void close() {
stop();
}
@Override

View File

@ -0,0 +1,94 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.c3p0.internal;
import java.sql.SQLException;
import org.jboss.logging.Cause;
import org.jboss.logging.LogMessage;
import org.jboss.logging.Message;
import org.jboss.logging.MessageLogger;
import org.hibernate.internal.CoreMessageLogger;
import static org.jboss.logging.Logger.Level.INFO;
import static org.jboss.logging.Logger.Level.WARN;
/**
* The jboss-logging {@link MessageLogger} for the hibernate-c3p0 module. It reserves message ids ranging from
* 10001 to 15000 inclusively.
* <p/>
* New messages must be added after the last message defined to ensure message codes are unique.
*/
@MessageLogger(projectCode = "HHH")
public interface C3P0MessageLogger extends CoreMessageLogger {
/**
* Log a message (WARN) about conflicting {@code hibernate.c3p0.XYZ} and {@code c3p0.XYZ} settings
*
* @param hibernateStyle The {@code hibernate.c3p0} prefixed setting
* @param c3p0Style The {@code c3p0.} prefixed setting
*/
@LogMessage(level = WARN)
@Message(value = "Both hibernate-style property '%1$s' and c3p0-style property '%2$s' have been set in Hibernate "
+ "properties. Hibernate-style property '%1$s' will be used and c3p0-style property '%2$s' will be ignored!", id = 10001)
void bothHibernateAndC3p0StylesSet(String hibernateStyle,String c3p0Style);
/**
* Log a message (INFO) about which Driver class is being used.
*
* @param jdbcDriverClass The JDBC Driver class
* @param jdbcUrl The JDBC URL
*/
@LogMessage(level = INFO)
@Message(value = "C3P0 using driver: %s at URL: %s", id = 10002)
void c3p0UsingDriver(String jdbcDriverClass, String jdbcUrl);
/**
* Build a message about not being able to find the JDBC driver class
*
* @param jdbcDriverClass The JDBC driver class we could not find
*
* @return The message
*/
@Message(value = "JDBC Driver class not found: %s", id = 10003)
String jdbcDriverNotFound(String jdbcDriverClass);
/**
* Log a message (WARN) about not being able to stop the underlying c3p0 pool.
*
* @param e The exception when we tried to stop pool
*/
@LogMessage(level = WARN)
@Message(value = "Could not destroy C3P0 connection pool", id = 10004)
void unableToDestroyC3p0ConnectionPool(@Cause SQLException e);
/**
* Build a message about not being able to start the underlying c3p0 pool.
*
* @return The message
*/
@Message(value = "Could not instantiate C3P0 connection pool", id = 10005)
String unableToInstantiateC3p0ConnectionPool();
}

View File

@ -0,0 +1,59 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.c3p0.internal;
import java.util.Collections;
import java.util.List;
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
import org.hibernate.boot.registry.selector.StrategyRegistration;
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
/**
* Provides the {@link C3P0ConnectionProvider} to the
* {@link org.hibernate.boot.registry.selector.spi.StrategySelector} service.
*
* @author Brett Meyer
*/
public class StrategyRegistrationProviderImpl implements StrategyRegistrationProvider {
private static final List<StrategyRegistration> REGISTRATIONS = Collections.singletonList(
(StrategyRegistration) new SimpleStrategyRegistrationImpl<ConnectionProvider>(
ConnectionProvider.class,
C3P0ConnectionProvider.class,
"c3p0",
C3P0ConnectionProvider.class.getSimpleName(),
// legacy
"org.hibernate.connection.C3P0ConnectionProvider",
// legacy
"org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider"
)
);
@Override
@SuppressWarnings("unchecked")
public Iterable<StrategyRegistration> getStrategyRegistrations() {
return REGISTRATIONS;
}
}

View File

@ -0,0 +1,4 @@
/**
* Implementation of ConnectionProvider using the c3p0 Connection pool.
*/
package org.hibernate.c3p0.internal;

View File

@ -1,69 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.service.jdbc.connections.internal;
import java.sql.SQLException;
import org.jboss.logging.Cause;
import org.jboss.logging.LogMessage;
import org.jboss.logging.Message;
import org.jboss.logging.MessageLogger;
import org.hibernate.internal.CoreMessageLogger;
import static org.jboss.logging.Logger.Level.INFO;
import static org.jboss.logging.Logger.Level.WARN;
/**
* The jboss-logging {@link MessageLogger} for the hibernate-c3p0 module. It reserves message ids ranging from
* 10001 to 15000 inclusively.
* <p/>
* New messages must be added after the last message defined to ensure message codes are unique.
*/
@MessageLogger( projectCode = "HHH" )
public interface C3P0MessageLogger extends CoreMessageLogger {
@LogMessage( level = WARN )
@Message( value = "Both hibernate-style property '%s' and c3p0-style property '%s' have been set in hibernate.properties. "
+ "Hibernate-style property '%s' will be used and c3p0-style property '%s' will be ignored!", id = 10001 )
void bothHibernateAndC3p0StylesSet( String hibernateStyle,
String c3p0Style,
String hibernateStyle2,
String c3p0Style2 );
@LogMessage( level = INFO )
@Message( value = "C3P0 using driver: %s at URL: %s", id = 10002 )
void c3p0UsingDriver( String jdbcDriverClass,
String jdbcUrl );
@Message( value = "JDBC Driver class not found: %s", id = 10003 )
String jdbcDriverNotFound( String jdbcDriverClass );
@LogMessage( level = WARN )
@Message( value = "Could not destroy C3P0 connection pool", id = 10004 )
void unableToDestroyC3p0ConnectionPool( @Cause SQLException e );
@Message( value = "Could not instantiate C3P0 connection pool", id = 10005 )
String unableToInstantiateC3p0ConnectionPool();
}

View File

@ -0,0 +1 @@
org.hibernate.c3p0.internal.StrategyRegistrationProviderImpl

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<blueprint default-activation="eager"
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<bean id="strategyRegistrationProvider" class="org.hibernate.c3p0.internal.StrategyRegistrationProviderImpl"/>
<service ref="strategyRegistrationProvider" interface="org.hibernate.boot.registry.selector.StrategyRegistrationProvider"/>
</blueprint>

View File

@ -30,8 +30,8 @@ import javax.management.ObjectName;
import org.junit.Test;
import org.hibernate.c3p0.internal.C3P0ConnectionProvider;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;

View File

@ -23,15 +23,11 @@
*/
package org.hibernate;
import org.jboss.logging.Logger;
/**
* A problem occurred translating a Hibernate query to SQL due to invalid query syntax, etc.
*/
public class QueryException extends HibernateException {
private static final Logger log = Logger.getLogger( QueryException.class );
private String queryString;
private final String queryString;
/**
* Constructs a QueryException using the specified exception message.
@ -39,7 +35,7 @@ public class QueryException extends HibernateException {
* @param message A message explaining the exception condition
*/
public QueryException(String message) {
super( message );
this( message, null, null );
}
/**
@ -48,8 +44,8 @@ public class QueryException extends HibernateException {
* @param message A message explaining the exception condition
* @param cause The underlying cause
*/
public QueryException(String message, Throwable cause) {
super( message, cause );
public QueryException(String message, Exception cause) {
this( message, null, cause );
}
/**
@ -59,7 +55,18 @@ public class QueryException extends HibernateException {
* @param queryString The query being evaluated when the exception occurred
*/
public QueryException(String message, String queryString) {
super( message );
this( message, queryString, null );
}
/**
* Constructs a QueryException using the specified exception message and query-string.
*
* @param message A message explaining the exception condition
* @param queryString The query being evaluated when the exception occurred
* @param cause The underlying cause
*/
public QueryException(String message, String queryString, Exception cause) {
super( message, cause );
this.queryString = queryString;
}
@ -69,7 +76,7 @@ public class QueryException extends HibernateException {
* @param cause The underlying cause
*/
public QueryException(Exception cause) {
super( cause );
this( "A query exception occurred", null, cause );
}
/**
@ -81,30 +88,52 @@ public class QueryException extends HibernateException {
return queryString;
}
/**
* Set the query string. Even an option since often the part of the code generating the exception does not
* have access to the query overall.
*
* @param queryString The query string.
*/
public void setQueryString(String queryString) {
if ( this.queryString != null ) {
log.debugf(
"queryString overriding non-null previous value [%s] : %s",
this.queryString,
queryString
);
}
this.queryString = queryString;
}
@Override
public String getMessage() {
String msg = super.getMessage();
if ( queryString!=null ) {
String msg = getOriginalMessage();
if ( queryString != null ) {
msg += " [" + queryString + ']';
}
return msg;
}
protected final String getOriginalMessage() {
return super.getMessage();
}
/**
* Wraps this exception with another, of same kind, with the specified queryString. If this exception already
* has a queryString defined, the same exception ({@code this}) is returned. Otherwise the protected
* {@link #generateQueryException(String)} is called, to allow subclasses to properly create the correct
* subclass for return.
*
* @param queryString The query string that led to the QueryException
*
* @return {@code this}, if {@code this} has {@code null} for {@link #getQueryString()}; otherwise a new
* QueryException (or subclass) is returned.
*/
public final QueryException wrapWithQueryString(String queryString) {
if ( this.getQueryString() != null ) {
return this;
}
return generateQueryException( queryString );
}
/**
* Called from {@link #wrapWithQueryString(String)} when we really need to generate a new QueryException
* (or subclass).
* <p/>
* NOTE : implementors should take care to use {@link #getOriginalMessage()} for the message, not
* {@link #getMessage()}
*
* @param queryString The query string
*
* @return The generated QueryException (or subclass)
*
* @see #getOriginalMessage()
*/
protected QueryException generateQueryException(String queryString) {
return new QueryException( getOriginalMessage(), queryString, this );
}
}

View File

@ -37,4 +37,20 @@ public class QueryParameterException extends QueryException {
public QueryParameterException(String message) {
super( message );
}
/**
* Constructs a QueryParameterException
*
* @param message The message explaining the exception condition
* @param queryString The query that led to the exception
* @param cause The underlying cause
*/
public QueryParameterException(String message, String queryString, Exception cause) {
super( message, queryString, cause );
}
@Override
protected QueryException generateQueryException(String queryString) {
return new QueryParameterException( super.getOriginalMessage(), queryString, this );
}
}

View File

@ -217,7 +217,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
// nothing to do
}
private static class EntityCleanup {
private static class EntityCleanup implements Serializable {
private final EntityRegionAccessStrategy cacheAccess;
private final SoftLock cacheLock;
@ -232,7 +232,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
}
}
private static class CollectionCleanup {
private static class CollectionCleanup implements Serializable {
private final CollectionRegionAccessStrategy cacheAccess;
private final SoftLock cacheLock;
@ -247,7 +247,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
}
}
private class NaturalIdCleanup {
private static class NaturalIdCleanup implements Serializable {
private final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy;
private final SoftLock cacheLock;

View File

@ -48,7 +48,6 @@ import org.hibernate.persister.entity.EntityPersister;
* @see EntityIdentityInsertAction
*/
public final class EntityInsertAction extends AbstractEntityInsertAction {
private Object version;
private Object cacheEntry;
@ -130,7 +129,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
version,
session
);
cacheEntry = persister.getCacheEntryStructure().structure(ce);
cacheEntry = persister.getCacheEntryStructure().structure( ce );
final CacheKey ck = session.generateCacheKey( id, persister.getIdentifierType(), persister.getRootEntityName() );
final boolean put = persister.getCacheAccessStrategy().insert( ck, cacheEntry, version );

View File

@ -32,8 +32,8 @@ import java.util.Set;
import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl;
import org.hibernate.boot.registry.selector.Availability;
import org.hibernate.boot.registry.selector.AvailabilityAnnouncer;
import org.hibernate.boot.registry.selector.StrategyRegistration;
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
import org.hibernate.boot.registry.selector.internal.StrategySelectorBuilder;
import org.hibernate.integrator.internal.IntegratorServiceImpl;
import org.hibernate.integrator.spi.Integrator;
@ -169,23 +169,23 @@ public class BootstrapServiceRegistryBuilder {
*/
@SuppressWarnings( {"UnusedDeclaration"})
public <T> BootstrapServiceRegistryBuilder withStrategySelector(Class<T> strategy, String name, Class<? extends T> implementation) {
this.strategySelectorBuilder.addExplicitAvailability( strategy, implementation, name );
this.strategySelectorBuilder.addExplicitStrategyRegistration( strategy, implementation, name );
return this;
}
/**
* Applies one or more strategy selectors announced as available by the passed announcer.
*
* @param availabilityAnnouncer An announcer for one or more available selectors
* @param strategyRegistrationProvider An provider for one or more available selectors
*
* @return {@code this}, for method chaining
*
* @see org.hibernate.boot.registry.selector.spi.StrategySelector#registerStrategyImplementor(Class, String, Class)
*/
@SuppressWarnings( {"UnusedDeclaration"})
public BootstrapServiceRegistryBuilder withStrategySelectors(AvailabilityAnnouncer availabilityAnnouncer) {
for ( Availability availability : availabilityAnnouncer.getAvailabilities() ) {
this.strategySelectorBuilder.addExplicitAvailability( availability );
public BootstrapServiceRegistryBuilder withStrategySelectors(StrategyRegistrationProvider strategyRegistrationProvider) {
for ( StrategyRegistration strategyRegistration : strategyRegistrationProvider.getStrategyRegistrations() ) {
this.strategySelectorBuilder.addExplicitStrategyRegistration( strategyRegistration );
}
return this;
}

View File

@ -2,6 +2,18 @@
* Defines service registry contracts application are likely to want to utilize for
* configuring Hibernate behavior.
*
* {@link BootstrapServiceRegistry} is the
* Service registries are designed to be hierarchical. This works in 2 fashions. First registries can "hide" or
* "override" services from parent registries. It also allows granular building of registries as services
* become available.
*
* {@link BootstrapServiceRegistry} is the base service registry, intended to be built via
* {@link BootstrapServiceRegistryBuilder} if you need customization. For non-customized
* {@link BootstrapServiceRegistry} usage, the {@link BootstrapServiceRegistryBuilder} and
* {@link BootstrapServiceRegistry} can be bypassed altogether.
*
* Usually the next level in a standard registry set up is the {@link StandardServiceRegistry}, intended to be built
* by the {@link StandardServiceRegistryBuilder} if you need customization. The builder optionally takes the
* {@link BootstrapServiceRegistry} to use as a base; if none is provided a default one is generated assuming sensible
* defaults in Java SE and EE environments, particularly in respect to Class loading.
*/
package org.hibernate.boot.registry;

View File

@ -26,25 +26,25 @@ package org.hibernate.boot.registry.selector;
import java.util.Arrays;
/**
* A simple implementation of Availability.
* A simple implementation of StrategyRegistration.
*
* @param <T> The strategy type.
*
* @author Steve Ebersole
*/
public class SimpleAvailabilityImpl<T> implements Availability<T> {
public class SimpleStrategyRegistrationImpl<T> implements StrategyRegistration<T> {
private final Class<T> strategyRole;
private final Class<? extends T> strategyImplementation;
private final Iterable<String> selectorNames;
/**
* Constructs a SimpleAvailabilityImpl.
* Constructs a SimpleStrategyRegistrationImpl.
*
* @param strategyRole The strategy contract
* @param strategyImplementation The strategy implementation class
* @param selectorNames The selection/registration names for this implementation
*/
public SimpleAvailabilityImpl(
public SimpleStrategyRegistrationImpl(
Class<T> strategyRole,
Class<? extends T> strategyImplementation,
Iterable<String> selectorNames) {
@ -54,13 +54,13 @@ public class SimpleAvailabilityImpl<T> implements Availability<T> {
}
/**
* Constructs a SimpleAvailabilityImpl.
* Constructs a SimpleStrategyRegistrationImpl.
*
* @param strategyRole The strategy contract
* @param strategyImplementation The strategy implementation class
* @param selectorNames The selection/registration names for this implementation
*/
public SimpleAvailabilityImpl(
public SimpleStrategyRegistrationImpl(
Class<T> strategyRole,
Class<? extends T> strategyImplementation,
String... selectorNames) {

View File

@ -24,16 +24,14 @@
package org.hibernate.boot.registry.selector;
/**
* Describes the availability of a named strategy implementation. A strategy + selector name should resolve
* Describes the registration of a named strategy implementation. A strategy + selector name should resolve
* to a single implementation.
*
* todo : better name?
*
* @param <T> The type of the strategy described by this implementation availability.
* @param <T> The type of the strategy described by this implementation registration.
*
* @author Steve Ebersole
*/
public interface Availability<T> {
public interface StrategyRegistration<T> {
/**
* The strategy role. Best practice says this should be an interface.
*
@ -42,7 +40,7 @@ public interface Availability<T> {
public Class<T> getStrategyRole();
/**
* Any registered names for this strategy availability.
* Any registered names for this strategy registration.
*
* @return The registered selection names.
*/

View File

@ -24,18 +24,16 @@
package org.hibernate.boot.registry.selector;
/**
* Responsible for announcing the availability of strategy selector(s). Can be registered directly with the
* Responsible for providing the registrations of strategy selector(s). Can be registered directly with the
* {@link org.hibernate.boot.registry.BootstrapServiceRegistry} or located via discovery.
*
* todo : better name?
*
* @author Steve Ebersole
*/
public interface AvailabilityAnnouncer {
public interface StrategyRegistrationProvider {
/**
* Get all availabilities announced by this announcer.
* Get all StrategyRegistrations announced by this provider.
*
* @return All announced availabilities
* @return All StrategyRegistrations
*/
public Iterable<Availability> getAvailabilities();
public Iterable<StrategyRegistration> getStrategyRegistrations();
}

View File

@ -29,9 +29,9 @@ import java.util.List;
import org.jboss.logging.Logger;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.selector.Availability;
import org.hibernate.boot.registry.selector.AvailabilityAnnouncer;
import org.hibernate.boot.registry.selector.SimpleAvailabilityImpl;
import org.hibernate.boot.registry.selector.StrategyRegistration;
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
import org.hibernate.boot.registry.selector.spi.StrategySelectionException;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.dialect.CUBRIDDialect;
@ -106,10 +106,10 @@ import org.hibernate.hql.spi.TemporaryTableBulkIdStrategy;
public class StrategySelectorBuilder {
private static final Logger log = Logger.getLogger( StrategySelectorBuilder.class );
private final List<Availability> explicitAvailabilities = new ArrayList<Availability>();
private final List<StrategyRegistration> explicitStrategyRegistrations = new ArrayList<StrategyRegistration>();
/**
* Adds an explicit (as opposed to discovered) strategy availability.
* Adds an explicit (as opposed to discovered) strategy registration.
*
* @param strategy The strategy
* @param implementation The strategy implementation
@ -118,31 +118,31 @@ public class StrategySelectorBuilder {
* compatible.
*/
@SuppressWarnings("unchecked")
public <T> void addExplicitAvailability(Class<T> strategy, Class<? extends T> implementation, String name) {
addExplicitAvailability( new SimpleAvailabilityImpl<T>( strategy, implementation, name ) );
public <T> void addExplicitStrategyRegistration(Class<T> strategy, Class<? extends T> implementation, String name) {
addExplicitStrategyRegistration( new SimpleStrategyRegistrationImpl<T>( strategy, implementation, name ) );
}
/**
* Adds an explicit (as opposed to discovered) strategy availability.
* Adds an explicit (as opposed to discovered) strategy registration.
*
* @param availability The strategy implementation availability.
* @param strategyRegistration The strategy implementation registration.
* @param <T> The type of the strategy. Used to make sure that the strategy and implementation are type
* compatible.
*/
public <T> void addExplicitAvailability(Availability<T> availability) {
if ( !availability.getStrategyRole().isInterface() ) {
public <T> void addExplicitStrategyRegistration(StrategyRegistration<T> strategyRegistration) {
if ( !strategyRegistration.getStrategyRole().isInterface() ) {
// not good form...
log.debug( "Registering non-interface strategy : " + availability.getStrategyRole().getName() );
log.debug( "Registering non-interface strategy : " + strategyRegistration.getStrategyRole().getName() );
}
if ( ! availability.getStrategyRole().isAssignableFrom( availability.getStrategyImplementation() ) ) {
if ( ! strategyRegistration.getStrategyRole().isAssignableFrom( strategyRegistration.getStrategyImplementation() ) ) {
throw new StrategySelectionException(
"Implementation class [" + availability.getStrategyImplementation().getName()
"Implementation class [" + strategyRegistration.getStrategyImplementation().getName()
+ "] does not implement strategy interface ["
+ availability.getStrategyRole().getName() + "]"
+ strategyRegistration.getStrategyRole().getName() + "]"
);
}
explicitAvailabilities.add( availability );
explicitStrategyRegistrations.add( strategyRegistration );
}
/**
@ -163,27 +163,27 @@ public class StrategySelectorBuilder {
addMultiTableBulkIdStrategies( strategySelector );
// apply auto-discovered registrations
for ( AvailabilityAnnouncer announcer : classLoaderService.loadJavaServices( AvailabilityAnnouncer.class ) ) {
for ( Availability discoveredAvailability : announcer.getAvailabilities() ) {
applyFromAvailability( strategySelector, discoveredAvailability );
for ( StrategyRegistrationProvider provider : classLoaderService.loadJavaServices( StrategyRegistrationProvider.class ) ) {
for ( StrategyRegistration discoveredStrategyRegistration : provider.getStrategyRegistrations() ) {
applyFromStrategyRegistration( strategySelector, discoveredStrategyRegistration );
}
}
// apply customizations
for ( Availability explicitAvailability : explicitAvailabilities ) {
applyFromAvailability( strategySelector, explicitAvailability );
for ( StrategyRegistration explicitStrategyRegistration : explicitStrategyRegistrations ) {
applyFromStrategyRegistration( strategySelector, explicitStrategyRegistration );
}
return strategySelector;
}
@SuppressWarnings("unchecked")
private <T> void applyFromAvailability(StrategySelectorImpl strategySelector, Availability<T> availability) {
for ( String name : availability.getSelectorNames() ) {
private <T> void applyFromStrategyRegistration(StrategySelectorImpl strategySelector, StrategyRegistration<T> strategyRegistration) {
for ( String name : strategyRegistration.getSelectorNames() ) {
strategySelector.registerStrategyImplementor(
availability.getStrategyRole(),
strategyRegistration.getStrategyRole(),
name,
availability.getStrategyImplementation()
strategyRegistration.getStrategyImplementation()
);
}
}

View File

@ -63,7 +63,7 @@ public class TransformingClassLoader extends ClassLoader {
try {
final CtClass cc = classPool.get( name );
// todo : modify the class definition if not already transformed...
byte[] b = cc.toBytecode();
final byte[] b = cc.toBytecode();
return defineClass( name, b, 0, b.length );
}
catch (NotFoundException e) {

View File

@ -30,10 +30,11 @@ import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.VersionType;
/**
* Standard CacheDataDescription implementation.
*
* @author Steve Ebersole
*/
public class CacheDataDescriptionImpl implements CacheDataDescription {
@ -41,48 +42,87 @@ public class CacheDataDescriptionImpl implements CacheDataDescription {
private final boolean versioned;
private final Comparator versionComparator;
/**
* Constructs a CacheDataDescriptionImpl instance. Generally speaking, code should use one of the
* overloaded {@link #decode} methods rather than direct instantiation.
*
* @param mutable Is the described data mutable?
* @param versioned Is the described data versioned?
* @param versionComparator The described data's version value comparator (if versioned).
*/
public CacheDataDescriptionImpl(boolean mutable, boolean versioned, Comparator versionComparator) {
this.mutable = mutable;
this.versioned = versioned;
this.versionComparator = versionComparator;
}
@Override
public boolean isMutable() {
return mutable;
}
@Override
public boolean isVersioned() {
return versioned;
}
@Override
public Comparator getVersionComparator() {
return versionComparator;
}
/**
* Builds a CacheDataDescriptionImpl from the mapping model of an entity class.
*
* @param model The mapping model.
*
* @return The constructed CacheDataDescriptionImpl
*/
public static CacheDataDescriptionImpl decode(PersistentClass model) {
return new CacheDataDescriptionImpl(
model.isMutable(),
model.isVersioned(),
model.isVersioned() ? ( ( VersionType ) model.getVersion().getType() ).getComparator() : null
model.isVersioned()
? ( (VersionType) model.getVersion().getType() ).getComparator()
: null
);
}
/**
* Builds a CacheDataDescriptionImpl from the mapping model of an entity class (using the new metamodel code).
*
* @param model The mapping model.
*
* @return The constructed CacheDataDescriptionImpl
*/
public static CacheDataDescriptionImpl decode(EntityBinding model) {
return new CacheDataDescriptionImpl(
model.isMutable(),
model.isVersioned(),
getVersionComparator( model )
);
return new CacheDataDescriptionImpl( model.isMutable(), model.isVersioned(), getVersionComparator( model ) );
}
/**
* Builds a CacheDataDescriptionImpl from the mapping model of a collection
*
* @param model The mapping model.
*
* @return The constructed CacheDataDescriptionImpl
*/
public static CacheDataDescriptionImpl decode(Collection model) {
return new CacheDataDescriptionImpl(
model.isMutable(),
model.getOwner().isVersioned(),
model.getOwner().isVersioned() ? ( ( VersionType ) model.getOwner().getVersion().getType() ).getComparator() : null
model.getOwner().isVersioned()
? ( (VersionType) model.getOwner().getVersion().getType() ).getComparator()
: null
);
}
/**
* Builds a CacheDataDescriptionImpl from the mapping model of a collection (using the new metamodel code).
*
* @param model The mapping model.
*
* @return The constructed CacheDataDescriptionImpl
*/
public static CacheDataDescriptionImpl decode(PluralAttributeBinding model) {
return new CacheDataDescriptionImpl(
model.isMutable(),
@ -91,18 +131,9 @@ public class CacheDataDescriptionImpl implements CacheDataDescription {
);
}
public static CacheDataDescriptionImpl decode(EntityPersister persister) {
return new CacheDataDescriptionImpl(
!persister.getEntityMetamodel().hasImmutableNaturalId(),
false,
null
);
}
private static Comparator getVersionComparator(EntityBinding model ) {
Comparator versionComparator = null;
if ( model.isVersioned() ) {
versionComparator = (
return (
( VersionType ) model.getHierarchyDetails()
.getEntityVersion()
.getVersioningAttributeBinding()
@ -110,6 +141,7 @@ public class CacheDataDescriptionImpl implements CacheDataDescription {
.getResolvedTypeMapping()
).getComparator();
}
return versionComparator;
return null;
}
}

View File

@ -42,7 +42,16 @@ import org.hibernate.cache.spi.access.AccessType;
* @author Steve Ebersole
*/
public class NoCachingRegionFactory extends AbstractRegionFactory {
public static NoCachingRegionFactory INSTANCE = new NoCachingRegionFactory();
/**
* Singleton access
*/
public static final NoCachingRegionFactory INSTANCE = new NoCachingRegionFactory();
/**
* Constructs a NoCachingRegionFactory. Although access should generally use {@link #INSTANCE}
*/
public NoCachingRegionFactory() {
}
@Override
public void start() {
@ -51,37 +60,45 @@ public class NoCachingRegionFactory extends AbstractRegionFactory {
@Override
public void stop() {
}
@Override
public boolean isMinimalPutsEnabledByDefault() {
return false;
}
@Override
public AccessType getDefaultAccessType() {
return null;
}
@Override
public long nextTimestamp() {
return System.currentTimeMillis() / 100;
}
@Override
public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException {
throw new NoCacheRegionFactoryAvailableException();
}
@Override
public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException {
throw new NoCacheRegionFactoryAvailableException();
}
@Override
public CollectionRegion buildCollectionRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException {
throw new NoCacheRegionFactoryAvailableException();
}
@Override
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
throw new NoCacheRegionFactoryAvailableException();
}
@Override
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
throw new NoCacheRegionFactoryAvailableException();

View File

@ -28,32 +28,30 @@ import org.jboss.logging.Logger;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceInitiator;
import java.util.Map;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.internal.util.config.ConfigurationHelper;
/**
* Initiator for the {@link RegionFactory} service.
*
* @author Hardy Ferentschik
* @author Brett Meyer
*/
public class RegionFactoryInitiator implements SessionFactoryServiceInitiator<RegionFactory> {
public static final RegionFactoryInitiator INSTANCE = new RegionFactoryInitiator();
private static final String DEFAULT_IMPL = NoCachingRegionFactory.class.getName();
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
RegionFactoryInitiator.class.getName()
);
public class RegionFactoryInitiator implements StandardServiceInitiator<RegionFactory> {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class,
RegionFactoryInitiator.class.getName() );
/**
* Property name to use to configure the full qualified class name for the {@code RegionFactory}
* Singleton access
*/
public static final String IMPL_NAME = AvailableSettings.CACHE_REGION_FACTORY;
public static final RegionFactoryInitiator INSTANCE = new RegionFactoryInitiator();
@Override
public Class<RegionFactory> getServiceInitiated() {
@ -61,50 +59,58 @@ public class RegionFactoryInitiator implements SessionFactoryServiceInitiator<Re
}
@Override
public RegionFactory initiateService(SessionFactoryImplementor sessionFactory, Configuration configuration, ServiceRegistryImplementor registry) {
return initiateService(sessionFactory, registry);
@SuppressWarnings({ "unchecked" })
public RegionFactory initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
Properties p = new Properties();
if (configurationValues != null) {
p.putAll( configurationValues );
}
@Override
public RegionFactory initiateService(SessionFactoryImplementor sessionFactory, MetadataImplementor metadata, ServiceRegistryImplementor registry) {
return initiateService(sessionFactory, registry);
boolean useSecondLevelCache = ConfigurationHelper.getBoolean( AvailableSettings.USE_SECOND_LEVEL_CACHE,
configurationValues, true );
boolean useQueryCache = ConfigurationHelper.getBoolean( AvailableSettings.USE_QUERY_CACHE, configurationValues );
RegionFactory regionFactory = NoCachingRegionFactory.INSTANCE;
// The cache provider is needed when we either have second-level cache enabled
// or query cache enabled. Note that useSecondLevelCache is enabled by default
final Object setting = configurationValues.get( AvailableSettings.CACHE_REGION_FACTORY ) ;
// ConfigurationHelper.get( AvailableSettings.CACHE_REGION_FACTORY,
// configurationValues, null );
if ( ( useSecondLevelCache || useQueryCache ) && setting != null ) {
try {
regionFactory = registry.getService( StrategySelector.class )
.resolveStrategy( RegionFactory.class, setting );
// try {
// regionFactory = regionFactoryClass.getConstructor( Properties.class ).newInstance( p );
// }
// catch ( NoSuchMethodException e ) {
// // no constructor accepting Properties found, try no arg constructor
// LOG.debugf(
// "%s did not provide constructor accepting java.util.Properties; attempting no-arg constructor.",
// regionFactoryClass.getSimpleName() );
// regionFactory = regionFactoryClass.getConstructor().newInstance();
// }
}
catch ( Exception e ) {
throw new HibernateException( "could not instantiate RegionFactory [" + setting + "]", e );
}
}
private RegionFactory initiateService(SessionFactoryImplementor sessionFactory, ServiceRegistryImplementor registry){
boolean isCacheEnabled = isCacheEnabled( registry );
if ( !isCacheEnabled ) {
LOG.debugf(
"Second level cache has been disabled, so using % as cache region factory",
NoCachingRegionFactory.class.getName()
);
return NoCachingRegionFactory.INSTANCE;
LOG.debugf( "Cache region factory : %s", regionFactory.getClass().getName() );
return regionFactory;
}
final Object setting = registry.getService( ConfigurationService.class ).getSettings().get( IMPL_NAME );
return registry.getService( StrategySelector.class ).resolveDefaultableStrategy(
RegionFactory.class,
setting,
NoCachingRegionFactory.INSTANCE
);
}
private static boolean isCacheEnabled(ServiceRegistryImplementor serviceRegistry) {
final ConfigurationService configurationService = serviceRegistry.getService( ConfigurationService.class );
final boolean useSecondLevelCache = configurationService.getSetting(
AvailableSettings.USE_SECOND_LEVEL_CACHE,
StandardConverters.BOOLEAN,
true
);
final boolean useQueryCache = configurationService.getSetting(
AvailableSettings.USE_QUERY_CACHE,
StandardConverters.BOOLEAN,
false
);
return useSecondLevelCache || useQueryCache;
}
// todo this shouldn't be public (nor really static):
// hack for org.hibernate.cfg.SettingsFactory.createRegionFactory()
/**
* Map legacy names unto the new corollary.
*
* TODO: temporary hack for org.hibernate.cfg.SettingsFactory.createRegionFactory()
*
* @param name The (possibly legacy) factory name
*
* @return The factory name to use.
*/
public static String mapLegacyNames(final String name) {
if ( "org.hibernate.cache.EhCacheRegionFactory".equals( name ) ) {
return "org.hibernate.cache.ehcache.EhCacheRegionFactory";

View File

@ -51,14 +51,13 @@ import org.hibernate.type.TypeHelper;
/**
* The standard implementation of the Hibernate QueryCache interface. This
* implementation is very good at recognizing stale query results and
* and re-running queries when it detects this condition, recaching the new
* and re-running queries when it detects this condition, re-caching the new
* results.
*
* @author Gavin King
* @author Steve Ebersole
*/
public class StandardQueryCache implements QueryCache {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
StandardQueryCache.class.getName()
@ -69,31 +68,58 @@ public class StandardQueryCache implements QueryCache {
private QueryResultsRegion cacheRegion;
private UpdateTimestampsCache updateTimestampsCache;
/**
* Constructs a StandardQueryCache instance
*
* @param sessionFactoryImplementor The SessionFactory.
* @param updateTimestampsCache The update-timestamps cache to use.
* @param regionName The base query cache region name
*/
public StandardQueryCache(SessionFactoryImplementor sessionFactoryImplementor, UpdateTimestampsCache updateTimestampsCache, String regionName) {
if ( regionName == null ) {
regionName = StandardQueryCache.class.getName();
String regionNameToUse = regionName;
if ( regionNameToUse == null ) {
regionNameToUse = StandardQueryCache.class.getName();
}
String prefix = sessionFactoryImplementor.getServiceRegistry()
.getService( ConfigurationService.class )
.getSetting(
AvailableSettings.CACHE_REGION_PREFIX, StandardConverters.STRING, null
);
if ( prefix != null ) {
regionName = prefix + '.' + regionName;
regionNameToUse = prefix + '.' + regionNameToUse;
}
LOG.startingQueryCache( regionName );
LOG.startingQueryCache( regionNameToUse );
this.cacheRegion = sessionFactoryImplementor.getServiceRegistry()
.getService( RegionFactory.class )
.buildQueryResultsRegion( regionName, sessionFactoryImplementor.getProperties() );
.buildQueryResultsRegion( regionNameToUse, sessionFactoryImplementor.getProperties() );
this.updateTimestampsCache = updateTimestampsCache;
}
@Override
public QueryResultsRegion getRegion() {
return cacheRegion;
}
@Override
public void destroy() {
try {
cacheRegion.destroy();
}
catch ( Exception e ) {
LOG.unableToDestroyQueryCache( cacheRegion.getName(), e.getMessage() );
}
}
@Override
public void clear() throws CacheException {
cacheRegion.evictAll();
}
@Override
@SuppressWarnings({ "unchecked" })
public boolean put(
final QueryKey key,
final Type[] returnTypes,
@ -103,20 +129,21 @@ public class StandardQueryCache implements QueryCache {
if ( isNaturalKeyLookup && result.isEmpty() ) {
return false;
}
long ts = cacheRegion.nextTimestamp();
final long ts = cacheRegion.nextTimestamp();
if ( DEBUGGING ) LOG.debugf( "Caching query results in region: %s; timestamp=%s", cacheRegion.getName(), ts );
if ( DEBUGGING ) {
LOG.debugf( "Caching query results in region: %s; timestamp=%s", cacheRegion.getName(), ts );
}
List cacheable = new ArrayList( result.size() + 1 );
final List cacheable = new ArrayList( result.size() + 1 );
logCachedResultDetails( key, null, returnTypes, cacheable );
cacheable.add( ts );
final boolean singleResult = returnTypes.length == 1;
final boolean isSingleResult = returnTypes.length == 1;
for ( Object aResult : result ) {
Serializable cacheItem = singleResult ? returnTypes[0].disassemble(
aResult,
session,
null
) : TypeHelper.disassemble( (Object[]) aResult, returnTypes, null, session, null );
final Serializable cacheItem = isSingleResult
? returnTypes[0].disassemble( aResult, session, null )
: TypeHelper.disassemble( (Object[]) aResult, returnTypes, null, session, null );
cacheable.add( cacheItem );
logCachedResultRowDetails( returnTypes, aResult );
}
@ -125,6 +152,7 @@ public class StandardQueryCache implements QueryCache {
return true;
}
@Override
@SuppressWarnings({ "unchecked" })
public List get(
final QueryKey key,
@ -132,23 +160,31 @@ public class StandardQueryCache implements QueryCache {
final boolean isNaturalKeyLookup,
final Set spaces,
final SessionImplementor session) throws HibernateException {
if ( DEBUGGING ) LOG.debugf( "Checking cached query results in region: %s", cacheRegion.getName() );
if ( DEBUGGING ) {
LOG.debugf( "Checking cached query results in region: %s", cacheRegion.getName() );
}
List cacheable = (List) cacheRegion.get( key );
final List cacheable = (List) cacheRegion.get( key );
logCachedResultDetails( key, spaces, returnTypes, cacheable );
if ( cacheable == null ) {
if ( DEBUGGING ) LOG.debug( "Query results were not found in cache" );
if ( DEBUGGING ) {
LOG.debug( "Query results were not found in cache" );
}
return null;
}
Long timestamp = (Long) cacheable.get( 0 );
final Long timestamp = (Long) cacheable.get( 0 );
if ( !isNaturalKeyLookup && !isUpToDate( spaces, timestamp ) ) {
if ( DEBUGGING ) LOG.debug( "Cached query results were not up-to-date" );
if ( DEBUGGING ) {
LOG.debug( "Cached query results were not up-to-date" );
}
return null;
}
if ( DEBUGGING ) LOG.debug( "Returning cached query results" );
if ( DEBUGGING ) {
LOG.debug( "Returning cached query results" );
}
final boolean singleResult = returnTypes.length == 1;
for ( int i = 1; i < cacheable.size(); i++ ) {
if ( singleResult ) {
@ -158,7 +194,8 @@ public class StandardQueryCache implements QueryCache {
TypeHelper.beforeAssemble( (Serializable[]) cacheable.get( i ), returnTypes, session );
}
}
List result = new ArrayList( cacheable.size() - 1 );
final List result = new ArrayList( cacheable.size() - 1 );
for ( int i = 1; i < cacheable.size(); i++ ) {
try {
if ( singleResult ) {
@ -172,17 +209,19 @@ public class StandardQueryCache implements QueryCache {
logCachedResultRowDetails( returnTypes, result.get( i - 1 ) );
}
catch ( RuntimeException ex ) {
if ( isNaturalKeyLookup &&
( UnresolvableObjectException.class.isInstance( ex ) ||
EntityNotFoundException.class.isInstance( ex ) ) ) {
//TODO: not really completely correct, since
// the uoe could occur while resolving
// associations, leaving the PC in an
// inconsistent state
if ( DEBUGGING ) LOG.debug( "Unable to reassemble cached result set" );
if ( isNaturalKeyLookup ) {
// potentially perform special handling for natural-id look ups.
if ( UnresolvableObjectException.class.isInstance( ex )
|| EntityNotFoundException.class.isInstance( ex ) ) {
if ( DEBUGGING ) {
LOG.debug( "Unable to reassemble cached natural-id query result" );
}
cacheRegion.evict( key );
// EARLY EXIT !!!!!
return null;
}
}
throw ex;
}
}
@ -190,23 +229,12 @@ public class StandardQueryCache implements QueryCache {
}
protected boolean isUpToDate(final Set spaces, final Long timestamp) {
if ( DEBUGGING ) LOG.debugf( "Checking query spaces are up-to-date: %s", spaces );
if ( DEBUGGING ) {
LOG.debugf( "Checking query spaces are up-to-date: %s", spaces );
}
return updateTimestampsCache.isUpToDate( spaces, timestamp );
}
public void destroy() {
try {
cacheRegion.destroy();
}
catch ( Exception e ) {
LOG.unableToDestroyQueryCache( cacheRegion.getName(), e.getMessage() );
}
}
public QueryResultsRegion getRegion() {
return cacheRegion;
}
@Override
public String toString() {
return "StandardQueryCache(" + cacheRegion.getName() + ')';
@ -226,12 +254,13 @@ public class StandardQueryCache implements QueryCache {
);
}
else {
StringBuilder returnTypeInfo = new StringBuilder();
for ( int i = 0; i < returnTypes.length; i++ ) {
final StringBuilder returnTypeInfo = new StringBuilder();
for ( Type returnType : returnTypes ) {
returnTypeInfo.append( "typename=" )
.append( returnTypes[i].getName() )
.append( returnType.getName() )
.append( " class=" )
.append( returnTypes[i].getReturnedClass().getName() ).append( ' ' );
.append( returnType.getReturnedClass().getName() )
.append( ' ' );
}
LOG.trace( "unexpected returnTypes is " + returnTypeInfo.toString() + "! result" );
}
@ -252,7 +281,10 @@ public class StandardQueryCache implements QueryCache {
return;
}
if ( tuple == null ) {
LOG.trace( " tuple is null; returnTypes is " + returnTypes == null ? "null" : "Type[" + returnTypes.length + "]" );
LOG.tracef(
"tuple is null; returnTypes is %s",
returnTypes == null ? "null" : "Type[" + returnTypes.length + "]"
);
if ( returnTypes != null && returnTypes.length > 1 ) {
LOG.trace(
"Unexpected result tuple! tuple is null; should be Object["
@ -267,8 +299,12 @@ public class StandardQueryCache implements QueryCache {
+ ( returnTypes == null ? "null" : "empty" )
);
}
LOG.trace( " tuple is Object[" + tuple.length + "]; returnTypes is Type[" + returnTypes.length + "]" );
if ( tuple.length != returnTypes.length ) {
LOG.tracef(
"tuple is Object[%s]; returnTypes is %s",
tuple.length,
returnTypes == null ? "null" : "Type[" + returnTypes.length + "]"
);
if ( returnTypes != null && tuple.length != returnTypes.length ) {
LOG.trace(
"Unexpected tuple length! transformer= expected="
+ returnTypes.length + " got=" + tuple.length
@ -276,7 +312,8 @@ public class StandardQueryCache implements QueryCache {
}
else {
for ( int j = 0; j < tuple.length; j++ ) {
if ( tuple[j] != null && !returnTypes[j].getReturnedClass().isInstance( tuple[j] ) ) {
if ( tuple[j] != null && returnTypes != null
&& ! returnTypes[j].getReturnedClass().isInstance( tuple[j] ) ) {
LOG.trace(
"Unexpected tuple value type! transformer= expected="
+ returnTypes[j].getReturnedClass().getName()

View File

@ -0,0 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
/**
* Internal implementations and support for second-level caching.
*/
package org.hibernate.cache.internal;

View File

@ -29,7 +29,6 @@ import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.cache.CacheException;
import org.hibernate.cfg.Settings;
import org.hibernate.engine.spi.SessionFactoryImplementor;

View File

@ -150,6 +150,7 @@ import org.hibernate.cfg.annotations.PropertyBinder;
import org.hibernate.cfg.annotations.QueryBinder;
import org.hibernate.cfg.annotations.SimpleValueBinder;
import org.hibernate.cfg.annotations.TableBinder;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.id.MultipleHiLoPerTableGenerator;
@ -1561,7 +1562,7 @@ public final class AnnotationBinder {
SimpleValue simpleValue = ( SimpleValue ) prop.getValue();
simpleValue.setNullValue( "undefined" );
rootClass.setOptimisticLockMode( Versioning.OPTIMISTIC_LOCK_VERSION );
rootClass.setOptimisticLockStyle( OptimisticLockStyle.VERSION );
if ( traceEnabled ) {
LOG.tracev( "Version name: {0}, unsavedValue: {1}", rootClass.getVersion().getName(),
( (SimpleValue) rootClass.getVersion().getValue() ).getNullValue() );

View File

@ -23,8 +23,6 @@
*/
package org.hibernate.cfg;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
/**
* @author Steve Ebersole
*/
@ -697,4 +695,22 @@ public interface AvailableSettings {
* Oracle), this is disabled by default.
*/
public static final String ENABLE_SYNONYMS = "hibernate.synonyms";
/**
* Unique columns and unique keys both use unique constraints in most dialects.
* SchemaUpdate needs to create these constraints, but DB's
* support for finding existing constraints is extremely inconsistent. Further,
* non-explicitly-named unique constraints use randomly generated characters.
*
* Therefore, select from these strategies.
* {@link org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy#DROP_RECREATE_QUIETLY} (DEFAULT):
* Attempt to drop, then (re-)create each unique constraint.
* Ignore any exceptions thrown.
* {@link org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy#RECREATE_QUIETLY}:
* attempt to (re-)create unique constraints,
* ignoring exceptions thrown if the constraint already existed
* {@link org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy#SKIP}:
* do not attempt to create unique constraints on a schema update
*/
public static final String UNIQUE_CONSTRAINT_SCHEMA_UPDATE_STRATEGY = "hibernate.schema_update.unique_constraint_strategy";
}

View File

@ -82,6 +82,7 @@ import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl;
import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
@ -89,6 +90,7 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.NamedQueryDefinition;
@ -136,13 +138,17 @@ import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.TypeDef;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.metamodel.spi.TypeContributions;
import org.hibernate.metamodel.spi.TypeContributor;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.secure.spi.GrantedPermission;
import org.hibernate.secure.spi.JaccPermissionDeclarations;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
import org.hibernate.tool.hbm2ddl.IndexMetadata;
import org.hibernate.tool.hbm2ddl.SchemaUpdateScript;
import org.hibernate.tool.hbm2ddl.TableMetadata;
import org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy;
import org.hibernate.tuple.entity.EntityTuplizerFactory;
import org.hibernate.type.BasicType;
import org.hibernate.type.SerializationException;
@ -221,7 +227,9 @@ public class Configuration implements Serializable {
protected Map<ExtendsQueueEntry, ?> extendsQueue;
protected Map<String, SQLFunction> sqlFunctions;
private TypeResolver typeResolver = new TypeResolver();
private List<TypeContributor> typeContributorRegistrations = new ArrayList<TypeContributor>();
private EntityTuplizerFactory entityTuplizerFactory;
// private ComponentTuplizerFactory componentTuplizerFactory; todo : HHH-3517 and HHH-1907
@ -1117,57 +1125,64 @@ public class Configuration implements Serializable {
*
* @throws HibernateException Generally indicates a problem calling {@link #buildMappings()}
*
* @see org.hibernate.tool.hbm2ddl.SchemaExport
* @see org.hibernate.tool.hbm2ddl.SchemaUpdate
*
* @deprecated Use {@link #generateSchemaUpdateScriptList(Dialect, DatabaseMetadata)} instead
*/
@SuppressWarnings({ "unchecked" })
@Deprecated
public String[] generateSchemaUpdateScript(Dialect dialect, DatabaseMetadata databaseMetadata)
throws HibernateException {
List<SchemaUpdateScript> scripts = generateSchemaUpdateScriptList( dialect, databaseMetadata );
return SchemaUpdateScript.toStringArray( scripts );
}
/**
* @param dialect The dialect for which to generate the creation script
* @param databaseMetadata The database catalog information for the database to be updated; needed to work out what
* should be created/altered
*
* @return The sequence of DDL commands to apply the schema objects
*
* @throws HibernateException Generally indicates a problem calling {@link #buildMappings()}
*
* @see org.hibernate.tool.hbm2ddl.SchemaUpdate
*/
public List<SchemaUpdateScript> generateSchemaUpdateScriptList(Dialect dialect, DatabaseMetadata databaseMetadata)
throws HibernateException {
secondPassCompile();
String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
UniqueConstraintSchemaUpdateStrategy constraintMethod = UniqueConstraintSchemaUpdateStrategy.interpret( properties
.get( Environment.UNIQUE_CONSTRAINT_SCHEMA_UPDATE_STRATEGY ) );
ArrayList<String> script = new ArrayList<String>( 50 );
List<SchemaUpdateScript> scripts = new ArrayList<SchemaUpdateScript>();
Iterator iter = getTableMappings();
while ( iter.hasNext() ) {
Table table = (Table) iter.next();
String tableSchema = ( table.getSchema() == null ) ? defaultSchema : table.getSchema() ;
String tableSchema = ( table.getSchema() == null ) ? defaultSchema : table.getSchema();
String tableCatalog = ( table.getCatalog() == null ) ? defaultCatalog : table.getCatalog();
if ( table.isPhysicalTable() ) {
TableMetadata tableInfo = databaseMetadata.getTableMetadata(
table.getName(),
tableSchema,
tableCatalog,
table.isQuoted()
);
TableMetadata tableInfo = databaseMetadata.getTableMetadata( table.getName(), tableSchema,
tableCatalog, table.isQuoted() );
if ( tableInfo == null ) {
script.add(
table.sqlCreateString(
dialect,
mapping,
tableCatalog,
tableSchema
)
);
scripts.add( new SchemaUpdateScript( table.sqlCreateString( dialect, mapping, tableCatalog,
tableSchema ), false ) );
}
else {
Iterator<String> subiter = table.sqlAlterStrings(
dialect,
mapping,
tableInfo,
tableCatalog,
tableSchema
);
Iterator<String> subiter = table.sqlAlterStrings( dialect, mapping, tableInfo, tableCatalog,
tableSchema );
while ( subiter.hasNext() ) {
script.add( subiter.next() );
scripts.add( new SchemaUpdateScript( subiter.next(), false ) );
}
}
Iterator<String> comments = table.sqlCommentStrings( dialect, defaultCatalog, defaultSchema );
while ( comments.hasNext() ) {
script.add( comments.next() );
scripts.add( new SchemaUpdateScript( comments.next(), false ) );
}
}
@ -1176,17 +1191,14 @@ public class Configuration implements Serializable {
iter = getTableMappings();
while ( iter.hasNext() ) {
Table table = (Table) iter.next();
String tableSchema = ( table.getSchema() == null ) ? defaultSchema : table.getSchema() ;
String tableSchema = ( table.getSchema() == null ) ? defaultSchema : table.getSchema();
String tableCatalog = ( table.getCatalog() == null ) ? defaultCatalog : table.getCatalog();
if ( table.isPhysicalTable() ) {
TableMetadata tableInfo = databaseMetadata.getTableMetadata(
table.getName(),
tableSchema,
tableCatalog,
table.isQuoted()
);
TableMetadata tableInfo = databaseMetadata.getTableMetadata( table.getName(), tableSchema,
tableCatalog, table.isQuoted() );
if (! constraintMethod.equals( UniqueConstraintSchemaUpdateStrategy.SKIP )) {
Iterator uniqueIter = table.getUniqueKeyIterator();
while ( uniqueIter.hasNext() ) {
final UniqueKey uniqueKey = (UniqueKey) uniqueIter.next();
@ -1199,9 +1211,14 @@ public class Configuration implements Serializable {
continue;
}
}
String constraintString = uniqueKey.sqlCreateString( dialect,
mapping, tableCatalog, tableSchema );
if (constraintString != null) script.add( constraintString );
String constraintString = uniqueKey.sqlCreateString( dialect, mapping, tableCatalog, tableSchema );
if ( constraintString != null && !constraintString.isEmpty() )
if ( constraintMethod.equals( UniqueConstraintSchemaUpdateStrategy.DROP_RECREATE_QUIETLY ) ) {
String constraintDropString = uniqueKey.sqlDropString( dialect, tableCatalog, tableCatalog );
scripts.add( new SchemaUpdateScript( constraintDropString, true) );
}
scripts.add( new SchemaUpdateScript( constraintString, true) );
}
}
if ( dialect.hasAlterTable() ) {
@ -1209,22 +1226,12 @@ public class Configuration implements Serializable {
while ( subIter.hasNext() ) {
ForeignKey fk = (ForeignKey) subIter.next();
if ( fk.isPhysicalConstraint() ) {
boolean create = tableInfo == null || (
tableInfo.getForeignKeyMetadata( fk ) == null && (
//Icky workaround for MySQL bug:
!( dialect instanceof MySQLDialect ) ||
tableInfo.getIndexMetadata( fk.getName() ) == null
)
);
boolean create = tableInfo == null || ( tableInfo.getForeignKeyMetadata( fk ) == null && (
// Icky workaround for MySQL bug:
!( dialect instanceof MySQLDialect ) || tableInfo.getIndexMetadata( fk.getName() ) == null ) );
if ( create ) {
script.add(
fk.sqlCreateString(
dialect,
mapping,
tableCatalog,
tableSchema
)
);
scripts.add( new SchemaUpdateScript( fk.sqlCreateString( dialect, mapping,
tableCatalog, tableSchema ), false ) );
}
}
}
@ -1240,14 +1247,8 @@ public class Configuration implements Serializable {
continue;
}
}
script.add(
index.sqlCreateString(
dialect,
mapping,
tableCatalog,
tableSchema
)
);
scripts.add( new SchemaUpdateScript( index.sqlCreateString( dialect, mapping, tableCatalog,
tableSchema ), false ) );
}
}
}
@ -1258,11 +1259,11 @@ public class Configuration implements Serializable {
Object key = generator.generatorKey();
if ( !databaseMetadata.isSequence( key ) && !databaseMetadata.isTable( key ) ) {
String[] lines = generator.sqlCreateStrings( dialect );
script.addAll( Arrays.asList( lines ) );
scripts.addAll( SchemaUpdateScript.fromStringArray( lines, false ) );
}
}
return ArrayHelper.toStringArray( script );
return scripts;
}
public void validateSchema(Dialect dialect, DatabaseMetadata databaseMetadata)throws HibernateException {
@ -1788,6 +1789,7 @@ public class Configuration implements Serializable {
public SessionFactory buildSessionFactory(ServiceRegistry serviceRegistry) throws HibernateException {
LOG.debugf( "Preparing to build session factory with filters : %s", filterDefinitions );
buildTypeRegistrations( serviceRegistry );
secondPassCompile();
if ( !metadataSourceQueue.isEmpty() ) {
LOG.incompleteMappingMetadataCacheProcessing();
@ -1810,6 +1812,39 @@ public class Configuration implements Serializable {
);
}
private void buildTypeRegistrations(ServiceRegistry serviceRegistry) {
final TypeContributions typeContributions = new TypeContributions() {
@Override
public void contributeType(BasicType type) {
typeResolver.registerTypeOverride( type );
}
@Override
public void contributeType(UserType type, String[] keys) {
typeResolver.registerTypeOverride( type, keys );
}
@Override
public void contributeType(CompositeUserType type, String[] keys) {
typeResolver.registerTypeOverride( type, keys );
}
};
// add Dialect contributed types
final Dialect dialect = serviceRegistry.getService( JdbcServices.class ).getDialect();
dialect.contributeTypes( typeContributions, serviceRegistry );
// add TypeContributor contributed types.
ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
for ( TypeContributor contributor : classLoaderService.loadJavaServices( TypeContributor.class ) ) {
contributor.contribute( typeContributions, serviceRegistry );
}
// from app registrations
for ( TypeContributor contributor : typeContributorRegistrations ) {
contributor.contribute( typeContributions, serviceRegistry );
}
}
/**
* Create a {@link SessionFactory} using the properties and mappings in this configuration. The
* {@link SessionFactory} will be immutable, so changes made to {@code this} {@link Configuration} after
@ -2515,6 +2550,10 @@ public class Configuration implements Serializable {
getTypeResolver().registerTypeOverride( type, keys );
}
public void registerTypeContributor(TypeContributor typeContributor) {
typeContributorRegistrations.add( typeContributor );
}
public SessionFactoryObserver getSessionFactoryObserver() {
return sessionFactoryObserver;
}

View File

@ -40,7 +40,7 @@ import org.hibernate.EntityMode;
import org.hibernate.FetchMode;
import org.hibernate.FlushMode;
import org.hibernate.MappingException;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.NamedQueryDefinition;
@ -687,7 +687,7 @@ public final class HbmBinder {
// OPTIMISTIC LOCK MODE
Attribute olNode = node.attribute( "optimistic-lock" );
entity.setOptimisticLockMode( getOptimisticLockMode( olNode ) );
entity.setOptimisticLockStyle( getOptimisticLockStyle( olNode ) );
entity.setMetaAttributes( getMetas( node, inheritedMetas ) );
@ -2896,21 +2896,23 @@ public final class HbmBinder {
}
}
private static int getOptimisticLockMode(Attribute olAtt) throws MappingException {
private static OptimisticLockStyle getOptimisticLockStyle(Attribute olAtt) throws MappingException {
if ( olAtt == null ) {
return OptimisticLockStyle.VERSION;
}
if ( olAtt == null ) return Versioning.OPTIMISTIC_LOCK_VERSION;
String olMode = olAtt.getValue();
final String olMode = olAtt.getValue();
if ( olMode == null || "version".equals( olMode ) ) {
return Versioning.OPTIMISTIC_LOCK_VERSION;
return OptimisticLockStyle.VERSION;
}
else if ( "dirty".equals( olMode ) ) {
return Versioning.OPTIMISTIC_LOCK_DIRTY;
return OptimisticLockStyle.DIRTY;
}
else if ( "all".equals( olMode ) ) {
return Versioning.OPTIMISTIC_LOCK_ALL;
return OptimisticLockStyle.ALL;
}
else if ( "none".equals( olMode ) ) {
return Versioning.OPTIMISTIC_LOCK_NONE;
return OptimisticLockStyle.NONE;
}
else {
throw new MappingException( "Unsupported optimistic-lock style: " + olMode );
@ -2932,7 +2934,7 @@ public final class HbmBinder {
boolean inheritable = Boolean
.valueOf( metaNode.attributeValue( "inherit" ) )
.booleanValue();
if ( onlyInheritable & !inheritable ) {
if ( onlyInheritable && !inheritable ) {
continue;
}
String name = metaNode.attributeValue( "attribute" );

View File

@ -1139,7 +1139,11 @@ public abstract class CollectionBinder {
XProperty property,
PropertyHolder parentPropertyHolder,
Mappings mappings) throws MappingException {
PersistentClass collectionEntity = (PersistentClass) persistentClasses.get( collType.getName() );
if ( property == null ) {
throw new IllegalArgumentException( "null was passed for argument property" );
}
final PersistentClass collectionEntity = (PersistentClass) persistentClasses.get( collType.getName() );
final String hqlOrderBy = extractHqlOrderBy( jpaOrderBy );
boolean isCollectionOfEntities = collectionEntity != null;
@ -1269,9 +1273,11 @@ public abstract class CollectionBinder {
buildOrderByClauseFromHql( hqlOrderBy, collectionEntity, collValue.getRole() )
);
}
ForeignKey fk = property != null ? property.getAnnotation( ForeignKey.class ) : null;
final ForeignKey fk = property.getAnnotation( ForeignKey.class );
String fkName = fk != null ? fk.inverseName() : "";
if ( !BinderHelper.isEmptyAnnotationValue( fkName ) ) element.setForeignKeyName( fkName );
if ( !BinderHelper.isEmptyAnnotationValue( fkName ) ) {
element.setForeignKeyName( fkName );
}
}
else if ( anyAnn != null ) {
//@ManyToAny

View File

@ -82,6 +82,7 @@ import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.ObjectNameSource;
import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.UniqueConstraintHolder;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.internal.Versioning;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.FilterDefinition;
@ -270,7 +271,7 @@ public class EntityBinder {
LOG.immutableAnnotationOnNonRoot(annotatedClass.getName());
}
}
persistentClass.setOptimisticLockMode( getVersioning( optimisticLockType ) );
persistentClass.setOptimisticLockStyle( getVersioning( optimisticLockType ) );
persistentClass.setSelectBeforeUpdate( selectBeforeUpdate );
//set persister if needed
@ -404,16 +405,16 @@ public class EntityBinder {
}
}
int getVersioning(OptimisticLockType type) {
OptimisticLockStyle getVersioning(OptimisticLockType type) {
switch ( type ) {
case VERSION:
return Versioning.OPTIMISTIC_LOCK_VERSION;
return OptimisticLockStyle.VERSION;
case NONE:
return Versioning.OPTIMISTIC_LOCK_NONE;
return OptimisticLockStyle.NONE;
case DIRTY:
return Versioning.OPTIMISTIC_LOCK_DIRTY;
return OptimisticLockStyle.DIRTY;
case ALL:
return Versioning.OPTIMISTIC_LOCK_ALL;
return OptimisticLockStyle.ALL;
default:
throw new AssertionFailure( "optimistic locking not supported: " + type );
}

View File

@ -75,7 +75,7 @@ public interface Lifecycle {
* Called when an entity is saved.
* @param s the session
* @return true to veto save
* @throws CallbackException
* @throws CallbackException Indicates a problem happened during callback
*/
public boolean onSave(Session s) throws CallbackException;
@ -85,7 +85,7 @@ public interface Lifecycle {
* state is persisted during a flush.
* @param s the session
* @return true to veto update
* @throws CallbackException
* @throws CallbackException Indicates a problem happened during callback
*/
public boolean onUpdate(Session s) throws CallbackException;
@ -93,7 +93,7 @@ public interface Lifecycle {
* Called when an entity is deleted.
* @param s the session
* @return true to veto delete
* @throws CallbackException
* @throws CallbackException Indicates a problem happened during callback
*/
public boolean onDelete(Session s) throws CallbackException;
@ -108,9 +108,3 @@ public interface Lifecycle {
*/
public void onLoad(Session s, Serializable id);
}

View File

@ -80,41 +80,57 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
private Serializable storedSnapshot;
private String sessionFactoryUuid;
private boolean specjLazyLoad = false;
private boolean specjLazyLoad;
/**
* Not called by Hibernate, but used by non-JDK serialization,
* eg. SOAP libraries.
*/
public AbstractPersistentCollection() {
}
protected AbstractPersistentCollection(SessionImplementor session) {
this.session = session;
}
@Override
public final String getRole() {
return role;
}
@Override
public final Serializable getKey() {
return key;
}
@Override
public final boolean isUnreferenced() {
return role == null;
}
@Override
public final boolean isDirty() {
return dirty;
}
@Override
public final void clearDirty() {
dirty = false;
}
@Override
public final void dirty() {
dirty = true;
}
@Override
public final Serializable getStoredSnapshot() {
return storedSnapshot;
}
//Careful: these methods do not initialize the collection.
/**
* Is the initialized collection empty?
*/
@Override
public abstract boolean empty();
/**
@ -134,14 +150,14 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
return true;
}
else {
boolean isExtraLazy = withTemporarySessionIfNeeded(
final boolean isExtraLazy = withTemporarySessionIfNeeded(
new LazyInitializationWork<Boolean>() {
@Override
public Boolean doWork() {
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
final CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
if ( entry != null ) {
CollectionPersister persister = entry.getLoadedPersister();
final CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) {
if ( hasQueuedOperations() ) {
session.flush();
@ -168,7 +184,17 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
return false;
}
/**
* TBH not sure why this is public
*
* @param <T> The java type of the return for this LazyInitializationWork
*/
public static interface LazyInitializationWork<T> {
/**
* Do the represented work and return the result.
*
* @return The result
*/
public T doWork();
}
@ -221,7 +247,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
// be created even if a current session and transaction are
// open (ex: session.clear() was used). We must prevent
// multiple transactions.
( ( Session) session ).beginTransaction();
( (Session) session ).beginTransaction();
}
session.getPersistenceContext().addUninitializedDetachedCollection(
@ -238,7 +264,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
// make sure the just opened temp session gets closed!
try {
if ( !isJTA ) {
( ( Session) session ).getTransaction().commit();
( (Session) session ).getTransaction().commit();
}
( (Session) session ).close();
}
@ -255,19 +281,19 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
throwLazyInitializationException( "SessionFactory UUID not known to create temporary Session for loading" );
}
SessionFactoryImplementor sf = (SessionFactoryImplementor)
final SessionFactoryImplementor sf = (SessionFactoryImplementor)
SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
return (SessionImplementor) sf.openSession();
}
protected Boolean readIndexExistence(final Object index) {
if ( !initialized ) {
Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
final Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
new LazyInitializationWork<Boolean>() {
@Override
public Boolean doWork() {
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
CollectionPersister persister = entry.getLoadedPersister();
final CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
final CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) {
if ( hasQueuedOperations() ) {
session.flush();
@ -290,12 +316,12 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
protected Boolean readElementExistence(final Object element) {
if ( !initialized ) {
Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
final Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
new LazyInitializationWork<Boolean>() {
@Override
public Boolean doWork() {
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
CollectionPersister persister = entry.getLoadedPersister();
final CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
final CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) {
if ( hasQueuedOperations() ) {
session.flush();
@ -326,8 +352,8 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
@Override
public Object doWork() {
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
CollectionPersister persister = entry.getLoadedPersister();
final CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
final CollectionPersister persister = entry.getLoadedPersister();
isExtraLazy = persister.isExtraLazy();
if ( isExtraLazy ) {
if ( hasQueuedOperations() ) {
@ -342,7 +368,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
ExtraLazyElementByIndexReader reader = new ExtraLazyElementByIndexReader();
final ExtraLazyElementByIndexReader reader = new ExtraLazyElementByIndexReader();
//noinspection unchecked
withTemporarySessionIfNeeded( reader );
if ( reader.isExtraLazy ) {
@ -358,9 +384,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
private boolean isConnectedToSession() {
return session != null &&
session.isOpen() &&
session.getPersistenceContext().containsCollection( this );
return session != null
&& session.isOpen()
&& session.getPersistenceContext().containsCollection( this );
}
/**
@ -377,9 +403,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
*/
@SuppressWarnings({"JavaDoc"})
protected boolean isOperationQueueEnabled() {
return !initialized &&
isConnectedToSession() &&
isInverseCollection();
return !initialized
&& isConnectedToSession()
&& isInverseCollection();
}
/**
@ -389,9 +415,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
*/
@SuppressWarnings({"JavaDoc"})
protected boolean isPutQueueEnabled() {
return !initialized &&
isConnectedToSession() &&
isInverseOneToManyOrNoOrphanDelete();
return !initialized
&& isConnectedToSession()
&& isInverseOneToManyOrNoOrphanDelete();
}
/**
@ -401,9 +427,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
*/
@SuppressWarnings({"JavaDoc"})
protected boolean isClearQueueEnabled() {
return !initialized &&
isConnectedToSession() &&
isInverseCollectionNoOrphanDelete();
return !initialized
&& isConnectedToSession()
&& isInverseCollectionNoOrphanDelete();
}
/**
@ -411,7 +437,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
*/
@SuppressWarnings({"JavaDoc"})
private boolean isInverseCollection() {
CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null && ce.getLoadedPersister().isInverse();
}
@ -421,8 +447,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
*/
@SuppressWarnings({"JavaDoc"})
private boolean isInverseCollectionNoOrphanDelete() {
CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null &&
final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null
&&
ce.getLoadedPersister().isInverse() &&
!ce.getLoadedPersister().hasOrphanDelete();
}
@ -433,11 +460,10 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
*/
@SuppressWarnings({"JavaDoc"})
private boolean isInverseOneToManyOrNoOrphanDelete() {
CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null && ce.getLoadedPersister().isInverse() && (
ce.getLoadedPersister().isOneToMany() ||
!ce.getLoadedPersister().hasOrphanDelete()
);
final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null
&& ce.getLoadedPersister().isInverse()
&& ( ce.getLoadedPersister().isOneToMany() || !ce.getLoadedPersister().hasOrphanDelete() );
}
/**
@ -449,7 +475,8 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
operationQueue = new ArrayList<DelayedOperation>( 10 );
}
operationQueue.add( operation );
dirty = true; //needed so that we remove this collection from the second-level cache
//needed so that we remove this collection from the second-level cache
dirty = true;
}
/**
@ -462,59 +489,38 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
/**
* After flushing, re-init snapshot state.
*/
@Override
public void setSnapshot(Serializable key, String role, Serializable snapshot) {
this.key = key;
this.role = role;
this.storedSnapshot = snapshot;
}
/**
* After flushing, clear any "queued" additions, since the
* database state is now synchronized with the memory state.
*/
@Override
public void postAction() {
operationQueue = null;
cachedSize = -1;
clearDirty();
}
/**
* Not called by Hibernate, but used by non-JDK serialization,
* eg. SOAP libraries.
*/
public AbstractPersistentCollection() {
}
protected AbstractPersistentCollection(SessionImplementor session) {
this.session = session;
}
/**
* return the user-visible collection (or array) instance
*/
@Override
public Object getValue() {
return this;
}
/**
* Called just before reading any rows from the JDBC result set
*/
@Override
public void beginRead() {
// override on some subclasses
initializing = true;
}
/**
* Called after reading all rows from the JDBC result set
*/
@Override
public boolean endRead() {
//override on some subclasses
return afterInitialize();
}
@Override
public boolean afterInitialize() {
setInitialized();
//do this bit after setting initialized to true or it will recurse
@ -579,19 +585,12 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
this.directlyAccessible = directlyAccessible;
}
/**
* Could the application possibly have a direct reference to
* the underlying collection implementation?
*/
@Override
public boolean isDirectlyAccessible() {
return directlyAccessible;
}
/**
* Disassociate this collection from the given session.
*
* @return true if this was currently associated with the given session
*/
@Override
public final boolean unsetSession(SessionImplementor currentSession) {
prepareForPossibleSpecialSpecjInitialization();
if ( currentSession == this.session ) {
@ -619,21 +618,14 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
/**
* Associate the collection with the given session.
*
* @return false if the collection was already associated with the session
*
* @throws HibernateException if the collection was already associated
* with another open session
*/
@Override
public final boolean setCurrentSession(SessionImplementor session) throws HibernateException {
if ( session == this.session ) {
return false;
}
else {
if ( isConnectedToSession() ) {
CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
if ( ce == null ) {
throw new HibernateException(
"Illegal attempt to associate a collection with two open sessions"
@ -656,17 +648,12 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
/**
* Do we need to completely recreate this collection when it changes?
*/
@Override
public boolean needsRecreate(CollectionPersister persister) {
return false;
}
/**
* To be called internally by the session, forcing
* immediate initialization.
*/
@Override
public final void forceInitialization() throws HibernateException {
if ( !initialized ) {
if ( initializing ) {
@ -691,40 +678,38 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
return session.getPersistenceContext().getSnapshot( this );
}
/**
* Is this instance initialized?
*/
@Override
public final boolean wasInitialized() {
return initialized;
}
@Override
public boolean isRowUpdatePossible() {
return true;
}
/**
* Does this instance have any "queued" additions?
*/
@Override
public final boolean hasQueuedOperations() {
return operationQueue != null;
}
/**
* Iterate the "queued" additions
*/
@Override
public final Iterator queuedAdditionIterator() {
if ( hasQueuedOperations() ) {
return new Iterator() {
int i = 0;
private int index;
@Override
public Object next() {
return operationQueue.get( i++ ).getAddedInstance();
return operationQueue.get( index++ ).getAddedInstance();
}
@Override
public boolean hasNext() {
return i < operationQueue.size();
return index < operationQueue.size();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@ -735,14 +720,12 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
/**
* Iterate the "queued" additions
*/
@Override
@SuppressWarnings({"unchecked"})
public final Collection getQueuedOrphans(String entityName) {
if ( hasQueuedOperations() ) {
Collection additions = new ArrayList( operationQueue.size() );
Collection removals = new ArrayList( operationQueue.size() );
final Collection additions = new ArrayList( operationQueue.size() );
final Collection removals = new ArrayList( operationQueue.size() );
for ( DelayedOperation operation : operationQueue ) {
additions.add( operation.getAddedInstance() );
removals.add( operation.getOrphan() );
@ -754,28 +737,22 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
/**
* Called before inserting rows, to ensure that any surrogate keys
* are fully generated
*/
@Override
public void preInsert(CollectionPersister persister) throws HibernateException {
}
/**
* Called after inserting a row, to fetch the natively generated id
*/
@Override
public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {
}
/**
* get all "orphaned" elements
*/
@Override
public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
/**
* Get the current session
* Get the session currently associated with this collection.
*
* @return The session
*/
@SuppressWarnings({"JavaDoc"})
public final SessionImplementor getSession() {
return session;
}
@ -787,19 +764,21 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
this.itr = itr;
}
@Override
public boolean hasNext() {
return itr.hasNext();
}
@Override
public Object next() {
return itr.next();
}
@Override
public void remove() {
write();
itr.remove();
}
}
protected final class ListIteratorProxy implements ListIterator {
@ -809,47 +788,55 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
this.itr = itr;
}
@Override
@SuppressWarnings({"unchecked"})
public void add(Object o) {
write();
itr.add( o );
}
@Override
public boolean hasNext() {
return itr.hasNext();
}
@Override
public boolean hasPrevious() {
return itr.hasPrevious();
}
@Override
public Object next() {
return itr.next();
}
@Override
public int nextIndex() {
return itr.nextIndex();
}
@Override
public Object previous() {
return itr.previous();
}
@Override
public int previousIndex() {
return itr.previousIndex();
}
@Override
public void remove() {
write();
itr.remove();
}
@Override
@SuppressWarnings({"unchecked"})
public void set(Object o) {
write();
itr.set( o );
}
}
protected class SetProxy implements java.util.Set {
@ -859,67 +846,82 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
this.set = set;
}
@Override
@SuppressWarnings({"unchecked"})
public boolean add(Object o) {
write();
return set.add( o );
}
@Override
@SuppressWarnings({"unchecked"})
public boolean addAll(Collection c) {
write();
return set.addAll( c );
}
@Override
public void clear() {
write();
set.clear();
}
@Override
public boolean contains(Object o) {
return set.contains( o );
}
@Override
@SuppressWarnings("unchecked")
public boolean containsAll(Collection c) {
return set.containsAll( c );
}
@Override
public boolean isEmpty() {
return set.isEmpty();
}
@Override
public Iterator iterator() {
return new IteratorProxy( set.iterator() );
}
@Override
public boolean remove(Object o) {
write();
return set.remove( o );
}
@Override
@SuppressWarnings("unchecked")
public boolean removeAll(Collection c) {
write();
return set.removeAll( c );
}
@Override
@SuppressWarnings("unchecked")
public boolean retainAll(Collection c) {
write();
return set.retainAll( c );
}
@Override
public int size() {
return set.size();
}
@Override
public Object[] toArray() {
return set.toArray();
}
@Override
@SuppressWarnings({"unchecked"})
public Object[] toArray(Object[] array) {
return set.toArray( array );
}
}
protected final class ListProxy implements java.util.List {
@ -969,6 +971,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
@Override
@SuppressWarnings("unchecked")
public boolean containsAll(Collection c) {
return list.containsAll( c );
}
@ -1021,12 +1024,14 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
@Override
@SuppressWarnings("unchecked")
public boolean removeAll(Collection c) {
write();
return list.removeAll( c );
}
@Override
@SuppressWarnings("unchecked")
public boolean retainAll(Collection c) {
write();
return list.retainAll( c );
@ -1087,29 +1092,31 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
// short-circuit(s)
if ( currentElements.size() == 0 ) {
return oldElements; // no new elements, the old list contains only Orphans
// no new elements, the old list contains only Orphans
return oldElements;
}
if ( oldElements.size() == 0 ) {
return oldElements; // no old elements, so no Orphans neither
// no old elements, so no Orphans neither
return oldElements;
}
final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
final Type idType = entityPersister.getIdentifierType();
// create the collection holding the Orphans
Collection res = new ArrayList();
final Collection res = new ArrayList();
// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
java.util.Set currentIds = new HashSet();
java.util.Set currentSaving = new IdentitySet();
final java.util.Set currentIds = new HashSet();
final java.util.Set currentSaving = new IdentitySet();
for ( Object current : currentElements ) {
if ( current != null && ForeignKeys.isNotTransient( entityName, current, null, session ) ) {
EntityEntry ee = session.getPersistenceContext().getEntry( current );
final EntityEntry ee = session.getPersistenceContext().getEntry( current );
if ( ee != null && ee.getStatus() == Status.SAVING ) {
currentSaving.add( current );
}
else {
Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(
final Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(
entityName,
current,
session
@ -1122,7 +1129,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
// iterate over the *old* list
for ( Object old : oldElements ) {
if ( !currentSaving.contains( old ) ) {
Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, old, session );
final Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, old, session );
if ( !currentIds.contains( new TypedValue( idType, oldId ) ) ) {
res.add( old );
}
@ -1132,20 +1139,28 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
return res;
}
/**
* Removes entity entries that have an equal identifier with the incoming entity instance
*
* @param list The list containing the entity instances
* @param entityInstance The entity instance to match elements.
* @param entityName The entity name
* @param session The session
*/
public static void identityRemove(
Collection list,
Object object,
Object entityInstance,
String entityName,
SessionImplementor session) throws HibernateException {
SessionImplementor session) {
if ( object != null && ForeignKeys.isNotTransient( entityName, object, null, session ) ) {
if ( entityInstance != null && ForeignKeys.isNotTransient( entityName, entityInstance, null, session ) ) {
final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
Type idType = entityPersister.getIdentifierType();
final Type idType = entityPersister.getIdentifierType();
Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, object, session );
Iterator itr = list.iterator();
final Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, entityInstance, session );
final Iterator itr = list.iterator();
while ( itr.hasNext() ) {
Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, itr.next(), session );
final Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, itr.next(), session );
if ( idType.isEqual( idOfCurrent, idOfOld, session.getFactory() ) ) {
itr.remove();
break;
@ -1155,14 +1170,17 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
}
}
@Override
public Object getIdentifier(Object entry, int i) {
throw new UnsupportedOperationException();
}
@Override
public Object getOwner() {
return owner;
}
@Override
public void setOwner(Object owner) {
this.owner = owner;
}

View File

@ -29,6 +29,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import org.jboss.logging.Logger;
@ -48,27 +49,52 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public class PersistentArrayHolder extends AbstractPersistentCollection {
protected Object array;
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
PersistentArrayHolder.class.getName()
);
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, PersistentArrayHolder.class.getName());
protected Object array;
//just to help out during the load (ugly, i know)
private transient Class elementClass;
private transient java.util.List tempList;
/**
* Constructs a PersistentCollection instance for holding an array.
*
* @param session The session
* @param array The array (the persistent "collection").
*/
public PersistentArrayHolder(SessionImplementor session, Object array) {
super(session);
super( session );
this.array = array;
setInitialized();
}
/**
* Constructs a PersistentCollection instance for holding an array.
*
* @param session The session
* @param persister The persister for the array
*/
public PersistentArrayHolder(SessionImplementor session, CollectionPersister persister) {
super( session );
elementClass = persister.getElementClass();
}
@Override
public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
int length = /*(array==null) ? tempList.size() :*/ Array.getLength(array);
Serializable result = (Serializable) Array.newInstance( persister.getElementClass(), length );
// final int length = (array==null) ? tempList.size() : Array.getLength( array );
final int length = Array.getLength( array );
final Serializable result = (Serializable) Array.newInstance( persister.getElementClass(), length );
for ( int i=0; i<length; i++ ) {
Object elt = /*(array==null) ? tempList.get(i) :*/ Array.get(array, i);
// final Object elt = (array==null) ? tempList.get( i ) : Array.get( array, i );
final Object elt = Array.get( array, i );
try {
Array.set( result, i, persister.getElementType().deepCopy(elt, persister.getFactory()) );
Array.set( result, i, persister.getElementType().deepCopy( elt, persister.getFactory() ) );
}
catch (IllegalArgumentException iae) {
LOG.invalidArrayElementType( iae.getMessage() );
@ -78,70 +104,84 @@ public class PersistentArrayHolder extends AbstractPersistentCollection {
return result;
}
@Override
public boolean isSnapshotEmpty(Serializable snapshot) {
return Array.getLength( snapshot ) == 0;
}
@Override
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
Object[] sn = (Object[]) snapshot;
Object[] arr = (Object[]) array;
ArrayList result = new ArrayList();
for (int i=0; i<sn.length; i++) result.add( sn[i] );
for (int i=0; i<sn.length; i++) identityRemove( result, arr[i], entityName, getSession() );
final Object[] sn = (Object[]) snapshot;
final Object[] arr = (Object[]) array;
final ArrayList result = new ArrayList();
Collections.addAll( result, sn );
for ( int i=0; i<sn.length; i++ ) {
identityRemove( result, arr[i], entityName, getSession() );
}
return result;
}
public PersistentArrayHolder(SessionImplementor session, CollectionPersister persister) throws HibernateException {
super(session);
elementClass = persister.getElementClass();
}
@SuppressWarnings("UnusedDeclaration")
public Object getArray() {
return array;
}
@Override
public boolean isWrapper(Object collection) {
return array==collection;
}
@Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
Type elementType = persister.getElementType();
Serializable snapshot = getSnapshot();
int xlen = Array.getLength(snapshot);
if ( xlen!= Array.getLength(array) ) return false;
final Type elementType = persister.getElementType();
final Serializable snapshot = getSnapshot();
final int xlen = Array.getLength( snapshot );
if ( xlen!= Array.getLength( array ) ) {
return false;
}
for ( int i=0; i<xlen; i++) {
if ( elementType.isDirty( Array.get(snapshot, i), Array.get(array, i), getSession() ) ) return false;
if ( elementType.isDirty( Array.get( snapshot, i ), Array.get( array, i ), getSession() ) ) {
return false;
}
}
return true;
}
/**
* Get an iterator over the array elements
*
* @return The iterator
*/
@SuppressWarnings("unchecked")
public Iterator elements() {
//if (array==null) return tempList.iterator();
int length = Array.getLength(array);
java.util.List list = new ArrayList(length);
for (int i=0; i<length; i++) {
list.add( Array.get(array, i) );
final int length = Array.getLength( array );
final java.util.List list = new ArrayList( length );
for ( int i=0; i<length; i++ ) {
list.add( Array.get( array, i ) );
}
return list.iterator();
}
@Override
public boolean empty() {
return false;
}
@Override
@SuppressWarnings("unchecked")
public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException {
Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
int index = (Integer) persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
final int index = (Integer) persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
for ( int i = tempList.size(); i<=index; i++) {
tempList.add(i, null);
tempList.add( i, null );
}
tempList.set(index, element);
tempList.set( index, element );
return element;
}
@Override
@SuppressWarnings("unchecked")
public Iterator entries(CollectionPersister persister) {
return elements();
}
@ -151,17 +191,19 @@ public class PersistentArrayHolder extends AbstractPersistentCollection {
super.beginRead();
tempList = new ArrayList();
}
@Override
public boolean endRead() {
setInitialized();
array = Array.newInstance( elementClass, tempList.size() );
for ( int i=0; i<tempList.size(); i++) {
Array.set(array, i, tempList.get(i) );
for ( int i=0; i<tempList.size(); i++ ) {
Array.set( array, i, tempList.get( i ) );
}
tempList=null;
tempList = null;
return true;
}
@Override
public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
//if (tempList==null) throw new UnsupportedOperationException("Can't lazily initialize arrays");
}
@ -171,10 +213,10 @@ public class PersistentArrayHolder extends AbstractPersistentCollection {
return true;
}
@Override
public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
throws HibernateException {
Serializable[] cached = (Serializable[]) disassembled;
final Serializable[] cached = (Serializable[]) disassembled;
array = Array.newInstance( persister.getElementClass(), cached.length );
for ( int i=0; i<cached.length; i++ ) {
@ -182,21 +224,15 @@ public class PersistentArrayHolder extends AbstractPersistentCollection {
}
}
@Override
public Serializable disassemble(CollectionPersister persister) throws HibernateException {
int length = Array.getLength(array);
Serializable[] result = new Serializable[length];
final int length = Array.getLength( array );
final Serializable[] result = new Serializable[length];
for ( int i=0; i<length; i++ ) {
result[i] = persister.getElementType().disassemble( Array.get(array,i), getSession(), null );
result[i] = persister.getElementType().disassemble( Array.get( array,i ), getSession(), null );
}
/*int length = tempList.size();
Serializable[] result = new Serializable[length];
for ( int i=0; i<length; i++ ) {
result[i] = persister.getElementType().disassemble( tempList.get(i), session );
}*/
return result;
}
@Override
@ -204,52 +240,63 @@ public class PersistentArrayHolder extends AbstractPersistentCollection {
return array;
}
@Override
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
java.util.List<Integer> deletes = new ArrayList<Integer>();
Serializable sn = getSnapshot();
int snSize = Array.getLength(sn);
int arraySize = Array.getLength(array);
final java.util.List<Integer> deletes = new ArrayList<Integer>();
final Serializable sn = getSnapshot();
final int snSize = Array.getLength( sn );
final int arraySize = Array.getLength( array );
int end;
if ( snSize > arraySize ) {
for ( int i=arraySize; i<snSize; i++ ) deletes.add( i );
for ( int i=arraySize; i<snSize; i++ ) {
deletes.add( i );
}
end = arraySize;
}
else {
end = snSize;
}
for ( int i=0; i<end; i++ ) {
if ( Array.get(array, i)==null && Array.get(sn, i)!=null ) deletes.add( i );
if ( Array.get( array, i ) == null && Array.get( sn, i ) != null ) {
deletes.add( i );
}
}
return deletes.iterator();
}
@Override
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
Serializable sn = getSnapshot();
return Array.get(array, i)!=null && ( i >= Array.getLength(sn) || Array.get(sn, i)==null );
final Serializable sn = getSnapshot();
return Array.get( array, i ) != null && ( i >= Array.getLength( sn ) || Array.get( sn, i ) == null );
}
@Override
public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException {
Serializable sn = getSnapshot();
return i<Array.getLength(sn) &&
Array.get(sn, i)!=null &&
Array.get(array, i)!=null &&
elemType.isDirty( Array.get(array, i), Array.get(sn, i), getSession() );
final Serializable sn = getSnapshot();
return i < Array.getLength( sn )
&& Array.get( sn, i ) != null
&& Array.get( array, i ) != null
&& elemType.isDirty( Array.get( array, i ), Array.get( sn, i ), getSession() );
}
@Override
public Object getIndex(Object entry, int i, CollectionPersister persister) {
return i;
}
@Override
public Object getElement(Object entry) {
return entry;
}
@Override
public Object getSnapshotElement(Object entry, int i) {
Serializable sn = getSnapshot();
return Array.get(sn, i);
final Serializable sn = getSnapshot();
return Array.get( sn, i );
}
@Override
public boolean entryExists(Object entry, int i) {
return entry!=null;
return entry != null;
}
}

View File

@ -50,59 +50,86 @@ public class PersistentBag extends AbstractPersistentCollection implements List
protected List bag;
public PersistentBag(SessionImplementor session) {
super(session);
/**
* Constructs a PersistentBag. Needed for SOAP libraries, etc
*/
@SuppressWarnings("UnusedDeclaration")
public PersistentBag() {
}
/**
* Constructs a PersistentBag
*
* @param session The session
*/
public PersistentBag(SessionImplementor session) {
super( session );
}
/**
* Constructs a PersistentBag
*
* @param session The session
* @param coll The base elements.
*/
@SuppressWarnings("unchecked")
public PersistentBag(SessionImplementor session, Collection coll) {
super(session);
if (coll instanceof List) {
super( session );
if ( coll instanceof List ) {
bag = (List) coll;
}
else {
bag = new ArrayList();
Iterator iter = coll.iterator();
while ( iter.hasNext() ) {
bag.add( iter.next() );
for ( Object element : coll ) {
bag.add( element );
}
}
setInitialized();
setDirectlyAccessible(true);
setDirectlyAccessible( true );
}
public PersistentBag() {} //needed for SOAP libraries, etc
@Override
public boolean isWrapper(Object collection) {
return bag==collection;
}
@Override
public boolean empty() {
return bag.isEmpty();
}
@Override
public Iterator entries(CollectionPersister persister) {
return bag.iterator();
}
@Override
@SuppressWarnings("unchecked")
public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException {
// note that if we load this collection from a cartesian product
// the multiplicity would be broken ... so use an idbag instead
Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
if (element!=null) bag.add(element);
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
if ( element != null ) {
bag.add( element );
}
return element;
}
@Override
public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
this.bag = ( List ) persister.getCollectionType().instantiate( anticipatedSize );
this.bag = (List) persister.getCollectionType().instantiate( anticipatedSize );
}
@Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
Type elementType = persister.getElementType();
List sn = (List) getSnapshot();
if ( sn.size()!=bag.size() ) return false;
final Type elementType = persister.getElementType();
final List sn = (List) getSnapshot();
if ( sn.size() != bag.size() ) {
return false;
}
for ( Object elt : bag ) {
final boolean unequal = countOccurrences( elt, bag, elementType )
!= countOccurrences( elt, sn, elementType );
final boolean unequal = countOccurrences( elt, bag, elementType ) != countOccurrences( elt, sn, elementType );
if ( unequal ) {
return false;
}
@ -110,60 +137,67 @@ public class PersistentBag extends AbstractPersistentCollection implements List
return true;
}
@Override
public boolean isSnapshotEmpty(Serializable snapshot) {
return ( (Collection) snapshot ).isEmpty();
}
private int countOccurrences(Object element, List list, Type elementType)
throws HibernateException {
Iterator iter = list.iterator();
int result=0;
final Iterator iter = list.iterator();
int result = 0;
while ( iter.hasNext() ) {
if ( elementType.isSame( element, iter.next() ) ) result++;
if ( elementType.isSame( element, iter.next() ) ) {
result++;
}
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public Serializable getSnapshot(CollectionPersister persister)
throws HibernateException {
ArrayList clonedList = new ArrayList( bag.size() );
Iterator iter = bag.iterator();
while ( iter.hasNext() ) {
clonedList.add( persister.getElementType().deepCopy( iter.next(), persister.getFactory() ) );
final ArrayList clonedList = new ArrayList( bag.size() );
for ( Object item : bag ) {
clonedList.add( persister.getElementType().deepCopy( item, persister.getFactory() ) );
}
return clonedList;
}
@Override
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
List sn = (List) snapshot;
final List sn = (List) snapshot;
return getOrphans( sn, bag, entityName, getSession() );
}
@Override
public Serializable disassemble(CollectionPersister persister)
throws HibernateException {
int length = bag.size();
Serializable[] result = new Serializable[length];
final int length = bag.size();
final Serializable[] result = new Serializable[length];
for ( int i=0; i<length; i++ ) {
result[i] = persister.getElementType().disassemble( bag.get(i), getSession(), null );
result[i] = persister.getElementType().disassemble( bag.get( i ), getSession(), null );
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
throws HibernateException {
Serializable[] array = (Serializable[]) disassembled;
int size = array.length;
final Serializable[] array = (Serializable[]) disassembled;
final int size = array.length;
beforeInitialize( persister, size );
for ( int i = 0; i < size; i++ ) {
Object element = persister.getElementType().assemble( array[i], getSession(), owner );
if ( element!=null ) {
for ( Serializable item : array ) {
final Object element = persister.getElementType().assemble( item, getSession(), owner );
if ( element != null ) {
bag.add( element );
}
}
}
@Override
public boolean needsRecreate(CollectionPersister persister) {
return !persister.isOneToMany();
}
@ -177,18 +211,19 @@ public class PersistentBag extends AbstractPersistentCollection implements List
// Anyway, here we implement <set> semantics for a
// <one-to-many> <bag>!
@Override
@SuppressWarnings("unchecked")
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
//if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
Type elementType = persister.getElementType();
ArrayList deletes = new ArrayList();
List sn = (List) getSnapshot();
Iterator olditer = sn.iterator();
final Type elementType = persister.getElementType();
final ArrayList deletes = new ArrayList();
final List sn = (List) getSnapshot();
final Iterator olditer = sn.iterator();
int i=0;
while ( olditer.hasNext() ) {
Object old = olditer.next();
Iterator newiter = bag.iterator();
final Object old = olditer.next();
final Iterator newiter = bag.iterator();
boolean found = false;
if ( bag.size()>i && elementType.isSame( old, bag.get(i++) ) ) {
if ( bag.size()>i && elementType.isSame( old, bag.get( i++ ) ) ) {
//a shortcut if its location didn't change!
found = true;
}
@ -202,104 +237,91 @@ public class PersistentBag extends AbstractPersistentCollection implements List
}
}
}
if (!found) deletes.add(old);
if ( !found ) {
deletes.add( old );
}
}
return deletes.iterator();
}
@Override
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
//if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
List sn = (List) getSnapshot();
if ( sn.size()>i && elemType.isSame( sn.get(i), entry ) ) {
final List sn = (List) getSnapshot();
if ( sn.size() > i && elemType.isSame( sn.get( i ), entry ) ) {
//a shortcut if its location didn't change!
return false;
}
else {
//search for it
//note that this code is incorrect for other than one-to-many
Iterator olditer = sn.iterator();
while ( olditer.hasNext() ) {
Object old = olditer.next();
if ( elemType.isSame( old, entry ) ) return false;
for ( Object old : sn ) {
if ( elemType.isSame( old, entry ) ) {
return false;
}
}
return true;
}
}
@Override
public boolean isRowUpdatePossible() {
return false;
}
@Override
public boolean needsUpdating(Object entry, int i, Type elemType) {
//if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
return false;
}
/**
* @see java.util.Collection#size()
*/
@Override
public int size() {
return readSize() ? getCachedSize() : bag.size();
}
/**
* @see java.util.Collection#isEmpty()
*/
@Override
public boolean isEmpty() {
return readSize() ? getCachedSize()==0 : bag.isEmpty();
}
/**
* @see java.util.Collection#contains(Object)
*/
@Override
@SuppressWarnings("UnnecessaryUnboxing")
public boolean contains(Object object) {
Boolean exists = readElementExistence(object);
return exists==null ?
bag.contains(object) :
exists.booleanValue();
final Boolean exists = readElementExistence( object );
return exists == null ? bag.contains( object ) : exists.booleanValue();
}
/**
* @see java.util.Collection#iterator()
*/
@Override
public Iterator iterator() {
read();
return new IteratorProxy( bag.iterator() );
}
/**
* @see java.util.Collection#toArray()
*/
@Override
public Object[] toArray() {
read();
return bag.toArray();
}
/**
* @see java.util.Collection#toArray(Object[])
*/
@Override
public Object[] toArray(Object[] a) {
read();
return bag.toArray(a);
return bag.toArray( a );
}
/**
* @see java.util.Collection#add(Object)
*/
@Override
@SuppressWarnings("unchecked")
public boolean add(Object object) {
if ( !isOperationQueueEnabled() ) {
write();
return bag.add(object);
return bag.add( object );
}
else {
queueOperation( new SimpleAdd(object) );
queueOperation( new SimpleAdd( object ) );
return true;
}
}
/**
* @see java.util.Collection#remove(Object)
*/
@Override
public boolean remove(Object o) {
initialize( true );
if ( bag.remove( o ) ) {
@ -311,35 +333,33 @@ public class PersistentBag extends AbstractPersistentCollection implements List
}
}
/**
* @see java.util.Collection#containsAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean containsAll(Collection c) {
read();
return bag.containsAll(c);
return bag.containsAll( c );
}
/**
* @see java.util.Collection#addAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean addAll(Collection values) {
if ( values.size()==0 ) return false;
if ( values.size()==0 ) {
return false;
}
if ( !isOperationQueueEnabled() ) {
write();
return bag.addAll(values);
return bag.addAll( values );
}
else {
Iterator iter = values.iterator();
while ( iter.hasNext() ) {
queueOperation( new SimpleAdd( iter.next() ) );
for ( Object value : values ) {
queueOperation( new SimpleAdd( value ) );
}
return values.size()>0;
}
}
/**
* @see java.util.Collection#removeAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean removeAll(Collection c) {
if ( c.size()>0 ) {
initialize( true );
@ -356,9 +376,8 @@ public class PersistentBag extends AbstractPersistentCollection implements List
}
}
/**
* @see java.util.Collection#retainAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean retainAll(Collection c) {
initialize( true );
if ( bag.retainAll( c ) ) {
@ -370,9 +389,8 @@ public class PersistentBag extends AbstractPersistentCollection implements List
}
}
/**
* @see java.util.Collection#clear()
*/
@Override
@SuppressWarnings("unchecked")
public void clear() {
if ( isClearQueueEnabled() ) {
queueOperation( new Clear() );
@ -386,160 +404,161 @@ public class PersistentBag extends AbstractPersistentCollection implements List
}
}
@Override
public Object getIndex(Object entry, int i, CollectionPersister persister) {
throw new UnsupportedOperationException("Bags don't have indexes");
}
@Override
public Object getElement(Object entry) {
return entry;
}
@Override
public Object getSnapshotElement(Object entry, int i) {
List sn = (List) getSnapshot();
return sn.get(i);
final List sn = (List) getSnapshot();
return sn.get( i );
}
/**
* Count how many times the given object occurs in the elements
*
* @param o The object to check
*
* @return The number of occurences.
*/
@SuppressWarnings("UnusedDeclaration")
public int occurrences(Object o) {
read();
Iterator iter = bag.iterator();
int result=0;
while ( iter.hasNext() ) {
if ( o.equals( iter.next() ) ) result++;
final Iterator itr = bag.iterator();
int result = 0;
while ( itr.hasNext() ) {
if ( o.equals( itr.next() ) ) {
result++;
}
}
return result;
}
// List OPERATIONS:
/**
* @see java.util.List#add(int, Object)
*/
@Override
@SuppressWarnings("unchecked")
public void add(int i, Object o) {
write();
bag.add(i, o);
bag.add( i, o );
}
/**
* @see java.util.List#addAll(int, Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean addAll(int i, Collection c) {
if ( c.size()>0 ) {
if ( c.size() > 0 ) {
write();
return bag.addAll(i, c);
return bag.addAll( i, c );
}
else {
return false;
}
}
/**
* @see java.util.List#get(int)
*/
@Override
@SuppressWarnings("unchecked")
public Object get(int i) {
read();
return bag.get(i);
return bag.get( i );
}
/**
* @see java.util.List#indexOf(Object)
*/
@Override
@SuppressWarnings("unchecked")
public int indexOf(Object o) {
read();
return bag.indexOf(o);
return bag.indexOf( o );
}
/**
* @see java.util.List#lastIndexOf(Object)
*/
@Override
@SuppressWarnings("unchecked")
public int lastIndexOf(Object o) {
read();
return bag.lastIndexOf(o);
return bag.lastIndexOf( o );
}
/**
* @see java.util.List#listIterator()
*/
@Override
@SuppressWarnings("unchecked")
public ListIterator listIterator() {
read();
return new ListIteratorProxy( bag.listIterator() );
}
/**
* @see java.util.List#listIterator(int)
*/
@Override
@SuppressWarnings("unchecked")
public ListIterator listIterator(int i) {
read();
return new ListIteratorProxy( bag.listIterator(i) );
return new ListIteratorProxy( bag.listIterator( i ) );
}
/**
* @see java.util.List#remove(int)
*/
@Override
@SuppressWarnings("unchecked")
public Object remove(int i) {
write();
return bag.remove(i);
return bag.remove( i );
}
/**
* @see java.util.List#set(int, Object)
*/
@Override
@SuppressWarnings("unchecked")
public Object set(int i, Object o) {
write();
return bag.set(i, o);
return bag.set( i, o );
}
/**
* @see java.util.List#subList(int, int)
*/
@Override
@SuppressWarnings("unchecked")
public List subList(int start, int end) {
read();
return new ListProxy( bag.subList(start, end) );
return new ListProxy( bag.subList( start, end ) );
}
@Override
public boolean entryExists(Object entry, int i) {
return entry!=null;
}
@Override
public String toString() {
read();
return bag.toString();
}
/*public boolean equals(Object other) {
read();
return bag.equals(other);
}
public int hashCode(Object other) {
read();
return bag.hashCode();
}*/
public boolean entryExists(Object entry, int i) {
return entry!=null;
}
/**
* Bag does not respect the collection API and do an
* JVM instance comparison to do the equals.
* The semantic is broken not to have to initialize a
* collection for a simple equals() operation.
* @see java.lang.Object#equals(java.lang.Object)
*
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
return super.equals(obj);
return super.equals( obj );
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return super.hashCode();
}
final class Clear implements DelayedOperation {
@Override
public void operate() {
bag.clear();
}
@Override
public Object getAddedInstance() {
return null;
}
@Override
public Object getOrphan() {
throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
}
@ -551,12 +570,19 @@ public class PersistentBag extends AbstractPersistentCollection implements List
public SimpleAdd(Object value) {
this.value = value;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
bag.add(value);
bag.add( value );
}
@Override
public Object getAddedInstance() {
return value;
}
@Override
public Object getOrphan() {
return null;
}

View File

@ -53,37 +53,53 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public class PersistentIdentifierBag extends AbstractPersistentCollection implements List {
protected List<Object> values;
protected Map<Integer, Object> identifiers;
protected List values; //element
protected Map identifiers; //index -> id
public PersistentIdentifierBag(SessionImplementor session) {
super(session);
/**
* Constructs a PersistentIdentifierBag. This form needed for SOAP libraries, etc
*/
@SuppressWarnings("UnusedDeclaration")
public PersistentIdentifierBag() {
}
public PersistentIdentifierBag() {} //needed for SOAP libraries, etc
/**
* Constructs a PersistentIdentifierBag.
*
* @param session The session
*/
public PersistentIdentifierBag(SessionImplementor session) {
super( session );
}
/**
* Constructs a PersistentIdentifierBag.
*
* @param session The session
* @param coll The base elements
*/
@SuppressWarnings("unchecked")
public PersistentIdentifierBag(SessionImplementor session, Collection coll) {
super(session);
super( session );
if (coll instanceof List) {
values = (List) coll;
values = (List<Object>) coll;
}
else {
values = new ArrayList();
Iterator iter = coll.iterator();
while ( iter.hasNext() ) {
values.add( iter.next() );
values = new ArrayList<Object>();
for ( Object element : coll ) {
values.add( element );
}
}
setInitialized();
setDirectlyAccessible(true);
identifiers = new HashMap();
setDirectlyAccessible( true );
identifiers = new HashMap<Integer, Object>();
}
@Override
public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
throws HibernateException {
Serializable[] array = (Serializable[]) disassembled;
int size = array.length;
final Serializable[] array = (Serializable[]) disassembled;
final int size = array.length;
beforeInitialize( persister, size );
for ( int i = 0; i < size; i+=2 ) {
identifiers.put(
@ -94,20 +110,24 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
}
}
@Override
public Object getIdentifier(Object entry, int i) {
return identifiers.get( i );
}
@Override
public boolean isWrapper(Object collection) {
return values==collection;
}
@Override
public boolean add(Object o) {
write();
values.add(o);
values.add( o );
return true;
}
@Override
public void clear() {
initialize( true );
if ( ! values.isEmpty() || ! identifiers.isEmpty() ) {
@ -117,31 +137,36 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
}
}
@Override
public boolean contains(Object o) {
read();
return values.contains(o);
return values.contains( o );
}
@Override
public boolean containsAll(Collection c) {
read();
return values.containsAll(c);
return values.containsAll( c );
}
@Override
public boolean isEmpty() {
return readSize() ? getCachedSize()==0 : values.isEmpty();
}
@Override
public Iterator iterator() {
read();
return new IteratorProxy( values.iterator() );
}
@Override
public boolean remove(Object o) {
initialize( true );
int index = values.indexOf(o);
if (index>=0) {
beforeRemove(index);
values.remove(index);
final int index = values.indexOf( o );
if ( index >= 0 ) {
beforeRemove( index );
values.remove( index );
dirty();
return true;
}
@ -150,12 +175,14 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
}
}
@Override
public boolean removeAll(Collection c) {
if ( c.size() > 0 ) {
boolean result = false;
Iterator iter = c.iterator();
while ( iter.hasNext() ) {
if ( remove( iter.next() ) ) result=true;
for ( Object element : c ) {
if ( remove( element ) ) {
result = true;
}
}
return result;
}
@ -164,6 +191,7 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
}
}
@Override
public boolean retainAll(Collection c) {
initialize( true );
if ( values.retainAll( c ) ) {
@ -175,168 +203,210 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
}
}
@Override
public int size() {
return readSize() ? getCachedSize() : values.size();
}
@Override
public Object[] toArray() {
read();
return values.toArray();
}
@Override
public Object[] toArray(Object[] a) {
read();
return values.toArray(a);
return values.toArray( a );
}
@Override
public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
identifiers = anticipatedSize <= 0 ? new HashMap() : new HashMap( anticipatedSize + 1 + (int)( anticipatedSize * .75f ), .75f );
values = anticipatedSize <= 0 ? new ArrayList() : new ArrayList( anticipatedSize );
identifiers = anticipatedSize <= 0
? new HashMap<Integer, Object>()
: new HashMap<Integer, Object>( anticipatedSize + 1 + (int)( anticipatedSize * .75f ), .75f );
values = anticipatedSize <= 0
? new ArrayList<Object>()
: new ArrayList<Object>( anticipatedSize );
}
@Override
public Serializable disassemble(CollectionPersister persister)
throws HibernateException {
Serializable[] result = new Serializable[ values.size() * 2 ];
int i=0;
for (int j=0; j< values.size(); j++) {
Object value = values.get(j);
final Serializable[] result = new Serializable[ values.size() * 2 ];
int i = 0;
for ( int j=0; j< values.size(); j++ ) {
final Object value = values.get( j );
result[i++] = persister.getIdentifierType().disassemble( identifiers.get( j ), getSession(), null );
result[i++] = persister.getElementType().disassemble( value, getSession(), null );
}
return result;
}
@Override
public boolean empty() {
return values.isEmpty();
}
@Override
public Iterator entries(CollectionPersister persister) {
return values.iterator();
}
@Override
public boolean entryExists(Object entry, int i) {
return entry!=null;
}
@Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
Type elementType = persister.getElementType();
Map snap = (Map) getSnapshot();
if ( snap.size()!= values.size() ) return false;
final Type elementType = persister.getElementType();
final Map snap = (Map) getSnapshot();
if ( snap.size()!= values.size() ) {
return false;
}
for ( int i=0; i<values.size(); i++ ) {
Object value = values.get(i);
Object id = identifiers.get( i );
if (id==null) return false;
Object old = snap.get(id);
if ( elementType.isDirty( old, value, getSession() ) ) return false;
final Object value = values.get( i );
final Object id = identifiers.get( i );
if ( id == null ) {
return false;
}
final Object old = snap.get( id );
if ( elementType.isDirty( old, value, getSession() ) ) {
return false;
}
}
return true;
}
@Override
public boolean isSnapshotEmpty(Serializable snapshot) {
return ( (Map) snapshot ).isEmpty();
}
@Override
@SuppressWarnings("unchecked")
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
Map snap = (Map) getSnapshot();
List deletes = new ArrayList( snap.keySet() );
final Map snap = (Map) getSnapshot();
final List deletes = new ArrayList( snap.keySet() );
for ( int i=0; i<values.size(); i++ ) {
if ( values.get(i)!=null ) deletes.remove( identifiers.get( i ) );
if ( values.get( i ) != null ) {
deletes.remove( identifiers.get( i ) );
}
}
return deletes.iterator();
}
@Override
public Object getIndex(Object entry, int i, CollectionPersister persister) {
throw new UnsupportedOperationException("Bags don't have indexes");
}
@Override
public Object getElement(Object entry) {
return entry;
}
@Override
public Object getSnapshotElement(Object entry, int i) {
Map snap = (Map) getSnapshot();
Object id = identifiers.get( i );
return snap.get(id);
final Map snap = (Map) getSnapshot();
final Object id = identifiers.get( i );
return snap.get( id );
}
@Override
public boolean needsInserting(Object entry, int i, Type elemType)
throws HibernateException {
Map snap = (Map) getSnapshot();
Object id = identifiers.get( i );
return entry!=null && ( id==null || snap.get(id)==null );
final Map snap = (Map) getSnapshot();
final Object id = identifiers.get( i );
return entry != null
&& ( id==null || snap.get( id )==null );
}
@Override
public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException {
if (entry==null) return false;
Map snap = (Map) getSnapshot();
Object id = identifiers.get( i );
if (id==null) return false;
Object old = snap.get(id);
return old!=null && elemType.isDirty( old, entry, getSession() );
if ( entry == null ) {
return false;
}
final Map snap = (Map) getSnapshot();
final Object id = identifiers.get( i );
if ( id == null ) {
return false;
}
final Object old = snap.get( id );
return old != null && elemType.isDirty( old, entry, getSession() );
}
@Override
public Object readFrom(
ResultSet rs,
CollectionPersister persister,
CollectionAliases descriptor,
Object owner)
throws HibernateException, SQLException {
Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
Object old = identifiers.put(
Object owner) throws HibernateException, SQLException {
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
final Object old = identifiers.put(
values.size(),
persister.readIdentifier( rs, descriptor.getSuffixedIdentifierAlias(), getSession() )
);
if ( old==null ) values.add(element); //maintain correct duplication if loaded in a cartesian product
if ( old == null ) {
//maintain correct duplication if loaded in a cartesian product
values.add( element );
}
return element;
}
@Override
@SuppressWarnings("unchecked")
public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
HashMap map = new HashMap( values.size() );
Iterator iter = values.iterator();
final HashMap map = new HashMap( values.size() );
final Iterator iter = values.iterator();
int i=0;
while ( iter.hasNext() ) {
Object value = iter.next();
final Object value = iter.next();
map.put(
identifiers.get( i++ ),
persister.getElementType().deepCopy(value, persister.getFactory())
persister.getElementType().deepCopy( value, persister.getFactory() )
);
}
return map;
}
@Override
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
Map sn = (Map) snapshot;
final Map sn = (Map) snapshot;
return getOrphans( sn.values(), values, entityName, getSession() );
}
@Override
public void preInsert(CollectionPersister persister) throws HibernateException {
Iterator iter = values.iterator();
int i=0;
while ( iter.hasNext() ) {
Object entry = iter.next();
Integer loc = i++;
if ( !identifiers.containsKey(loc) ) { //TODO: native ids
Serializable id = persister.getIdentifierGenerator().generate( getSession(), entry );
identifiers.put(loc, id);
final Iterator itr = values.iterator();
int i = 0;
while ( itr.hasNext() ) {
final Object entry = itr.next();
final Integer loc = i++;
if ( !identifiers.containsKey( loc ) ) {
//TODO: native ids
final Serializable id = persister.getIdentifierGenerator().generate( getSession(), entry );
identifiers.put( loc, id );
}
}
}
@Override
public void add(int index, Object element) {
write();
beforeAdd(index);
values.add(index, element);
beforeAdd( index );
values.add( index, element );
}
@Override
public boolean addAll(int index, Collection c) {
if ( c.size() > 0 ) {
Iterator iter = c.iterator();
while ( iter.hasNext() ) {
add( index++, iter.next() );
for ( Object element : c ) {
add( index++, element );
}
return true;
}
@ -345,37 +415,42 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
}
}
@Override
public Object get(int index) {
read();
return values.get(index);
return values.get( index );
}
@Override
public int indexOf(Object o) {
read();
return values.indexOf(o);
return values.indexOf( o );
}
@Override
public int lastIndexOf(Object o) {
read();
return values.lastIndexOf(o);
return values.lastIndexOf( o );
}
@Override
public ListIterator listIterator() {
read();
return new ListIteratorProxy( values.listIterator() );
}
@Override
public ListIterator listIterator(int index) {
read();
return new ListIteratorProxy( values.listIterator(index) );
return new ListIteratorProxy( values.listIterator( index ) );
}
private void beforeRemove(int index) {
Object removedId = identifiers.get( index );
int last = values.size()-1;
final Object removedId = identifiers.get( index );
final int last = values.size()-1;
for ( int i=index; i<last; i++ ) {
Object id = identifiers.get( i+1 );
if ( id==null ) {
final Object id = identifiers.get( i+1 );
if ( id == null ) {
identifiers.remove( i );
}
else {
@ -392,37 +467,41 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
identifiers.remove( index );
}
@Override
public Object remove(int index) {
write();
beforeRemove(index);
return values.remove(index);
beforeRemove( index );
return values.remove( index );
}
@Override
public Object set(int index, Object element) {
write();
return values.set(index, element);
return values.set( index, element );
}
@Override
public List subList(int fromIndex, int toIndex) {
read();
return new ListProxy( values.subList(fromIndex, toIndex) );
return new ListProxy( values.subList( fromIndex, toIndex ) );
}
@Override
public boolean addAll(Collection c) {
if ( c.size()> 0 ) {
write();
return values.addAll(c);
return values.addAll( c );
}
else {
return false;
}
}
@Override
public void afterRowInsert(
CollectionPersister persister,
Object entry,
int i)
throws HibernateException {
int i) throws HibernateException {
//TODO: if we are using identity columns, fetch the identifier
}

View File

@ -48,12 +48,40 @@ import org.hibernate.type.Type;
public class PersistentList extends AbstractPersistentCollection implements List {
protected List list;
/**
* Constructs a PersistentList. This form needed for SOAP libraries, etc
*/
public PersistentList() {
}
/**
* Constructs a PersistentList.
*
* @param session The session
*/
public PersistentList(SessionImplementor session) {
super( session );
}
/**
* Constructs a PersistentList.
*
* @param session The session
* @param list The raw list
*/
public PersistentList(SessionImplementor session, List list) {
super( session );
this.list = list;
setInitialized();
setDirectlyAccessible( true );
}
@Override
@SuppressWarnings( {"unchecked"})
public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
ArrayList clonedList = new ArrayList( list.size() );
final ArrayList clonedList = new ArrayList( list.size() );
for ( Object element : list ) {
Object deepCopy = persister.getElementType().deepCopy( element, persister.getFactory() );
final Object deepCopy = persister.getElementType().deepCopy( element, persister.getFactory() );
clonedList.add( deepCopy );
}
return clonedList;
@ -61,19 +89,23 @@ public class PersistentList extends AbstractPersistentCollection implements List
@Override
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
List sn = (List) snapshot;
final List sn = (List) snapshot;
return getOrphans( sn, list, entityName, getSession() );
}
@Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
Type elementType = persister.getElementType();
List sn = (List) getSnapshot();
if ( sn.size()!=this.list.size() ) return false;
Iterator iter = list.iterator();
Iterator sniter = sn.iterator();
while ( iter.hasNext() ) {
if ( elementType.isDirty( iter.next(), sniter.next(), getSession() ) ) return false;
final Type elementType = persister.getElementType();
final List sn = (List) getSnapshot();
if ( sn.size()!=this.list.size() ) {
return false;
}
final Iterator itr = list.iterator();
final Iterator snapshotItr = sn.iterator();
while ( itr.hasNext() ) {
if ( elementType.isDirty( itr.next(), snapshotItr.next(), getSession() ) ) {
return false;
}
}
return true;
}
@ -83,94 +115,70 @@ public class PersistentList extends AbstractPersistentCollection implements List
return ( (Collection) snapshot ).isEmpty();
}
public PersistentList(SessionImplementor session) {
super(session);
}
public PersistentList(SessionImplementor session, List list) {
super(session);
this.list = list;
setInitialized();
setDirectlyAccessible(true);
}
@Override
public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
this.list = ( List ) persister.getCollectionType().instantiate( anticipatedSize );
this.list = (List) persister.getCollectionType().instantiate( anticipatedSize );
}
@Override
public boolean isWrapper(Object collection) {
return list==collection;
}
public PersistentList() {} //needed for SOAP libraries, etc
/**
* @see java.util.List#size()
*/
@Override
public int size() {
return readSize() ? getCachedSize() : list.size();
}
/**
* @see java.util.List#isEmpty()
*/
@Override
public boolean isEmpty() {
return readSize() ? getCachedSize()==0 : list.isEmpty();
}
/**
* @see java.util.List#contains(Object)
*/
@Override
@SuppressWarnings("UnnecessaryUnboxing")
public boolean contains(Object object) {
Boolean exists = readElementExistence(object);
return exists==null ?
list.contains(object) :
exists.booleanValue();
final Boolean exists = readElementExistence( object );
return exists == null
? list.contains( object )
: exists.booleanValue();
}
/**
* @see java.util.List#iterator()
*/
@Override
public Iterator iterator() {
read();
return new IteratorProxy( list.iterator() );
}
/**
* @see java.util.List#toArray()
*/
@Override
public Object[] toArray() {
read();
return list.toArray();
}
/**
* @see java.util.List#toArray(Object[])
*/
@Override
public Object[] toArray(Object[] array) {
read();
return list.toArray(array);
return list.toArray( array );
}
/**
* @see java.util.List#add(Object)
*/
@Override
@SuppressWarnings("unchecked")
public boolean add(Object object) {
if ( !isOperationQueueEnabled() ) {
write();
return list.add(object);
return list.add( object );
}
else {
queueOperation( new SimpleAdd(object) );
queueOperation( new SimpleAdd( object ) );
return true;
}
}
/**
* @see java.util.List#remove(Object)
*/
@Override
@SuppressWarnings("UnnecessaryUnboxing")
public boolean remove(Object value) {
Boolean exists = isPutQueueEnabled() ? readElementExistence(value) : null;
final Boolean exists = isPutQueueEnabled() ? readElementExistence( value ) : null;
if ( exists == null ) {
initialize( true );
if ( list.remove( value ) ) {
@ -182,7 +190,7 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
}
else if ( exists.booleanValue() ) {
queueOperation( new SimpleRemove(value) );
queueOperation( new SimpleRemove( value ) );
return true;
}
else {
@ -190,50 +198,45 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
}
/**
* @see java.util.List#containsAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean containsAll(Collection coll) {
read();
return list.containsAll(coll);
return list.containsAll( coll );
}
/**
* @see java.util.List#addAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean addAll(Collection values) {
if ( values.size()==0 ) {
return false;
}
if ( !isOperationQueueEnabled() ) {
write();
return list.addAll(values);
return list.addAll( values );
}
else {
Iterator iter = values.iterator();
while ( iter.hasNext() ) {
queueOperation( new SimpleAdd( iter.next() ) );
for ( Object value : values ) {
queueOperation( new SimpleAdd( value ) );
}
return values.size()>0;
}
}
/**
* @see java.util.List#addAll(int, Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean addAll(int index, Collection coll) {
if ( coll.size()>0 ) {
write();
return list.addAll(index, coll);
return list.addAll( index, coll );
}
else {
return false;
}
}
/**
* @see java.util.List#removeAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean removeAll(Collection coll) {
if ( coll.size()>0 ) {
initialize( true );
@ -250,9 +253,8 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
}
/**
* @see java.util.List#retainAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean retainAll(Collection coll) {
initialize( true );
if ( list.retainAll( coll ) ) {
@ -264,9 +266,8 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
}
/**
* @see java.util.List#clear()
*/
@Override
@SuppressWarnings("unchecked")
public void clear() {
if ( isClearQueueEnabled() ) {
queueOperation( new Clear() );
@ -280,166 +281,167 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
}
/**
* @see java.util.List#get(int)
*/
@Override
@SuppressWarnings("unchecked")
public Object get(int index) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
if ( index < 0 ) {
throw new ArrayIndexOutOfBoundsException( "negative index" );
}
Object result = readElementByIndex( index );
return result==UNKNOWN ? list.get(index) : result;
final Object result = readElementByIndex( index );
return result == UNKNOWN ? list.get( index ) : result;
}
/**
* @see java.util.List#set(int, Object)
*/
@Override
@SuppressWarnings("unchecked")
public Object set(int index, Object value) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
}
Object old = isPutQueueEnabled() ? readElementByIndex( index ) : UNKNOWN;
final Object old = isPutQueueEnabled() ? readElementByIndex( index ) : UNKNOWN;
if ( old==UNKNOWN ) {
write();
return list.set(index, value);
return list.set( index, value );
}
else {
queueOperation( new Set(index, value, old) );
queueOperation( new Set( index, value, old ) );
return old;
}
}
/**
* @see java.util.List#add(int, Object)
*/
@Override
@SuppressWarnings("unchecked")
public Object remove(int index) {
if ( index < 0 ) {
throw new ArrayIndexOutOfBoundsException( "negative index" );
}
final Object old = isPutQueueEnabled() ? readElementByIndex( index ) : UNKNOWN;
if ( old == UNKNOWN ) {
write();
return list.remove( index );
}
else {
queueOperation( new Remove( index, old ) );
return old;
}
}
@Override
@SuppressWarnings("unchecked")
public void add(int index, Object value) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
if ( index < 0 ) {
throw new ArrayIndexOutOfBoundsException( "negative index" );
}
if ( !isOperationQueueEnabled() ) {
write();
list.add(index, value);
list.add( index, value );
}
else {
queueOperation( new Add(index, value) );
queueOperation( new Add( index, value ) );
}
}
/**
* @see java.util.List#remove(int)
*/
public Object remove(int index) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
}
Object old = isPutQueueEnabled() ?
readElementByIndex( index ) : UNKNOWN;
if ( old==UNKNOWN ) {
write();
return list.remove(index);
}
else {
queueOperation( new Remove(index, old) );
return old;
}
}
/**
* @see java.util.List#indexOf(Object)
*/
@Override
@SuppressWarnings("unchecked")
public int indexOf(Object value) {
read();
return list.indexOf(value);
return list.indexOf( value );
}
/**
* @see java.util.List#lastIndexOf(Object)
*/
@Override
@SuppressWarnings("unchecked")
public int lastIndexOf(Object value) {
read();
return list.lastIndexOf(value);
return list.lastIndexOf( value );
}
/**
* @see java.util.List#listIterator()
*/
@Override
@SuppressWarnings("unchecked")
public ListIterator listIterator() {
read();
return new ListIteratorProxy( list.listIterator() );
}
/**
* @see java.util.List#listIterator(int)
*/
@Override
@SuppressWarnings("unchecked")
public ListIterator listIterator(int index) {
read();
return new ListIteratorProxy( list.listIterator(index) );
return new ListIteratorProxy( list.listIterator( index ) );
}
/**
* @see java.util.List#subList(int, int)
*/
@Override
@SuppressWarnings("unchecked")
public java.util.List subList(int from, int to) {
read();
return new ListProxy( list.subList(from, to) );
return new ListProxy( list.subList( from, to ) );
}
@Override
public boolean empty() {
return list.isEmpty();
}
@Override
public String toString() {
read();
return list.toString();
}
@Override
@SuppressWarnings("unchecked")
public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException {
Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
int index = (Integer) persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
final int index = (Integer) persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
//pad with nulls from the current last element up to the new index
for ( int i = list.size(); i<=index; i++) {
list.add(i, null);
list.add( i, null );
}
list.set(index, element);
list.set( index, element );
return element;
}
@Override
@SuppressWarnings("unchecked")
public Iterator entries(CollectionPersister persister) {
return list.iterator();
}
@Override
@SuppressWarnings("unchecked")
public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
throws HibernateException {
Serializable[] array = ( Serializable[] ) disassembled;
int size = array.length;
final Serializable[] array = (Serializable[]) disassembled;
final int size = array.length;
beforeInitialize( persister, size );
for ( int i = 0; i < size; i++ ) {
list.add( persister.getElementType().assemble( array[i], getSession(), owner ) );
for ( Serializable arrayElement : array ) {
list.add( persister.getElementType().assemble( arrayElement, getSession(), owner ) );
}
}
public Serializable disassemble(CollectionPersister persister)
throws HibernateException {
int length = list.size();
Serializable[] result = new Serializable[length];
@Override
@SuppressWarnings("unchecked")
public Serializable disassemble(CollectionPersister persister) throws HibernateException {
final int length = list.size();
final Serializable[] result = new Serializable[length];
for ( int i=0; i<length; i++ ) {
result[i] = persister.getElementType().disassemble( list.get(i), getSession(), null );
result[i] = persister.getElementType().disassemble( list.get( i ), getSession(), null );
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
List deletes = new ArrayList();
List sn = (List) getSnapshot();
final List deletes = new ArrayList();
final List sn = (List) getSnapshot();
int end;
if ( sn.size() > list.size() ) {
for ( int i=list.size(); i<sn.size(); i++ ) {
deletes.add( indexIsFormula ? sn.get(i) : i );
deletes.add( indexIsFormula ? sn.get( i ) : i );
}
end = list.size();
}
@ -447,60 +449,78 @@ public class PersistentList extends AbstractPersistentCollection implements List
end = sn.size();
}
for ( int i=0; i<end; i++ ) {
if ( list.get(i)==null && sn.get(i)!=null ) {
deletes.add( indexIsFormula ? sn.get(i) : i );
final Object item = list.get( i );
final Object snapshotItem = sn.get( i );
if ( item == null && snapshotItem != null ) {
deletes.add( indexIsFormula ? snapshotItem : i );
}
}
return deletes.iterator();
}
@Override
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
final List sn = (List) getSnapshot();
return list.get(i)!=null && ( i >= sn.size() || sn.get(i)==null );
return list.get( i ) != null && ( i >= sn.size() || sn.get( i ) == null );
}
@Override
public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException {
final List sn = (List) getSnapshot();
return i<sn.size() && sn.get(i)!=null && list.get(i)!=null &&
elemType.isDirty( list.get(i), sn.get(i), getSession() );
return i < sn.size()
&& sn.get( i ) != null
&& list.get( i ) != null
&& elemType.isDirty( list.get( i ), sn.get( i ), getSession() );
}
@Override
public Object getIndex(Object entry, int i, CollectionPersister persister) {
return i;
}
@Override
public Object getElement(Object entry) {
return entry;
}
@Override
public Object getSnapshotElement(Object entry, int i) {
final List sn = (List) getSnapshot();
return sn.get(i);
return sn.get( i );
}
@Override
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object other) {
read();
return list.equals(other);
return list.equals( other );
}
@Override
public int hashCode() {
read();
return list.hashCode();
}
@Override
public boolean entryExists(Object entry, int i) {
return entry!=null;
}
final class Clear implements DelayedOperation {
@Override
public void operate() {
list.clear();
}
@Override
public Object getAddedInstance() {
return null;
}
@Override
public Object getOrphan() {
throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
throw new UnsupportedOperationException( "queued clear cannot be used with orphan delete" );
}
}
@ -510,12 +530,19 @@ public class PersistentList extends AbstractPersistentCollection implements List
public SimpleAdd(Object value) {
this.value = value;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
list.add(value);
list.add( value );
}
@Override
public Object getAddedInstance() {
return value;
}
@Override
public Object getOrphan() {
return null;
}
@ -529,12 +556,19 @@ public class PersistentList extends AbstractPersistentCollection implements List
this.index = index;
this.value = value;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
list.add(index, value);
list.add( index, value );
}
@Override
public Object getAddedInstance() {
return value;
}
@Override
public Object getOrphan() {
return null;
}
@ -550,12 +584,19 @@ public class PersistentList extends AbstractPersistentCollection implements List
this.value = value;
this.old = old;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
list.set(index, value);
list.set( index, value );
}
@Override
public Object getAddedInstance() {
return value;
}
@Override
public Object getOrphan() {
return old;
}
@ -569,12 +610,19 @@ public class PersistentList extends AbstractPersistentCollection implements List
this.index = index;
this.old = old;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
list.remove(index);
list.remove( index );
}
@Override
public Object getAddedInstance() {
return null;
}
@Override
public Object getOrphan() {
return old;
}
@ -586,12 +634,19 @@ public class PersistentList extends AbstractPersistentCollection implements List
public SimpleRemove(Object value) {
this.value = value;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
list.remove(value);
list.remove( value );
}
@Override
public Object getAddedInstance() {
return null;
}
@Override
public Object getOrphan() {
return value;
}

View File

@ -68,7 +68,7 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
* @param session The session to which this map will belong.
*/
public PersistentMap(SessionImplementor session) {
super(session);
super( session );
}
/**
@ -79,106 +79,108 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
* @param map The underlying map data.
*/
public PersistentMap(SessionImplementor session, Map map) {
super(session);
super( session );
this.map = map;
setInitialized();
setDirectlyAccessible(true);
setDirectlyAccessible( true );
}
@Override
@SuppressWarnings( {"unchecked"})
public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
HashMap clonedMap = new HashMap( map.size() );
final HashMap clonedMap = new HashMap( map.size() );
for ( Object o : map.entrySet() ) {
Entry e = (Entry) o;
final Entry e = (Entry) o;
final Object copy = persister.getElementType().deepCopy( e.getValue(), persister.getFactory() );
clonedMap.put( e.getKey(), copy );
}
return clonedMap;
}
@Override
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
Map sn = (Map) snapshot;
final Map sn = (Map) snapshot;
return getOrphans( sn.values(), map.values(), entityName, getSession() );
}
@Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
Type elementType = persister.getElementType();
Map xmap = (Map) getSnapshot();
if ( xmap.size()!=this.map.size() ) return false;
Iterator iter = map.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry entry = (Map.Entry) iter.next();
if ( elementType.isDirty( entry.getValue(), xmap.get( entry.getKey() ), getSession() ) ) return false;
final Type elementType = persister.getElementType();
final Map snapshotMap = (Map) getSnapshot();
if ( snapshotMap.size() != this.map.size() ) {
return false;
}
for ( Object o : map.entrySet() ) {
final Entry entry = (Entry) o;
if ( elementType.isDirty( entry.getValue(), snapshotMap.get( entry.getKey() ), getSession() ) ) {
return false;
}
}
return true;
}
@Override
public boolean isSnapshotEmpty(Serializable snapshot) {
return ( (Map) snapshot ).isEmpty();
}
@Override
public boolean isWrapper(Object collection) {
return map==collection;
}
@Override
public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
this.map = ( Map ) persister.getCollectionType().instantiate( anticipatedSize );
this.map = (Map) persister.getCollectionType().instantiate( anticipatedSize );
}
/**
* @see java.util.Map#size()
*/
@Override
public int size() {
return readSize() ? getCachedSize() : map.size();
}
/**
* @see java.util.Map#isEmpty()
*/
@Override
public boolean isEmpty() {
return readSize() ? getCachedSize()==0 : map.isEmpty();
}
/**
* @see java.util.Map#containsKey(Object)
*/
@Override
@SuppressWarnings("UnnecessaryUnboxing")
public boolean containsKey(Object key) {
Boolean exists = readIndexExistence(key);
return exists==null ? map.containsKey(key) : exists.booleanValue();
final Boolean exists = readIndexExistence( key );
return exists == null ? map.containsKey( key ) : exists.booleanValue();
}
/**
* @see java.util.Map#containsValue(Object)
*/
@Override
@SuppressWarnings("UnnecessaryUnboxing")
public boolean containsValue(Object value) {
Boolean exists = readElementExistence(value);
return exists==null ?
map.containsValue(value) :
exists.booleanValue();
final Boolean exists = readElementExistence( value );
return exists == null
? map.containsValue( value )
: exists.booleanValue();
}
/**
* @see java.util.Map#get(Object)
*/
@Override
public Object get(Object key) {
Object result = readElementByIndex(key);
return result==UNKNOWN ? map.get(key) : result;
final Object result = readElementByIndex( key );
return result == UNKNOWN
? map.get( key )
: result;
}
/**
* @see java.util.Map#put(Object, Object)
*/
@Override
@SuppressWarnings("unchecked")
public Object put(Object key, Object value) {
if ( isPutQueueEnabled() ) {
Object old = readElementByIndex( key );
final Object old = readElementByIndex( key );
if ( old != UNKNOWN ) {
queueOperation( new Put( key, value, old ) );
return old;
}
}
initialize( true );
Object old = map.put( key, value );
final Object old = map.put( key, value );
// would be better to use the element-type to determine
// whether the old and the new are equal here; the problem being
// we do not necessarily have access to the element type in all
@ -189,12 +191,11 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
return old;
}
/**
* @see java.util.Map#remove(Object)
*/
@Override
@SuppressWarnings("unchecked")
public Object remove(Object key) {
if ( isPutQueueEnabled() ) {
Object old = readElementByIndex( key );
final Object old = readElementByIndex( key );
if ( old != UNKNOWN ) {
queueOperation( new Remove( key, old ) );
return old;
@ -208,23 +209,20 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
return map.remove( key );
}
/**
* @see java.util.Map#putAll(java.util.Map puts)
*/
@Override
@SuppressWarnings("unchecked")
public void putAll(Map puts) {
if ( puts.size()>0 ) {
if ( puts.size() > 0 ) {
initialize( true );
Iterator itr = puts.entrySet().iterator();
while ( itr.hasNext() ) {
Map.Entry entry = ( Entry ) itr.next();
for ( Object o : puts.entrySet() ) {
final Entry entry = (Entry) o;
put( entry.getKey(), entry.getValue() );
}
}
}
/**
* @see java.util.Map#clear()
*/
@Override
@SuppressWarnings("unchecked")
public void clear() {
if ( isClearQueueEnabled() ) {
queueOperation( new Clear() );
@ -238,34 +236,35 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
}
}
/**
* @see java.util.Map#keySet()
*/
@Override
@SuppressWarnings("unchecked")
public Set keySet() {
read();
return new SetProxy( map.keySet() );
}
/**
* @see java.util.Map#values()
*/
@Override
@SuppressWarnings("unchecked")
public Collection values() {
read();
return new SetProxy( map.values() );
}
/**
* @see java.util.Map#entrySet()
*/
@Override
@SuppressWarnings("unchecked")
public Set entrySet() {
read();
return new EntrySetProxy( map.entrySet() );
}
@Override
@SuppressWarnings("unchecked")
public boolean empty() {
return map.isEmpty();
}
@Override
@SuppressWarnings("unchecked")
public String toString() {
read();
return map.toString();
@ -273,6 +272,8 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
private transient List<Object[]> loadingEntries;
@Override
@SuppressWarnings("unchecked")
public Object readFrom(
ResultSet rs,
CollectionPersister persister,
@ -301,75 +302,129 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
return super.endRead();
}
@Override
@SuppressWarnings("unchecked")
public Iterator entries(CollectionPersister persister) {
return map.entrySet().iterator();
}
/** a wrapper for Map.Entry sets */
/**
* a wrapper for Map.Entry sets
*/
class EntrySetProxy implements Set {
private final Set set;
EntrySetProxy(Set set) {
this.set=set;
}
@Override
@SuppressWarnings("unchecked")
public boolean add(Object entry) {
//write(); -- doesn't
return set.add(entry);
return set.add( entry );
}
@Override
@SuppressWarnings("unchecked")
public boolean addAll(Collection entries) {
//write(); -- doesn't
return set.addAll(entries);
return set.addAll( entries );
}
@Override
@SuppressWarnings("unchecked")
public void clear() {
write();
set.clear();
}
@Override
@SuppressWarnings("unchecked")
public boolean contains(Object entry) {
return set.contains(entry);
return set.contains( entry );
}
@Override
@SuppressWarnings("unchecked")
public boolean containsAll(Collection entries) {
return set.containsAll(entries);
return set.containsAll( entries );
}
@Override
@SuppressWarnings("unchecked")
public boolean isEmpty() {
return set.isEmpty();
}
@Override
@SuppressWarnings("unchecked")
public Iterator iterator() {
return new EntryIteratorProxy( set.iterator() );
}
@Override
@SuppressWarnings("unchecked")
public boolean remove(Object entry) {
write();
return set.remove(entry);
return set.remove( entry );
}
@Override
@SuppressWarnings("unchecked")
public boolean removeAll(Collection entries) {
write();
return set.removeAll(entries);
return set.removeAll( entries );
}
@Override
@SuppressWarnings("unchecked")
public boolean retainAll(Collection entries) {
write();
return set.retainAll(entries);
return set.retainAll( entries );
}
@Override
@SuppressWarnings("unchecked")
public int size() {
return set.size();
}
// amazingly, these two will work because AbstractCollection
// uses iterator() to fill the array
@Override
@SuppressWarnings("unchecked")
public Object[] toArray() {
return set.toArray();
}
@Override
@SuppressWarnings("unchecked")
public Object[] toArray(Object[] array) {
return set.toArray(array);
return set.toArray( array );
}
}
final class EntryIteratorProxy implements Iterator {
private final Iterator iter;
EntryIteratorProxy(Iterator iter) {
this.iter=iter;
}
@Override
@SuppressWarnings("unchecked")
public boolean hasNext() {
return iter.hasNext();
}
@Override
@SuppressWarnings("unchecked")
public Object next() {
return new MapEntryProxy( (Map.Entry) iter.next() );
}
@Override
@SuppressWarnings("unchecked")
public void remove() {
write();
iter.remove();
@ -381,21 +436,46 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
MapEntryProxy( Map.Entry me ) {
this.me = me;
}
public Object getKey() { return me.getKey(); }
public Object getValue() { return me.getValue(); }
public boolean equals(Object o) { return me.equals(o); }
public int hashCode() { return me.hashCode(); }
@Override
@SuppressWarnings("unchecked")
public Object getKey() {
return me.getKey();
}
@Override
@SuppressWarnings("unchecked")
public Object getValue() {
return me.getValue();
}
@Override
@SuppressWarnings({"unchecked", "EqualsWhichDoesntCheckParameterClass"})
public boolean equals(Object o) {
return me.equals( o );
}
@Override
@SuppressWarnings("unchecked")
public int hashCode() {
return me.hashCode();
}
// finally, what it's all about...
@Override
@SuppressWarnings("unchecked")
public Object setValue(Object value) {
write();
return me.setValue(value);
return me.setValue( value );
}
}
@Override
@SuppressWarnings("unchecked")
public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
throws HibernateException {
Serializable[] array = ( Serializable[] ) disassembled;
int size = array.length;
final Serializable[] array = (Serializable[]) disassembled;
final int size = array.length;
beforeInitialize( persister, size );
for ( int i = 0; i < size; i+=2 ) {
map.put(
@ -405,13 +485,14 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
}
}
@Override
@SuppressWarnings("unchecked")
public Serializable disassemble(CollectionPersister persister) throws HibernateException {
Serializable[] result = new Serializable[ map.size() * 2 ];
Iterator iter = map.entrySet().iterator();
final Serializable[] result = new Serializable[ map.size() * 2 ];
final Iterator itr = map.entrySet().iterator();
int i=0;
while ( iter.hasNext() ) {
Map.Entry e = (Map.Entry) iter.next();
while ( itr.hasNext() ) {
final Map.Entry e = (Map.Entry) itr.next();
result[i++] = persister.getIndexType().disassemble( e.getKey(), getSession(), null );
result[i++] = persister.getElementType().disassemble( e.getValue(), getSession(), null );
}
@ -419,74 +500,92 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
}
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula)
throws HibernateException {
List deletes = new ArrayList();
Iterator iter = ( (Map) getSnapshot() ).entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry e = (Map.Entry) iter.next();
Object key = e.getKey();
if ( e.getValue()!=null && map.get(key)==null ) {
@Override
@SuppressWarnings("unchecked")
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
final List deletes = new ArrayList();
for ( Object o : ((Map) getSnapshot()).entrySet() ) {
final Entry e = (Entry) o;
final Object key = e.getKey();
if ( e.getValue() != null && map.get( key ) == null ) {
deletes.add( indexIsFormula ? e.getValue() : key );
}
}
return deletes.iterator();
}
public boolean needsInserting(Object entry, int i, Type elemType)
throws HibernateException {
@Override
@SuppressWarnings("unchecked")
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
final Map sn = (Map) getSnapshot();
Map.Entry e = (Map.Entry) entry;
return e.getValue()!=null && sn.get( e.getKey() )==null;
final Map.Entry e = (Map.Entry) entry;
return e.getValue() != null && sn.get( e.getKey() ) == null;
}
public boolean needsUpdating(Object entry, int i, Type elemType)
throws HibernateException {
@Override
@SuppressWarnings("unchecked")
public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException {
final Map sn = (Map) getSnapshot();
Map.Entry e = (Map.Entry) entry;
Object snValue = sn.get( e.getKey() );
return e.getValue()!=null &&
snValue!=null &&
elemType.isDirty( snValue, e.getValue(), getSession() );
final Map.Entry e = (Map.Entry) entry;
final Object snValue = sn.get( e.getKey() );
return e.getValue() != null
&& snValue != null
&& elemType.isDirty( snValue, e.getValue(), getSession() );
}
@Override
@SuppressWarnings("unchecked")
public Object getIndex(Object entry, int i, CollectionPersister persister) {
return ( (Map.Entry) entry ).getKey();
}
@Override
@SuppressWarnings("unchecked")
public Object getElement(Object entry) {
return ( (Map.Entry) entry ).getValue();
}
@Override
@SuppressWarnings("unchecked")
public Object getSnapshotElement(Object entry, int i) {
final Map sn = (Map) getSnapshot();
return sn.get( ( (Map.Entry) entry ).getKey() );
}
@Override
@SuppressWarnings({"unchecked", "EqualsWhichDoesntCheckParameterClass"})
public boolean equals(Object other) {
read();
return map.equals(other);
return map.equals( other );
}
@Override
@SuppressWarnings("unchecked")
public int hashCode() {
read();
return map.hashCode();
}
@Override
@SuppressWarnings("unchecked")
public boolean entryExists(Object entry, int i) {
return ( (Map.Entry) entry ).getValue()!=null;
return ( (Map.Entry) entry ).getValue() != null;
}
final class Clear implements DelayedOperation {
@Override
public void operate() {
map.clear();
}
@Override
public Object getAddedInstance() {
return null;
}
@Override
public Object getOrphan() {
throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
throw new UnsupportedOperationException( "queued clear cannot be used with orphan delete" );
}
}
@ -500,12 +599,21 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
this.value = value;
this.old = old;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
map.put(index, value);
map.put( index, value );
}
@Override
@SuppressWarnings("unchecked")
public Object getAddedInstance() {
return value;
}
@Override
@SuppressWarnings("unchecked")
public Object getOrphan() {
return old;
}
@ -519,12 +627,19 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
this.index = index;
this.old = old;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
map.remove(index);
map.remove( index );
}
@Override
public Object getAddedInstance() {
return null;
}
@Override
public Object getOrphan() {
return old;
}

View File

@ -48,7 +48,6 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public class PersistentSet extends AbstractPersistentCollection implements java.util.Set {
protected Set set;
protected transient List tempList;
@ -80,128 +79,127 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
* @param set The underlying set data.
*/
public PersistentSet(SessionImplementor session, java.util.Set set) {
super(session);
super( session );
// Sets can be just a view of a part of another collection.
// do we need to copy it to be sure it won't be changing
// underneath us?
// ie. this.set.addAll(set);
this.set = set;
setInitialized();
setDirectlyAccessible(true);
setDirectlyAccessible( true );
}
@Override
@SuppressWarnings( {"unchecked"})
public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
HashMap clonedSet = new HashMap( set.size() );
final HashMap clonedSet = new HashMap( set.size() );
for ( Object aSet : set ) {
Object copied = persister.getElementType()
.deepCopy( aSet, persister.getFactory() );
final Object copied = persister.getElementType().deepCopy( aSet, persister.getFactory() );
clonedSet.put( copied, copied );
}
return clonedSet;
}
@Override
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
java.util.Map sn = (java.util.Map) snapshot;
final java.util.Map sn = (java.util.Map) snapshot;
return getOrphans( sn.keySet(), set, entityName, getSession() );
}
@Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
Type elementType = persister.getElementType();
java.util.Map sn = (java.util.Map) getSnapshot();
final Type elementType = persister.getElementType();
final java.util.Map sn = (java.util.Map) getSnapshot();
if ( sn.size()!=set.size() ) {
return false;
}
else {
Iterator iter = set.iterator();
while ( iter.hasNext() ) {
Object test = iter.next();
Object oldValue = sn.get(test);
if ( oldValue==null || elementType.isDirty( oldValue, test, getSession() ) ) return false;
for ( Object test : set ) {
final Object oldValue = sn.get( test );
if ( oldValue == null || elementType.isDirty( oldValue, test, getSession() ) ) {
return false;
}
}
return true;
}
}
@Override
public boolean isSnapshotEmpty(Serializable snapshot) {
return ( (java.util.Map) snapshot ).isEmpty();
}
@Override
public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
this.set = ( Set ) persister.getCollectionType().instantiate( anticipatedSize );
this.set = (Set) persister.getCollectionType().instantiate( anticipatedSize );
}
@Override
@SuppressWarnings("unchecked")
public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
throws HibernateException {
Serializable[] array = ( Serializable[] ) disassembled;
int size = array.length;
final Serializable[] array = (Serializable[]) disassembled;
final int size = array.length;
beforeInitialize( persister, size );
for (int i = 0; i < size; i++ ) {
Object element = persister.getElementType().assemble( array[i], getSession(), owner );
if ( element != null ) {
set.add( element );
for ( Serializable arrayElement : array ) {
final Object assembledArrayElement = persister.getElementType().assemble( arrayElement, getSession(), owner );
if ( assembledArrayElement != null ) {
set.add( assembledArrayElement );
}
}
}
@Override
public boolean empty() {
return set.isEmpty();
}
/**
* @see java.util.Set#size()
*/
@Override
@SuppressWarnings("unchecked")
public int size() {
return readSize() ? getCachedSize() : set.size();
}
/**
* @see java.util.Set#isEmpty()
*/
@Override
@SuppressWarnings("unchecked")
public boolean isEmpty() {
return readSize() ? getCachedSize()==0 : set.isEmpty();
}
/**
* @see java.util.Set#contains(Object)
*/
@Override
@SuppressWarnings({"unchecked", "UnnecessaryUnboxing"})
public boolean contains(Object object) {
Boolean exists = readElementExistence(object);
return exists==null ?
set.contains(object) :
exists.booleanValue();
final Boolean exists = readElementExistence( object );
return exists == null
? set.contains( object )
: exists.booleanValue();
}
/**
* @see java.util.Set#iterator()
*/
@Override
@SuppressWarnings("unchecked")
public Iterator iterator() {
read();
return new IteratorProxy( set.iterator() );
}
/**
* @see java.util.Set#toArray()
*/
@Override
@SuppressWarnings("unchecked")
public Object[] toArray() {
read();
return set.toArray();
}
/**
* @see java.util.Set#toArray(Object[])
*/
@Override
@SuppressWarnings("unchecked")
public Object[] toArray(Object[] array) {
read();
return set.toArray(array);
return set.toArray( array );
}
/**
* @see java.util.Set#add(Object)
*/
@Override
@SuppressWarnings({"unchecked", "UnnecessaryUnboxing"})
public boolean add(Object value) {
Boolean exists = isOperationQueueEnabled() ? readElementExistence( value ) : null;
final Boolean exists = isOperationQueueEnabled() ? readElementExistence( value ) : null;
if ( exists == null ) {
initialize( true );
if ( set.add( value ) ) {
@ -216,17 +214,16 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
return false;
}
else {
queueOperation( new SimpleAdd(value) );
queueOperation( new SimpleAdd( value ) );
return true;
}
}
/**
* @see java.util.Set#remove(Object)
*/
@Override
@SuppressWarnings({"unchecked", "UnnecessaryUnboxing"})
public boolean remove(Object value) {
Boolean exists = isPutQueueEnabled() ? readElementExistence( value ) : null;
if ( exists==null ) {
final Boolean exists = isPutQueueEnabled() ? readElementExistence( value ) : null;
if ( exists == null ) {
initialize( true );
if ( set.remove( value ) ) {
dirty();
@ -237,7 +234,7 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
}
}
else if ( exists.booleanValue() ) {
queueOperation( new SimpleRemove(value) );
queueOperation( new SimpleRemove( value ) );
return true;
}
else {
@ -245,17 +242,15 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
}
}
/**
* @see java.util.Set#containsAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean containsAll(Collection coll) {
read();
return set.containsAll(coll);
return set.containsAll( coll );
}
/**
* @see java.util.Set#addAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean addAll(Collection coll) {
if ( coll.size() > 0 ) {
initialize( true );
@ -272,9 +267,8 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
}
}
/**
* @see java.util.Set#retainAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean retainAll(Collection coll) {
initialize( true );
if ( set.retainAll( coll ) ) {
@ -286,9 +280,8 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
}
}
/**
* @see java.util.Set#removeAll(Collection)
*/
@Override
@SuppressWarnings("unchecked")
public boolean removeAll(Collection coll) {
if ( coll.size() > 0 ) {
initialize( true );
@ -305,9 +298,8 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
}
}
/**
* @see java.util.Set#clear()
*/
@Override
@SuppressWarnings("unchecked")
public void clear() {
if ( isClearQueueEnabled() ) {
queueOperation( new Clear() );
@ -321,129 +313,168 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
}
}
@Override
@SuppressWarnings("unchecked")
public String toString() {
//if (needLoading) return "asleep";
read();
return set.toString();
}
@Override
@SuppressWarnings("unchecked")
public Object readFrom(
ResultSet rs,
CollectionPersister persister,
CollectionAliases descriptor,
Object owner) throws HibernateException, SQLException {
Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
if (element!=null) tempList.add(element);
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
if ( element != null ) {
tempList.add( element );
}
return element;
}
@Override
@SuppressWarnings("unchecked")
public void beginRead() {
super.beginRead();
tempList = new ArrayList();
}
@Override
@SuppressWarnings("unchecked")
public boolean endRead() {
set.addAll(tempList);
set.addAll( tempList );
tempList = null;
setInitialized();
return true;
}
@Override
@SuppressWarnings("unchecked")
public Iterator entries(CollectionPersister persister) {
return set.iterator();
}
public Serializable disassemble(CollectionPersister persister)
throws HibernateException {
Serializable[] result = new Serializable[ set.size() ];
Iterator iter = set.iterator();
@Override
@SuppressWarnings("unchecked")
public Serializable disassemble(CollectionPersister persister) throws HibernateException {
final Serializable[] result = new Serializable[ set.size() ];
final Iterator itr = set.iterator();
int i=0;
while ( iter.hasNext() ) {
result[i++] = persister.getElementType().disassemble( iter.next(), getSession(), null );
while ( itr.hasNext() ) {
result[i++] = persister.getElementType().disassemble( itr.next(), getSession(), null );
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
Type elementType = persister.getElementType();
final Type elementType = persister.getElementType();
final java.util.Map sn = (java.util.Map) getSnapshot();
ArrayList deletes = new ArrayList( sn.size() );
Iterator iter = sn.keySet().iterator();
while ( iter.hasNext() ) {
Object test = iter.next();
if ( !set.contains(test) ) {
final ArrayList deletes = new ArrayList( sn.size() );
Iterator itr = sn.keySet().iterator();
while ( itr.hasNext() ) {
final Object test = itr.next();
if ( !set.contains( test ) ) {
// the element has been removed from the set
deletes.add(test);
deletes.add( test );
}
}
iter = set.iterator();
while ( iter.hasNext() ) {
Object test = iter.next();
Object oldValue = sn.get(test);
itr = set.iterator();
while ( itr.hasNext() ) {
final Object test = itr.next();
final Object oldValue = sn.get( test );
if ( oldValue!=null && elementType.isDirty( test, oldValue, getSession() ) ) {
// the element has changed
deletes.add(oldValue);
deletes.add( oldValue );
}
}
return deletes.iterator();
}
@Override
@SuppressWarnings("unchecked")
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
final java.util.Map sn = (java.util.Map) getSnapshot();
Object oldValue = sn.get(entry);
final Object oldValue = ( (java.util.Map) getSnapshot() ).get( entry );
// note that it might be better to iterate the snapshot but this is safe,
// assuming the user implements equals() properly, as required by the Set
// contract!
return oldValue==null || elemType.isDirty( oldValue, entry, getSession() );
return oldValue == null || elemType.isDirty( oldValue, entry, getSession() );
}
@Override
@SuppressWarnings("unchecked")
public boolean needsUpdating(Object entry, int i, Type elemType) {
return false;
}
@Override
@SuppressWarnings("unchecked")
public boolean isRowUpdatePossible() {
return false;
}
@Override
@SuppressWarnings("unchecked")
public Object getIndex(Object entry, int i, CollectionPersister persister) {
throw new UnsupportedOperationException("Sets don't have indexes");
}
@Override
@SuppressWarnings("unchecked")
public Object getElement(Object entry) {
return entry;
}
@Override
@SuppressWarnings("unchecked")
public Object getSnapshotElement(Object entry, int i) {
throw new UnsupportedOperationException("Sets don't support updating by element");
}
@Override
@SuppressWarnings({"unchecked", "EqualsWhichDoesntCheckParameterClass"})
public boolean equals(Object other) {
read();
return set.equals(other);
return set.equals( other );
}
@Override
@SuppressWarnings("unchecked")
public int hashCode() {
read();
return set.hashCode();
}
@Override
@SuppressWarnings("unchecked")
public boolean entryExists(Object key, int i) {
return true;
}
@Override
@SuppressWarnings("unchecked")
public boolean isWrapper(Object collection) {
return set==collection;
}
final class Clear implements DelayedOperation {
@Override
public void operate() {
set.clear();
}
@Override
public Object getAddedInstance() {
return null;
}
@Override
public Object getOrphan() {
throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
}
@ -455,12 +486,19 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
public SimpleAdd(Object value) {
this.value = value;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
set.add(value);
set.add( value );
}
@Override
public Object getAddedInstance() {
return value;
}
@Override
public Object getOrphan() {
return null;
}
@ -472,12 +510,19 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
public SimpleRemove(Object value) {
this.value = value;
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
set.remove(value);
set.remove( value );
}
@Override
public Object getAddedInstance() {
return null;
}
@Override
public Object getOrphan() {
return value;
}

View File

@ -26,7 +26,6 @@ package org.hibernate.collection.internal;
import java.io.Serializable;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
@ -45,167 +44,212 @@ import org.hibernate.persister.collection.BasicCollectionPersister;
* @author <a href="mailto:doug.currie@alum.mit.edu">e</a>
*/
public class PersistentSortedMap extends PersistentMap implements SortedMap {
protected Comparator comparator;
/**
* Constructs a PersistentSortedMap. This form needed for SOAP libraries, etc
*/
@SuppressWarnings("UnusedDeclaration")
public PersistentSortedMap() {
}
/**
* Constructs a PersistentSortedMap.
*
* @param session The session
*/
public PersistentSortedMap(SessionImplementor session) {
super( session );
}
/**
* Constructs a PersistentSortedMap.
*
* @param session The session
* @param map The underlying map data
*/
public PersistentSortedMap(SessionImplementor session, SortedMap map) {
super( session, map );
comparator = map.comparator();
}
@SuppressWarnings({"unchecked", "UnusedParameters"})
protected Serializable snapshot(BasicCollectionPersister persister, EntityMode entityMode) throws HibernateException {
TreeMap clonedMap = new TreeMap(comparator);
Iterator iter = map.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry e = (Map.Entry) iter.next();
final TreeMap clonedMap = new TreeMap( comparator );
for ( Object o : map.entrySet() ) {
final Entry e = (Entry) o;
clonedMap.put( e.getKey(), persister.getElementType().deepCopy( e.getValue(), persister.getFactory() ) );
}
return clonedMap;
}
public PersistentSortedMap(SessionImplementor session) {
super(session);
}
public void setComparator(Comparator comparator) {
this.comparator = comparator;
}
public PersistentSortedMap(SessionImplementor session, SortedMap map) {
super(session, map);
comparator = map.comparator();
}
public PersistentSortedMap() {} //needed for SOAP libraries, etc
/**
* @see PersistentSortedMap#comparator()
*/
@Override
public Comparator comparator() {
return comparator;
}
/**
* @see PersistentSortedMap#subMap(Object, Object)
*/
@Override
@SuppressWarnings("unchecked")
public SortedMap subMap(Object fromKey, Object toKey) {
read();
SortedMap m = ( (SortedMap) map ).subMap(fromKey, toKey);
return new SortedSubMap(m);
final SortedMap subMap = ( (SortedMap) map ).subMap( fromKey, toKey );
return new SortedSubMap( subMap );
}
/**
* @see PersistentSortedMap#headMap(Object)
*/
@Override
@SuppressWarnings("unchecked")
public SortedMap headMap(Object toKey) {
read();
SortedMap m;
m = ( (SortedMap) map ).headMap(toKey);
return new SortedSubMap(m);
final SortedMap headMap = ( (SortedMap) map ).headMap( toKey );
return new SortedSubMap( headMap );
}
/**
* @see PersistentSortedMap#tailMap(Object)
*/
@Override
@SuppressWarnings("unchecked")
public SortedMap tailMap(Object fromKey) {
read();
SortedMap m;
m = ( (SortedMap) map ).tailMap(fromKey);
return new SortedSubMap(m);
final SortedMap tailMap = ( (SortedMap) map ).tailMap( fromKey );
return new SortedSubMap( tailMap );
}
/**
* @see PersistentSortedMap#firstKey()
*/
@Override
@SuppressWarnings("unchecked")
public Object firstKey() {
read();
return ( (SortedMap) map ).firstKey();
}
/**
* @see PersistentSortedMap#lastKey()
*/
@Override
@SuppressWarnings("unchecked")
public Object lastKey() {
read();
return ( (SortedMap) map ).lastKey();
}
class SortedSubMap implements SortedMap {
SortedMap subMap;
SortedMap submap;
SortedSubMap(SortedMap m) {
this.submap = m;
SortedSubMap(SortedMap subMap) {
this.subMap = subMap;
}
// from Map
@Override
@SuppressWarnings("unchecked")
public int size() {
return submap.size();
return subMap.size();
}
@Override
@SuppressWarnings("unchecked")
public boolean isEmpty() {
return submap.isEmpty();
return subMap.isEmpty();
}
@Override
@SuppressWarnings("unchecked")
public boolean containsKey(Object key) {
return submap.containsKey(key);
return subMap.containsKey( key );
}
@Override
@SuppressWarnings("unchecked")
public boolean containsValue(Object key) {
return submap.containsValue(key) ;
return subMap.containsValue( key ) ;
}
@Override
@SuppressWarnings("unchecked")
public Object get(Object key) {
return submap.get(key);
return subMap.get( key );
}
@Override
@SuppressWarnings("unchecked")
public Object put(Object key, Object value) {
write();
return submap.put(key, value);
return subMap.put( key, value );
}
@Override
@SuppressWarnings("unchecked")
public Object remove(Object key) {
write();
return submap.remove(key);
return subMap.remove( key );
}
@Override
@SuppressWarnings("unchecked")
public void putAll(Map other) {
write();
submap.putAll(other);
subMap.putAll( other );
}
@Override
@SuppressWarnings("unchecked")
public void clear() {
write();
submap.clear();
subMap.clear();
}
@Override
@SuppressWarnings("unchecked")
public Set keySet() {
return new SetProxy( submap.keySet() );
return new SetProxy( subMap.keySet() );
}
@Override
@SuppressWarnings("unchecked")
public Collection values() {
return new SetProxy( submap.values() );
return new SetProxy( subMap.values() );
}
@Override
@SuppressWarnings("unchecked")
public Set entrySet() {
return new EntrySetProxy( submap.entrySet() );
return new EntrySetProxy( subMap.entrySet() );
}
// from SortedMap
@Override
@SuppressWarnings("unchecked")
public Comparator comparator() {
return submap.comparator();
return subMap.comparator();
}
@Override
@SuppressWarnings("unchecked")
public SortedMap subMap(Object fromKey, Object toKey) {
SortedMap m;
m = submap.subMap(fromKey, toKey);
return new SortedSubMap( m );
final SortedMap subMap = this.subMap.subMap( fromKey, toKey );
return new SortedSubMap( subMap );
}
@Override
@SuppressWarnings("unchecked")
public SortedMap headMap(Object toKey) {
SortedMap m;
m = submap.headMap(toKey);
return new SortedSubMap(m);
final SortedMap headMap = subMap.headMap( toKey );
return new SortedSubMap( headMap );
}
@Override
@SuppressWarnings("unchecked")
public SortedMap tailMap(Object fromKey) {
SortedMap m;
m = submap.tailMap(fromKey);
return new SortedSubMap(m);
final SortedMap tailMap = subMap.tailMap( fromKey );
return new SortedSubMap( tailMap );
}
@Override
@SuppressWarnings("unchecked")
public Object firstKey() {
return submap.firstKey();
return subMap.firstKey();
}
@Override
@SuppressWarnings("unchecked")
public Object lastKey() {
return submap.lastKey();
return subMap.lastKey();
}
}
}

View File

@ -25,7 +25,6 @@ package org.hibernate.collection.internal;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeMap;
@ -42,17 +41,42 @@ import org.hibernate.persister.collection.BasicCollectionPersister;
* @author <a href="mailto:doug.currie@alum.mit.edu">e</a>
*/
public class PersistentSortedSet extends PersistentSet implements SortedSet {
protected Comparator comparator;
/**
* Constructs a PersistentSortedSet. This form needed for SOAP libraries, etc
*/
@SuppressWarnings("UnusedDeclaration")
public PersistentSortedSet() {
}
/**
* Constructs a PersistentSortedSet
*
* @param session The session
*/
public PersistentSortedSet(SessionImplementor session) {
super( session );
}
/**
* Constructs a PersistentSortedSet
*
* @param session The session
* @param set The underlying set data
*/
public PersistentSortedSet(SessionImplementor session, SortedSet set) {
super( session, set );
comparator = set.comparator();
}
@SuppressWarnings({"unchecked", "UnusedParameters"})
protected Serializable snapshot(BasicCollectionPersister persister, EntityMode entityMode)
throws HibernateException {
//if (set==null) return new Set(session);
TreeMap clonedSet = new TreeMap(comparator);
Iterator iter = set.iterator();
while ( iter.hasNext() ) {
Object copy = persister.getElementType().deepCopy( iter.next(), persister.getFactory() );
clonedSet.put(copy, copy);
final TreeMap clonedSet = new TreeMap( comparator );
for ( Object setElement : set ) {
final Object copy = persister.getElementType().deepCopy( setElement, persister.getFactory() );
clonedSet.put( copy, copy );
}
return clonedSet;
}
@ -61,106 +85,91 @@ public class PersistentSortedSet extends PersistentSet implements SortedSet {
this.comparator = comparator;
}
public PersistentSortedSet(SessionImplementor session) {
super(session);
}
public PersistentSortedSet(SessionImplementor session, SortedSet set) {
super(session, set);
comparator = set.comparator();
}
public PersistentSortedSet() {} //needed for SOAP libraries, etc
/**
* @see PersistentSortedSet#comparator()
*/
@Override
public Comparator comparator() {
return comparator;
}
/**
* @see PersistentSortedSet#subSet(Object,Object)
*/
@Override
@SuppressWarnings("unchecked")
public SortedSet subSet(Object fromElement, Object toElement) {
read();
SortedSet s;
s = ( (SortedSet) set ).subSet(fromElement, toElement);
return new SubSetProxy(s);
final SortedSet subSet = ( (SortedSet) set ).subSet( fromElement, toElement );
return new SubSetProxy( subSet );
}
/**
* @see PersistentSortedSet#headSet(Object)
*/
@Override
@SuppressWarnings("unchecked")
public SortedSet headSet(Object toElement) {
read();
SortedSet s = ( (SortedSet) set ).headSet(toElement);
return new SubSetProxy(s);
final SortedSet headSet = ( (SortedSet) set ).headSet( toElement );
return new SubSetProxy( headSet );
}
/**
* @see PersistentSortedSet#tailSet(Object)
*/
@Override
@SuppressWarnings("unchecked")
public SortedSet tailSet(Object fromElement) {
read();
SortedSet s = ( (SortedSet) set ).tailSet(fromElement);
return new SubSetProxy(s);
final SortedSet tailSet = ( (SortedSet) set ).tailSet( fromElement );
return new SubSetProxy( tailSet );
}
/**
* @see PersistentSortedSet#first()
*/
@Override
@SuppressWarnings("unchecked")
public Object first() {
read();
return ( (SortedSet) set ).first();
}
/**
* @see PersistentSortedSet#last()
*/
@Override
@SuppressWarnings("unchecked")
public Object last() {
read();
return ( (SortedSet) set ).last();
}
/** wrapper for subSets to propagate write to its backing set */
/**
* wrapper for subSets to propagate write to its backing set
*/
class SubSetProxy extends SetProxy implements SortedSet {
SubSetProxy(SortedSet s) {
super(s);
super( s );
}
@Override
@SuppressWarnings("unchecked")
public Comparator comparator() {
return ( (SortedSet) this.set ).comparator();
}
@Override
@SuppressWarnings("unchecked")
public Object first() {
return ( (SortedSet) this.set ).first();
}
@Override
@SuppressWarnings("unchecked")
public SortedSet headSet(Object toValue) {
return new SubSetProxy( ( (SortedSet) this.set ).headSet(toValue) );
return new SubSetProxy( ( (SortedSet) this.set ).headSet( toValue ) );
}
@Override
@SuppressWarnings("unchecked")
public Object last() {
return ( (SortedSet) this.set ).last();
}
@Override
@SuppressWarnings("unchecked")
public SortedSet subSet(Object fromValue, Object toValue) {
return new SubSetProxy( ( (SortedSet) this.set ).subSet(fromValue, toValue) );
return new SubSetProxy( ( (SortedSet) this.set ).subSet( fromValue, toValue ) );
}
@Override
@SuppressWarnings("unchecked")
public SortedSet tailSet(Object fromValue) {
return new SubSetProxy( ( (SortedSet) this.set ).tailSet(fromValue) );
return new SubSetProxy( ( (SortedSet) this.set ).tailSet( fromValue ) );
}
}
}

View File

@ -0,0 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
/**
* Internal implementations and support for persistent collections
*/
package org.hibernate.collection.internal;

View File

@ -63,25 +63,35 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public interface PersistentCollection {
/**
* Get the owning entity. Note that the owner is only
* set during the flush cycle, and when a new collection
* wrapper is created while loading an entity.
*
* @return The owner
*/
public Object getOwner();
/**
* Set the reference to the owning entity
*
* @param entity The owner
*/
public void setOwner(Object entity);
/**
* Is the collection empty? (don't try to initialize the collection)
*
* @return {@code false} if the collection is non-empty; {@code true} otherwise.
*/
public boolean empty();
/**
* After flushing, re-init snapshot state.
*
* @param key The collection instance key (fk value).
* @param role The collection role
* @param snapshot The snapshot state
*/
public void setSnapshot(Serializable key, String role, Serializable snapshot);
@ -92,7 +102,9 @@ public interface PersistentCollection {
public void postAction();
/**
* return the user-visible collection (or array) instance
* Return the user-visible collection (or array) instance
*
* @return The underlying collection/array
*/
public Object getValue();
@ -103,70 +115,121 @@ public interface PersistentCollection {
/**
* Called after reading all rows from the JDBC result set
*
* @return Whether to end the read.
*/
public boolean endRead();
/**
* Called after initializing from cache
*
* @return ??
*/
public boolean afterInitialize();
/**
* Could the application possibly have a direct reference to
* the underlying collection implementation?
*
* @return {@code true} indicates that the application might have access to the underlying collection/array.
*/
public boolean isDirectlyAccessible();
/**
* Disassociate this collection from the given session.
*
* @param currentSession The session we are disassociating from. Used for validations.
*
* @return true if this was currently associated with the given session
*/
public boolean unsetSession(SessionImplementor currentSession);
/**
* Associate the collection with the given session.
*
* @param session The session to associate with
*
* @return false if the collection was already associated with the session
*
* @throws HibernateException if the collection was already associated
* with another open session
*/
public boolean setCurrentSession(SessionImplementor session)
throws HibernateException;
public boolean setCurrentSession(SessionImplementor session) throws HibernateException;
/**
* Read the state of the collection from a disassembled cached value
*
* @param persister The collection persister
* @param disassembled The disassembled cached state
* @param owner The collection owner
*/
public void initializeFromCache(CollectionPersister persister,
Serializable disassembled, Object owner) throws HibernateException;
public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner);
/**
* Iterate all collection entries, during update of the database
*
* @param persister The collection persister.
*
* @return The iterator
*/
public Iterator entries(CollectionPersister persister);
/**
* Read a row from the JDBC result set
*
* @param rs The JDBC ResultSet
* @param role The collection role
* @param descriptor The aliases used for the columns making up the collection
* @param owner The collection owner
*
* @return The read object
*
* @throws HibernateException Generally indicates a problem resolving data read from the ResultSet
* @throws SQLException Indicates a problem accessing the ResultSet
*/
public Object readFrom(ResultSet rs, CollectionPersister role, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException;
/**
* Get the index of the given collection entry
* Get the identifier of the given collection entry. This refers to the collection identifier, not the
* identifier of the (possibly) entity elements. This is only valid for invocation on the
* {@code idbag} collection.
*
* @param entry The collection entry/element
* @param i The assumed identifier (?)
*
* @return The identifier value
*/
public Object getIdentifier(Object entry, int i);
/**
* Get the index of the given collection entry
*
* @param entry The collection entry/element
* @param i The assumed index
* @param persister it was more elegant before we added this...
*
* @return The index value
*/
public Object getIndex(Object entry, int i, CollectionPersister persister);
/**
* Get the value of the given collection entry
* Get the value of the given collection entry. Generally the given entry parameter value will just be returned.
* Might get a different value for a duplicate entries in a Set.
*
* @param entry The object instance for which to get the collection element instance.
*
* @return The corresponding object that is part of the collection elements.
*/
public Object getElement(Object entry);
/**
* Get the snapshot value of the given collection entry
*
* @param entry The entry
* @param i The index
*
* @return The snapshot state for that element
*/
public Object getSnapshotElement(Object entry, int i);
@ -175,106 +238,168 @@ public interface PersistentCollection {
* allowing appropriate initializations to occur.
*
* @param persister The underlying collection persister.
* @param anticipatedSize The anticipated size of the collection after initilization is complete.
* @param anticipatedSize The anticipated size of the collection after initialization is complete.
*/
public void beforeInitialize(CollectionPersister persister, int anticipatedSize);
/**
* Does the current state exactly match the snapshot?
*
* @param persister The collection persister
*
* @return {@code true} if the current state and the snapshot state match.
*
*/
public boolean equalsSnapshot(CollectionPersister persister)
throws HibernateException;
public boolean equalsSnapshot(CollectionPersister persister);
/**
* Is the snapshot empty?
*
* @param snapshot The snapshot to check
*
* @return {@code true} if the given snapshot is empty
*/
public boolean isSnapshotEmpty(Serializable snapshot);
/**
* Disassemble the collection, ready for the cache
* Disassemble the collection to get it ready for the cache
*
* @param persister The collection persister
*
* @return The disassembled state
*/
public Serializable disassemble(CollectionPersister persister)
throws HibernateException;
public Serializable disassemble(CollectionPersister persister) ;
/**
* Do we need to completely recreate this collection when it changes?
*
* @param persister The collection persister
*
* @return {@code true} if a change requires a recreate.
*/
public boolean needsRecreate(CollectionPersister persister);
/**
* Return a new snapshot of the current state of the collection
*
* @param persister The collection persister
*
* @return The snapshot
*/
public Serializable getSnapshot(CollectionPersister persister)
throws HibernateException;
public Serializable getSnapshot(CollectionPersister persister);
/**
* To be called internally by the session, forcing
* immediate initialization.
* To be called internally by the session, forcing immediate initialization.
*/
public void forceInitialization() throws HibernateException;
public void forceInitialization();
/**
* Does an element exist at this entry in the collection?
* Does the given element/entry exist in the collection?
*
* @param entry The object to check if it exists as a collection element
* @param i Unused
*
* @return {@code true} if the given entry is a collection element
*/
public boolean entryExists(Object entry, int i); //note that i parameter is now unused (delete it?)
public boolean entryExists(Object entry, int i);
/**
* Do we need to insert this element?
*
* @param entry The collection element to check
* @param i The index (for indexed collections)
* @param elemType The type for the element
*
* @return {@code true} if the element needs inserting
*/
public boolean needsInserting(Object entry, int i, Type elemType)
throws HibernateException;
public boolean needsInserting(Object entry, int i, Type elemType);
/**
* Do we need to update this element?
*
* @param entry The collection element to check
* @param i The index (for indexed collections)
* @param elemType The type for the element
*
* @return {@code true} if the element needs updating
*/
public boolean needsUpdating(Object entry, int i, Type elemType)
throws HibernateException;
public boolean needsUpdating(Object entry, int i, Type elemType);
/**
* Can each element in the collection be mapped unequivocally to a single row in the database? Generally
* bags and sets are the only collections that cannot be.
*
* @return {@code true} if the row for each element is known
*/
public boolean isRowUpdatePossible();
/**
* Get all the elements that need deleting
*
* @param persister The collection persister
* @param indexIsFormula For indexed collections, tells whether the index is a formula (calculated value) mapping
*
* @return An iterator over the elements to delete
*/
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula)
throws HibernateException;
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula);
/**
* Is this the wrapper for the given underlying collection instance?
* Is this the wrapper for the given collection instance?
*
* @param collection The collection to check whether this is wrapping it
*
* @return {@code true} if this is a wrapper around that given collection instance.
*/
public boolean isWrapper(Object collection);
/**
* Is this instance initialized?
*
* @return Was this collection initialized? Or is its data still not (fully) loaded?
*/
public boolean wasInitialized();
/**
* Does this instance have any "queued" additions?
* Does this instance have any "queued" operations?
*
* @return {@code true} indicates there are pending, queued, delayed operations
*/
public boolean hasQueuedOperations();
/**
* Iterate the "queued" additions
* Iterator over the "queued" additions
*
* @return The iterator
*/
public Iterator queuedAdditionIterator();
/**
* Get the "queued" orphans
*
* @param entityName The name of the entity that makes up the elements
*
* @return The orphaned elements
*/
public Collection getQueuedOrphans(String entityName);
/**
* Get the current collection key value
*
* @return the current collection key value
*/
public Serializable getKey();
/**
* Get the current role name
*
* @return the collection role name
*/
public String getRole();
/**
* Is the collection unreferenced?
*
* @return {@code true} if the collection is no longer referenced by an owner
*/
public boolean isUnreferenced();
@ -283,6 +408,8 @@ public interface PersistentCollection {
* reliable during the flush cycle, after the
* collection elements are dirty checked against
* the snapshot.
*
* @return {@code true} if the collection is dirty
*/
public boolean isDirty();
@ -293,8 +420,9 @@ public interface PersistentCollection {
public void clearDirty();
/**
* Get the snapshot cached by the collection
* instance
* Get the snapshot cached by the collection instance
*
* @return The internally stored snapshot state
*/
public Serializable getStoredSnapshot();
@ -306,20 +434,28 @@ public interface PersistentCollection {
/**
* Called before inserting rows, to ensure that any surrogate keys
* are fully generated
*
* @param persister The collection persister
*/
public void preInsert(CollectionPersister persister)
throws HibernateException;
public void preInsert(CollectionPersister persister);
/**
* Called after inserting a row, to fetch the natively generated id
*
* @param persister The collection persister
* @param entry The collection element just inserted
* @param i The element position/index
*/
public void afterRowInsert(CollectionPersister persister, Object entry, int i)
throws HibernateException;
public void afterRowInsert(CollectionPersister persister, Object entry, int i);
/**
* get all "orphaned" elements
*
* @param snapshot The snapshot state
* @param entityName The name of the entity that are the elements of the collection
*
* @return The orphans
*/
public Collection getOrphans(Serializable snapshot, String entityName)
throws HibernateException;
public Collection getOrphans(Serializable snapshot, String entityName);
}

View File

@ -0,0 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
/**
* SPI definitions for persistent collections
*/
package org.hibernate.collection.spi;

View File

@ -33,11 +33,22 @@ import org.hibernate.HibernateException;
* @author Steve Ebersole
*/
public class TenantIdentifierMismatchException extends HibernateException{
/**
* Constructs a TenantIdentifierMismatchException.
*
* @param message Message explaining the exception condition
*/
public TenantIdentifierMismatchException(String message) {
super( message );
}
public TenantIdentifierMismatchException(String message, Throwable root) {
super( message, root );
/**
* Constructs a TenantIdentifierMismatchException.
*
* @param message Message explaining the exception condition
* @param cause The underlying cause
*/
public TenantIdentifierMismatchException(String message, Throwable cause) {
super( message, cause );
}
}

View File

@ -28,47 +28,49 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.transaction.Synchronization;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.jboss.logging.Logger;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.context.spi.AbstractCurrentSessionContext;
import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.internal.CoreMessageLogger;
/**
* An implementation of {@link CurrentSessionContext} which scopes the notion
* of a current session to a JTA transaction. Because JTA gives us a nice
* tie-in to clean up after ourselves, this implementation will generate
* Sessions as needed provided a JTA transaction is in effect. If a session
* is not already associated with the current JTA transaction at the time
* {@link #currentSession()} is called, a new session will be opened and it
* will be associated with that JTA transaction.
* <p/>
* Note that the sessions returned from this method are automatically configured with
* both the {@link org.hibernate.cfg.Environment#FLUSH_BEFORE_COMPLETION auto-flush} and
* {@link org.hibernate.cfg.Environment#AUTO_CLOSE_SESSION auto-close} attributes set to
* true, meaning that the Session will be automatically flushed and closed
* as part of the lifecycle for the JTA transaction to which it is associated.
* Additionally, it will also be configured to aggressively release JDBC
* connections after each statement is executed. These settings are governed
* by the {@link #isAutoFlushEnabled()}, {@link #isAutoCloseEnabled()}, and
* {@link #getConnectionReleaseMode()} methods; these are provided (along with
* the {@link #buildOrObtainSession()} method) for easier subclassing for custom
* JTA-based session tracking logic (like maybe long-session semantics).
* An implementation of {@link org.hibernate.context.spi.CurrentSessionContext} which scopes the notion
* of a current session to a JTA transaction. Because JTA gives us a nice tie-in to clean up after
* ourselves, this implementation will generate Sessions as needed provided a JTA transaction is in
* effect. If a session is not already associated with the current JTA transaction at the time
* {@link #currentSession()} is called, a new session will be opened and it will be associated with that
* JTA transaction.
*
* Note that the sessions returned from this method are automatically configured with both the
* {@link org.hibernate.cfg.Environment#FLUSH_BEFORE_COMPLETION auto-flush} and
* {@link org.hibernate.cfg.Environment#AUTO_CLOSE_SESSION auto-close} attributes set to true, meaning
* that the Session will be automatically flushed and closed as part of the lifecycle for the JTA
* transaction to which it is associated. Additionally, it will also be configured to aggressively
* release JDBC connections after each statement is executed. These settings are governed by the
* {@link #isAutoFlushEnabled()}, {@link #isAutoCloseEnabled()}, and {@link #getConnectionReleaseMode()}
* methods; these are provided (along with the {@link #buildOrObtainSession()} method) for easier
* subclassing for custom JTA-based session tracking logic (like maybe long-session semantics).
*
* @author Steve Ebersole
*/
public class JTASessionContext extends AbstractCurrentSessionContext {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, JTASessionContext.class.getName());
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
JTASessionContext.class.getName()
);
private transient Map<Object, Session> currentSessionMap = new ConcurrentHashMap<Object, Session>();
/**
* Constructs a JTASessionContext
*
* @param factory The factory this context will service
*/
public JTASessionContext(SessionFactoryImplementor factory) {
super( factory );
}
@ -131,24 +133,23 @@ public class JTASessionContext extends AbstractCurrentSessionContext {
}
/**
* Builds a {@link CleanupSynch} capable of cleaning up the the current session map as an after transaction
* Builds a {@link org.hibernate.context.internal.JTASessionContext.CleanupSync} capable of cleaning up the the current session map as an after transaction
* callback.
*
* @param transactionIdentifier The transaction identifier under which the current session is registered.
* @return The cleanup synch.
*/
private CleanupSynch buildCleanupSynch(Object transactionIdentifier) {
return new CleanupSynch( transactionIdentifier, this );
private CleanupSync buildCleanupSynch(Object transactionIdentifier) {
return new CleanupSync( transactionIdentifier, this );
}
/**
* Strictly provided for subclassing purposes; specifically to allow long-session
* support.
* <p/>
* This implementation always just opens a new session.
* support. This implementation always just opens a new session.
*
* @return the built or (re)obtained session.
*/
@SuppressWarnings("deprecation")
protected Session buildOrObtainSession() {
return baseSessionBuilder()
.autoClose( isAutoCloseEnabled() )
@ -185,26 +186,22 @@ public class JTASessionContext extends AbstractCurrentSessionContext {
}
/**
* JTA transaction synch used for cleanup of the internal session map.
* JTA transaction sync used for cleanup of the internal session map.
*/
protected static class CleanupSynch implements Synchronization {
protected static class CleanupSync implements Synchronization {
private Object transactionIdentifier;
private JTASessionContext context;
public CleanupSynch(Object transactionIdentifier, JTASessionContext context) {
public CleanupSync(Object transactionIdentifier, JTASessionContext context) {
this.transactionIdentifier = transactionIdentifier;
this.context = context;
}
/**
* {@inheritDoc}
*/
@Override
public void beforeCompletion() {
}
/**
* {@inheritDoc}
*/
@Override
public void afterCompletion(int i) {
context.currentSessionMap.remove( transactionIdentifier );
}

View File

@ -57,16 +57,20 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
* @author Steve Ebersole
*/
public class ManagedSessionContext extends AbstractCurrentSessionContext {
private static final ThreadLocal<Map<SessionFactory,Session>> CONTEXT_TL = new ThreadLocal<Map<SessionFactory,Session>>();
private static final ThreadLocal<Map<SessionFactory,Session>> context = new ThreadLocal<Map<SessionFactory,Session>>();
/**
* Constructs a new ManagedSessionContext
*
* @param factory The factory this context will service
*/
public ManagedSessionContext(SessionFactoryImplementor factory) {
super( factory );
}
@Override
public Session currentSession() {
Session current = existingSession( factory() );
final Session current = existingSession( factory() );
if ( current == null ) {
throw new HibernateException( "No session currently bound to execution context" );
}
@ -106,8 +110,8 @@ public class ManagedSessionContext extends AbstractCurrentSessionContext {
* @return The bound session if one, else null.
*/
public static Session unbind(SessionFactory factory) {
final Map<SessionFactory,Session> sessionMap = sessionMap();
Session existing = null;
Map<SessionFactory,Session> sessionMap = sessionMap();
if ( sessionMap != null ) {
existing = sessionMap.remove( factory );
doCleanup();
@ -116,12 +120,12 @@ public class ManagedSessionContext extends AbstractCurrentSessionContext {
}
private static Session existingSession(SessionFactory factory) {
Map sessionMap = sessionMap();
final Map sessionMap = sessionMap();
if ( sessionMap == null ) {
return null;
}
else {
return ( Session ) sessionMap.get( factory );
return (Session) sessionMap.get( factory );
}
}
@ -130,19 +134,19 @@ public class ManagedSessionContext extends AbstractCurrentSessionContext {
}
private static synchronized Map<SessionFactory,Session> sessionMap(boolean createMap) {
Map<SessionFactory,Session> sessionMap = context.get();
Map<SessionFactory,Session> sessionMap = CONTEXT_TL.get();
if ( sessionMap == null && createMap ) {
sessionMap = new HashMap<SessionFactory,Session>();
context.set( sessionMap );
CONTEXT_TL.set( sessionMap );
}
return sessionMap;
}
private static synchronized void doCleanup() {
Map<SessionFactory,Session> sessionMap = sessionMap( false );
final Map<SessionFactory,Session> sessionMap = sessionMap( false );
if ( sessionMap != null ) {
if ( sessionMap.isEmpty() ) {
context.set( null );
CONTEXT_TL.set( null );
}
}
}

View File

@ -42,7 +42,6 @@ import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.context.spi.AbstractCurrentSessionContext;
import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
@ -51,35 +50,33 @@ import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreMessageLogger;
/**
* A {@link CurrentSessionContext} impl which scopes the notion of current
* session by the current thread of execution. Unlike the JTA counterpart,
* threads do not give us a nice hook to perform any type of cleanup making
* it questionable for this impl to actually generate Session instances. In
* the interest of usability, it was decided to have this default impl
* actually generate a session upon first request and then clean it up
* after the {@link org.hibernate.Transaction} associated with that session
* is committed/rolled-back. In order for ensuring that happens, the sessions
* generated here are unusable until after {@link Session#beginTransaction()}
* has been called. If <tt>close()</tt> is called on a session managed by
* this class, it will be automatically unbound.
* <p/>
* Additionally, the static {@link #bind} and {@link #unbind} methods are
* provided to allow application code to explicitly control opening and
* closing of these sessions. This, with some from of interception,
* is the preferred approach. It also allows easy framework integration
* and one possible approach for implementing long-sessions.
* <p/>
* The {@link #buildOrObtainSession}, {@link #isAutoCloseEnabled},
* {@link #isAutoFlushEnabled}, {@link #getConnectionReleaseMode}, and
* {@link #buildCleanupSynch} methods are all provided to allow easy
* A {@link org.hibernate.context.spi.CurrentSessionContext} impl which scopes the notion of current
* session by the current thread of execution. Unlike the JTA counterpart, threads do not give us a nice
* hook to perform any type of cleanup making it questionable for this impl to actually generate Session
* instances. In the interest of usability, it was decided to have this default impl actually generate
* a session upon first request and then clean it up after the {@link org.hibernate.Transaction}
* associated with that session is committed/rolled-back. In order for ensuring that happens, the
* sessions generated here are unusable until after {@link Session#beginTransaction()} has been
* called. If <tt>close()</tt> is called on a session managed by this class, it will be automatically
* unbound.
*
* Additionally, the static {@link #bind} and {@link #unbind} methods are provided to allow application
* code to explicitly control opening and closing of these sessions. This, with some from of interception,
* is the preferred approach. It also allows easy framework integration and one possible approach for
* implementing long-sessions.
*
* The {@link #buildOrObtainSession}, {@link #isAutoCloseEnabled}, {@link #isAutoFlushEnabled},
* {@link #getConnectionReleaseMode}, and {@link #buildCleanupSynch} methods are all provided to allow easy
* subclassing (for long-running session scenarios, for example).
*
* @author Steve Ebersole
*/
public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
ThreadLocalSessionContext.class.getName()
);
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class,
ThreadLocalSessionContext.class.getName());
private static final Class[] SESSION_PROXY_INTERFACES = new Class[] {
Session.class,
SessionImplementor.class,
@ -91,11 +88,16 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
/**
* A ThreadLocal maintaining current sessions for the given execution thread.
* The actual ThreadLocal variable is a java.util.Map to account for
* the possibility for multiple SessionFactorys being used during execution
* the possibility for multiple SessionFactory instances being used during execution
* of the given thread.
*/
private static final ThreadLocal<Map> context = new ThreadLocal<Map>();
private static final ThreadLocal<Map> CONTEXT_TL = new ThreadLocal<Map>();
/**
* Constructs a ThreadLocal
*
* @param factory The factory this context will service
*/
public ThreadLocalSessionContext(SessionFactoryImplementor factory) {
super( factory );
}
@ -122,10 +124,15 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
private boolean needsWrapping(Session session) {
// try to make sure we don't wrap and already wrapped session
return session != null
&& ! Proxy.isProxyClass( session.getClass() )
|| ( Proxy.getInvocationHandler( session ) != null
&& ! ( Proxy.getInvocationHandler( session ) instanceof TransactionProtectionWrapper ) );
if ( session != null ) {
if ( Proxy.isProxyClass( session.getClass() ) ) {
final InvocationHandler invocationHandler = Proxy.getInvocationHandler( session );
if ( invocationHandler != null && TransactionProtectionWrapper.class.isInstance( invocationHandler ) ) {
return false;
}
}
}
return true;
}
/**
@ -138,13 +145,14 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
}
/**
* Strictly provided for subclassing purposes; specifically to allow long-session
* Strictly provided for sub-classing purposes; specifically to allow long-session
* support.
* <p/>
* This implementation always just opens a new session.
*
* @return the built or (re)obtained session.
*/
@SuppressWarnings("deprecation")
protected Session buildOrObtainSession() {
return baseSessionBuilder()
.autoClose( isAutoCloseEnabled() )
@ -153,8 +161,8 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
.openSession();
}
protected CleanupSynch buildCleanupSynch() {
return new CleanupSynch( factory() );
protected CleanupSync buildCleanupSynch() {
return new CleanupSync( factory() );
}
/**
@ -185,8 +193,8 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
}
protected Session wrap(Session session) {
TransactionProtectionWrapper wrapper = new TransactionProtectionWrapper( session );
Session wrapped = ( Session ) Proxy.newProxyInstance(
final TransactionProtectionWrapper wrapper = new TransactionProtectionWrapper( session );
final Session wrapped = (Session) Proxy.newProxyInstance(
Session.class.getClassLoader(),
SESSION_PROXY_INTERFACES,
wrapper
@ -202,13 +210,13 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
* @param session The session to bind.
*/
public static void bind(org.hibernate.Session session) {
SessionFactory factory = session.getSessionFactory();
final SessionFactory factory = session.getSessionFactory();
cleanupAnyOrphanedSession( factory );
doBind( session, factory );
}
private static void cleanupAnyOrphanedSession(SessionFactory factory) {
Session orphan = doUnbind( factory, false );
final Session orphan = doUnbind( factory, false );
if ( orphan != null ) {
LOG.alreadySessionBound();
try {
@ -239,7 +247,7 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
}
private static Session existingSession(SessionFactory factory) {
Map sessionMap = sessionMap();
final Map sessionMap = sessionMap();
if ( sessionMap == null ) {
return null;
}
@ -247,7 +255,7 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
}
protected static Map sessionMap() {
return context.get();
return CONTEXT_TL.get();
}
@SuppressWarnings({"unchecked"})
@ -255,42 +263,38 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
Map sessionMap = sessionMap();
if ( sessionMap == null ) {
sessionMap = new HashMap();
context.set( sessionMap );
CONTEXT_TL.set( sessionMap );
}
sessionMap.put( factory, session );
}
private static Session doUnbind(SessionFactory factory, boolean releaseMapIfEmpty) {
Map sessionMap = sessionMap();
Session session = null;
final Map sessionMap = sessionMap();
if ( sessionMap != null ) {
session = ( Session ) sessionMap.remove( factory );
session = (Session) sessionMap.remove( factory );
if ( releaseMapIfEmpty && sessionMap.isEmpty() ) {
context.set( null );
CONTEXT_TL.set( null );
}
}
return session;
}
/**
* JTA transaction synch used for cleanup of the internal session map.
* Transaction sync used for cleanup of the internal session map.
*/
protected static class CleanupSynch implements Synchronization, Serializable {
protected static class CleanupSync implements Synchronization, Serializable {
protected final SessionFactory factory;
public CleanupSynch(SessionFactory factory) {
public CleanupSync(SessionFactory factory) {
this.factory = factory;
}
/**
* {@inheritDoc}
*/
@Override
public void beforeCompletion() {
}
/**
* {@inheritDoc}
*/
@Override
public void afterCompletion(int i) {
unbind( factory );
}
@ -304,9 +308,7 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
this.realSession = realSession;
}
/**
* {@inheritDoc}
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String methodName = method.getName();
try {
@ -319,9 +321,9 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
|| "hashCode".equals( methodName )
|| "getStatistics".equals( methodName )
|| "isOpen".equals( methodName )
|| "getListeners".equals( methodName )
) {
|| "getListeners".equals( methodName ) ) {
// allow these to go through the the real session no matter what
LOG.tracef( "Allowing invocation [%s] to proceed to real session", methodName );
}
else if ( !realSession.isOpen() ) {
// essentially, if the real session is closed allow any
@ -329,6 +331,7 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
// will complain by throwing an appropriate exception;
// NOTE that allowing close() above has the same basic effect,
// but we capture that there simply to doAfterTransactionCompletion the unbind...
LOG.tracef( "Allowing invocation [%s] to proceed to real (closed) session", methodName );
}
else if ( !realSession.getTransaction().isActive() ) {
// limit the methods available if no transaction is active
@ -339,20 +342,23 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
|| "getFactory".equals( methodName )
|| "getSessionFactory".equals( methodName )
|| "getTenantIdentifier".equals( methodName ) ) {
LOG.tracev( "Allowing method [{0}] in non-transacted context", methodName );
LOG.tracef( "Allowing invocation [%s] to proceed to real (non-transacted) session", methodName );
}
else if ( "reconnect".equals( methodName ) || "disconnect".equals( methodName ) ) {
// allow these (deprecated) methods to pass through
LOG.tracef( "Allowing invocation [%s] to proceed to real (non-transacted) session - deprecated methods", methodName );
}
else {
throw new HibernateException( methodName + " is not valid without active transaction" );
}
}
LOG.tracev( "Allowing proxied method [{0}] to proceed to real session", methodName );
LOG.tracef( "Allowing proxy invocation [%s] to proceed to real session", methodName );
return method.invoke( realSession, args );
}
catch ( InvocationTargetException e ) {
if (e.getTargetException() instanceof RuntimeException) throw (RuntimeException)e.getTargetException();
if (e.getTargetException() instanceof RuntimeException) {
throw (RuntimeException)e.getTargetException();
}
throw e;
}
}

View File

@ -0,0 +1,4 @@
/**
* Internal implementations and support around "current session" handling.
*/
package org.hibernate.context.internal;

View File

@ -0,0 +1,4 @@
/**
* Defines support for "current session" feature.
*/
package org.hibernate.context;

View File

@ -41,6 +41,11 @@ public abstract class AbstractCurrentSessionContext implements CurrentSessionCon
this.factory = factory;
}
/**
* Access to the SessionFactory
*
* @return The SessionFactory being serviced by this context
*/
public SessionFactoryImplementor factory() {
return factory;
}

View File

@ -0,0 +1,4 @@
/**
* SPI level contracts around "current session" support.
*/
package org.hibernate.context.spi;

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
@ -37,7 +36,7 @@ import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;
/**
* Implementation of AbstractEmptinessExpression.
* Base expression implementation for (not) emptiness checking of collection properties
*
* @author Steve Ebersole
*/
@ -51,21 +50,26 @@ public abstract class AbstractEmptinessExpression implements Criterion {
this.propertyName = propertyName;
}
/**
* Should empty rows be excluded?
*
* @return {@code true} Indicates the expression should be 'exists'; {@code false} indicates 'not exists'
*/
protected abstract boolean excludeEmpty();
@Override
public final String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
String entityName = criteriaQuery.getEntityName( criteria, propertyName );
String actualPropertyName = criteriaQuery.getPropertyName( propertyName );
String sqlAlias = criteriaQuery.getSQLAlias( criteria, propertyName );
final String entityName = criteriaQuery.getEntityName( criteria, propertyName );
final String actualPropertyName = criteriaQuery.getPropertyName( propertyName );
final String sqlAlias = criteriaQuery.getSQLAlias( criteria, propertyName );
SessionFactoryImplementor factory = criteriaQuery.getFactory();
QueryableCollection collectionPersister = getQueryableCollection( entityName, actualPropertyName, factory );
final SessionFactoryImplementor factory = criteriaQuery.getFactory();
final QueryableCollection collectionPersister = getQueryableCollection( entityName, actualPropertyName, factory );
String[] collectionKeys = collectionPersister.getKeyColumnNames();
String[] ownerKeys = ( ( Loadable ) factory.getEntityPersister( entityName ) ).getIdentifierColumnNames();
final String[] collectionKeys = collectionPersister.getKeyColumnNames();
final String[] ownerKeys = ( (Loadable) factory.getEntityPersister( entityName ) ).getIdentifierColumnNames();
String innerSelect = "(select 1 from " + collectionPersister.getTableName()
+ " where "
final String innerSelect = "(select 1 from " + collectionPersister.getTableName() + " where "
+ new ConditionFragment().setTableAlias( sqlAlias ).setCondition( ownerKeys, collectionKeys ).toFragmentString()
+ ")";
@ -75,19 +79,21 @@ public abstract class AbstractEmptinessExpression implements Criterion {
}
protected QueryableCollection getQueryableCollection(String entityName, String propertyName, SessionFactoryImplementor factory)
throws HibernateException {
PropertyMapping ownerMapping = ( PropertyMapping ) factory.getEntityPersister( entityName );
Type type = ownerMapping.toType( propertyName );
protected QueryableCollection getQueryableCollection(
String entityName,
String propertyName,
SessionFactoryImplementor factory) throws HibernateException {
final PropertyMapping ownerMapping = (PropertyMapping) factory.getEntityPersister( entityName );
final Type type = ownerMapping.toType( propertyName );
if ( !type.isCollectionType() ) {
throw new MappingException(
"Property path [" + entityName + "." + propertyName + "] does not reference a collection"
);
}
String role = ( ( CollectionType ) type ).getRole();
final String role = ( (CollectionType) type ).getRole();
try {
return ( QueryableCollection ) factory.getCollectionPersister( role );
return (QueryableCollection) factory.getCollectionPersister( role );
}
catch ( ClassCastException cce ) {
throw new QueryException( "collection role is not queryable: " + role );
@ -97,11 +103,13 @@ public abstract class AbstractEmptinessExpression implements Criterion {
}
}
@Override
public final TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return NO_VALUES;
}
@Override
public final String toString() {
return propertyName + ( excludeEmpty() ? " is not empty" : " is empty" );
}

View File

@ -52,13 +52,7 @@ public class AggregateProjection extends SimpleProjection {
return propertyName;
}
public String toString() {
return functionName + "(" + propertyName + ')';
}
/**
* {@inheritDoc}
*/
@Override
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return new Type[] {
getFunction( criteriaQuery ).getReturnType(
@ -68,9 +62,7 @@ public class AggregateProjection extends SimpleProjection {
};
}
/**
* {@inheritDoc}
*/
@Override
public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery) throws HibernateException {
final String functionFragment = getFunction( criteriaQuery ).render(
criteriaQuery.getType( criteria, getPropertyName() ),
@ -85,7 +77,7 @@ public class AggregateProjection extends SimpleProjection {
}
protected SQLFunction getFunction(String functionName, CriteriaQuery criteriaQuery) {
SQLFunction function = criteriaQuery.getFactory()
final SQLFunction function = criteriaQuery.getFactory()
.getSqlFunctionRegistry()
.findSQLFunction( functionName );
if ( function == null ) {
@ -101,4 +93,10 @@ public class AggregateProjection extends SimpleProjection {
protected List buildFunctionParameterList(String column) {
return Collections.singletonList( column );
}
@Override
public String toString() {
return functionName + "(" + propertyName + ')';
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
@ -28,71 +27,80 @@ import org.hibernate.HibernateException;
import org.hibernate.type.Type;
/**
* Represents a projection that specifies an alias
*
* @author Gavin King
*/
public class AliasedProjection implements EnhancedProjection {
private final Projection projection;
private final String alias;
public String toString() {
return projection.toString() + " as " + alias;
}
protected AliasedProjection(Projection projection, String alias) {
this.projection = projection;
this.alias = alias;
}
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery)
throws HibernateException {
return projection.toSqlString(criteria, position, criteriaQuery);
@Override
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) throws HibernateException {
return projection.toSqlString( criteria, position, criteriaQuery );
}
@Override
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
return projection.toGroupSqlString(criteria, criteriaQuery);
return projection.toGroupSqlString( criteria, criteriaQuery );
}
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return projection.getTypes(criteria, criteriaQuery);
@Override
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return projection.getTypes( criteria, criteriaQuery );
}
@Override
public String[] getColumnAliases(int loc) {
return projection.getColumnAliases(loc);
return projection.getColumnAliases( loc );
}
@Override
public String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
return projection instanceof EnhancedProjection ?
( ( EnhancedProjection ) projection ).getColumnAliases( loc, criteria, criteriaQuery ) :
getColumnAliases( loc );
return projection instanceof EnhancedProjection
? ( (EnhancedProjection) projection ).getColumnAliases( loc, criteria, criteriaQuery )
: getColumnAliases( loc );
}
public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return this.alias.equals(alias) ?
getTypes(criteria, criteriaQuery) :
null;
@Override
public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return this.alias.equals( alias )
? getTypes( criteria, criteriaQuery )
: null;
}
@Override
public String[] getColumnAliases(String alias, int loc) {
return this.alias.equals(alias) ?
getColumnAliases(loc) :
null;
return this.alias.equals( alias )
? getColumnAliases( loc )
: null;
}
@Override
public String[] getColumnAliases(String alias, int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
return this.alias.equals(alias) ?
getColumnAliases( loc, criteria, criteriaQuery ) :
null;
return this.alias.equals( alias )
? getColumnAliases( loc, criteria, criteriaQuery )
: null;
}
@Override
public String[] getAliases() {
return new String[]{ alias };
return new String[] { alias };
}
@Override
public boolean isGrouped() {
return projection.isGrouped();
}
@Override
public String toString() {
return projection.toString() + " as " + alias;
}
}

View File

@ -23,14 +23,18 @@
*/
package org.hibernate.criterion;
/**
* An avg() projection
*
* @author Gavin King
*/
public class AvgProjection extends AggregateProjection {
/**
* Constructs the AvgProjection
*
* @param propertyName The name of the property to average
*/
public AvgProjection(String propertyName) {
super("avg", propertyName);
super( "avg", propertyName );
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.TypedValue;
@ -30,10 +30,10 @@ import org.hibernate.internal.util.StringHelper;
/**
* Constrains a property to between two values
*
* @author Gavin King
*/
public class BetweenExpression implements Criterion {
private final String propertyName;
private final Object lo;
private final Object hi;
@ -44,24 +44,22 @@ public class BetweenExpression implements Criterion {
this.hi = hi;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return StringHelper.join(
" and ",
StringHelper.suffix( criteriaQuery.findColumns(propertyName, criteria), " between ? and ?" )
);
//TODO: get SQL rendering out of this package!
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
final String[] expressions = StringHelper.suffix( columns, " between ? and ?" );
return StringHelper.join( " and ", expressions );
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return new TypedValue[] {
criteriaQuery.getTypedValue(criteria, propertyName, lo),
criteriaQuery.getTypedValue(criteria, propertyName, hi)
criteriaQuery.getTypedValue( criteria, propertyName, lo ),
criteriaQuery.getTypedValue( criteria, propertyName, hi )
};
}
@Override
public String toString() {
return propertyName + " between " + lo + " and " + hi;
}

View File

@ -24,10 +24,22 @@
package org.hibernate.criterion;
/**
* Defines a conjunction (AND series).
*
* @author Gavin King
* @author Steve Ebersole
*
* @see Disjunction
*/
public class Conjunction extends Junction {
/**
* Constructs a Conjunction
*/
public Conjunction() {
super( Nature.AND );
}
protected Conjunction(Criterion... criterion) {
super( Nature.AND, criterion );
}
}

View File

@ -29,16 +29,50 @@ import java.util.List;
import org.hibernate.Criteria;
/**
* A count
* A count projection
*
* @author Gavin King
*/
public class CountProjection extends AggregateProjection {
private boolean distinct;
/**
* Constructs the count projection.
*
* @param prop The property name
*
* @see Projections#count(String)
* @see Projections#countDistinct(String)
*/
protected CountProjection(String prop) {
super("count", prop);
super( "count", prop );
}
@Override
protected List buildFunctionParameterList(Criteria criteria, CriteriaQuery criteriaQuery) {
final String[] cols = criteriaQuery.getColumns( propertyName, criteria );
return ( distinct ? buildCountDistinctParameterList( cols ) : Arrays.asList( cols ) );
}
@SuppressWarnings("unchecked")
private List buildCountDistinctParameterList(String[] cols) {
final List params = new ArrayList( cols.length + 1 );
params.add( "distinct" );
params.addAll( Arrays.asList( cols ) );
return params;
}
/**
* Sets the count as being distinct
*
* @return {@code this}, for method chaining
*/
public CountProjection setDistinct() {
distinct = true;
return this;
}
@Override
public String toString() {
if ( distinct ) {
return "distinct " + super.toString();
@ -48,20 +82,4 @@ public class CountProjection extends AggregateProjection {
}
}
protected List buildFunctionParameterList(Criteria criteria, CriteriaQuery criteriaQuery) {
String cols[] = criteriaQuery.getColumns( propertyName, criteria );
return ( distinct ? buildCountDistinctParameterList( cols ) : Arrays.asList( cols ) );
}
private List buildCountDistinctParameterList(String[] cols) {
List params = new ArrayList( cols.length + 1 );
params.add( "distinct" );
params.addAll( Arrays.asList( cols ) );
return params;
}
public CountProjection setDistinct() {
distinct = true;
return this;
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -38,93 +38,183 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public interface CriteriaQuery {
/**
* Provides access to the SessionFactory
*
* @return The SessionFactory
*/
public SessionFactoryImplementor getFactory();
/**
* Get the names of the columns mapped by a property path,
* ignoring projection aliases
* @throws org.hibernate.QueryException if the property maps to more than 1 column
* Resolve a property path to the name of the column it maps to. Ignores projection aliases.
*
* @param criteria The overall criteria
* @param propertyPath The property path to resolve
*
* @return The column name
*
* @throws HibernateException if the property maps to more than 1 column, or if the property could not be resolved
*
* @see #getColumns
*/
public String getColumn(Criteria criteria, String propertyPath)
throws HibernateException;
public String getColumn(Criteria criteria, String propertyPath) throws HibernateException;
/**
* Get the names of the columns mapped by a property path,
* ignoring projection aliases
* Resolve a property path to the names of the columns it maps to. Ignores projection aliases
*
* @param criteria The criteria
* @param propertyPath The property path to resolve
*
* @return The column names
*
* @throws HibernateException if the property maps to more than 1 column, or if the property could not be resolved
*/
public String[] getColumns(String propertyPath, Criteria criteria)
throws HibernateException;
public String[] getColumns(String propertyPath, Criteria criteria) throws HibernateException;
/**
* Get the names of the columns mapped by a property path; if the
* property path is not found in criteria, try the "outer" query.
* Projection aliases are ignored.
* Get the names of the columns mapped by a property path; if the property path is not found in criteria, try
* the "outer" query. Projection aliases are ignored.
*
* @param criteria The criteria
* @param propertyPath The property path to resolve
*
* @return The column names
*
* @throws HibernateException if the property could not be resolved
*/
public String[] findColumns(String propertyPath, Criteria criteria)
throws HibernateException;
public String[] findColumns(String propertyPath, Criteria criteria) throws HibernateException;
/**
* Get the type of a property path, ignoring projection aliases
* Get the type of a property path.
*
* @param criteria The criteria
* @param propertyPath The property path to resolve
*
* @return The type
*
* @throws HibernateException if the property could not be resolved
*/
public Type getType(Criteria criteria, String propertyPath)
throws HibernateException;
public Type getType(Criteria criteria, String propertyPath) throws HibernateException;
/**
* Get the names of the columns mapped by a property path
* Get the names of the columns mapped by a property path. Here, the property path can refer to
* a projection alias.
*
* @param criteria The criteria
* @param propertyPath The property path to resolve or projection alias
*
* @return The column names
*
* @throws HibernateException if the property/alias could not be resolved
*/
public String[] getColumnsUsingProjection(Criteria criteria, String propertyPath)
throws HibernateException;
public String[] getColumnsUsingProjection(Criteria criteria, String propertyPath) throws HibernateException;
/**
* Get the type of a property path
* Get the type of a property path. Here, the property path can refer to a projection alias.
*
* @param criteria The criteria
* @param propertyPath The property path to resolve or projection alias
*
* @return The type
*
* @throws HibernateException if the property/alias could not be resolved
*/
public Type getTypeUsingProjection(Criteria criteria, String propertyPath)
throws HibernateException;
public Type getTypeUsingProjection(Criteria criteria, String propertyPath) throws HibernateException;
/**
* Get the a typed value for the given property value.
* Build a typed-value for the property/value combo. Essentially the same as manually building a TypedValue
* using the given value and the resolved type using {@link #getTypeUsingProjection}.
*
* @param criteria The criteria query
* @param propertyPath The property path/alias to resolve to type.
* @param value The value
*
* @return The TypedValue
*
* @throws HibernateException if the property/alias could not be resolved
*/
public TypedValue getTypedValue(Criteria criteria, String propertyPath, Object value)
throws HibernateException;
public TypedValue getTypedValue(Criteria criteria, String propertyPath, Object value) throws HibernateException;
/**
* Get the entity name of an entity
*
* @param criteria The criteria
*
* @return The entity name
*/
public String getEntityName(Criteria criteria);
/**
* Get the entity name of an entity, taking into account
* the qualifier of the property path
* Get the entity name of an entity, taking into account the qualifier of the property path
*
* @param criteria The criteria
* @param propertyPath The property path that (supposedly) references an entity
*
* @return The entity name
*/
public String getEntityName(Criteria criteria, String propertyPath);
/**
* Get the root table alias of an entity
*
* @param criteria The criteria
*
* @return The SQL table alias for the given criteria
*/
public String getSQLAlias(Criteria subcriteria);
public String getSQLAlias(Criteria criteria);
/**
* Get the root table alias of an entity, taking into account
* the qualifier of the property path
*
* @param criteria The criteria
* @param propertyPath The property path whose SQL alias should be returned.
*
* @return The SQL table alias for the given criteria
*/
public String getSQLAlias(Criteria criteria, String propertyPath);
/**
* Get the property name, given a possibly qualified property name
*
* @param propertyName The (possibly qualified) property name
*
* @return The simple property name
*/
public String getPropertyName(String propertyName);
/**
* Get the identifier column names of this entity
*
* @param criteria The criteria
*
* @return The identifier column names
*/
public String[] getIdentifierColumns(Criteria subcriteria);
public String[] getIdentifierColumns(Criteria criteria);
/**
* Get the identifier type of this entity
*
* @param criteria The criteria
*
* @return The identifier type.
*/
public Type getIdentifierType(Criteria subcriteria);
public Type getIdentifierType(Criteria criteria);
public TypedValue getTypedIdentifierValue(Criteria subcriteria, Object value);
/**
* Build a TypedValue for the given identifier value.
*
* @param criteria The criteria whose identifier is referenced.
* @param value The identifier value
*
* @return The TypedValue
*/
public TypedValue getTypedIdentifierValue(Criteria criteria, Object value);
/**
* Generate a unique SQL alias
*
* @return The generated alias
*/
public String generateSQLAlias();
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.sql.JoinType;
import org.hibernate.transform.AliasToEntityMapResultTransformer;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
@ -31,6 +31,8 @@ import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.RootEntityResultTransformer;
/**
* Commonality between different types of Criteria.
*
* @author Gavin King
*/
public interface CriteriaSpecification {
@ -62,24 +64,27 @@ public interface CriteriaSpecification {
/**
* Specifies joining to an entity based on an inner join.
* @deprecated use {@link JoinType#INNER_JOIN}
*
* @deprecated use {@link org.hibernate.sql.JoinType#INNER_JOIN}
*/
@Deprecated
public static final int INNER_JOIN = org.hibernate.sql.JoinFragment.INNER_JOIN;
public static final int INNER_JOIN = JoinType.INNER_JOIN.getJoinTypeValue();
/**
* Specifies joining to an entity based on a full join.
* @deprecated use {@link JoinType#FULL_JOIN}
*
* @deprecated use {@link org.hibernate.sql.JoinType#FULL_JOIN}
*/
@Deprecated
public static final int FULL_JOIN = org.hibernate.sql.JoinFragment.FULL_JOIN;
public static final int FULL_JOIN = JoinType.FULL_JOIN.getJoinTypeValue();
/**
* Specifies joining to an entity based on a left outer join.
* @deprecated use {@link JoinType#LEFT_OUTER_JOIN}
*
* @deprecated use {@link org.hibernate.sql.JoinType#LEFT_OUTER_JOIN}
*/
@Deprecated
public static final int LEFT_JOIN = org.hibernate.sql.JoinFragment.LEFT_OUTER_JOIN;
public static final int LEFT_JOIN = JoinType.LEFT_OUTER_JOIN.getJoinTypeValue();
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,14 +20,13 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import java.io.Serializable;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.engine.spi.SessionImplementor;
@ -36,29 +35,36 @@ import org.hibernate.sql.JoinType;
import org.hibernate.transform.ResultTransformer;
/**
* Some applications need to create criteria queries in "detached
* mode", where the Hibernate session is not available. This class
* may be instantiated anywhere, and then a <literal>Criteria</literal>
* may be obtained by passing a session to
* <literal>getExecutableCriteria()</literal>. All methods have the
* same semantics and behavior as the corresponding methods of the
* <literal>Criteria</literal> interface.
* Models a detached form of a Criteria (not associated with a Session).
*
* Some applications need to create criteria queries in "detached mode", where the Hibernate Session is
* not available. Applications would create a DetachableCriteria to describe the query, and then later
* associated it with a Session to obtain the "executable" Criteria:
* <code>
* DetachedCriteria detached = new DetachedCriteria();
* ...
* Criteria criteria = detached.getExecutableCriteria( session );
* ...
* criteria.list();
* </code>
*
* All methods have the same semantics and behavior as the corresponding methods of the Criteria interface.
*
* @author Gavin King
*
* @see org.hibernate.Criteria
* @author Gavin King
*/
public class DetachedCriteria implements CriteriaSpecification, Serializable {
private final CriteriaImpl impl;
private final Criteria criteria;
protected DetachedCriteria(String entityName) {
impl = new CriteriaImpl(entityName, null);
impl = new CriteriaImpl( entityName, null );
criteria = impl;
}
protected DetachedCriteria(String entityName, String alias) {
impl = new CriteriaImpl(entityName, alias, null);
impl = new CriteriaImpl( entityName, alias, null );
criteria = impl;
}
@ -68,154 +74,373 @@ public class DetachedCriteria implements CriteriaSpecification, Serializable {
}
/**
* Get an executable instance of <literal>Criteria</literal>,
* to actually run the query.
* Get an executable instance of Criteria to actually run the query.
*
* @param session The session to associate the built Criteria with
*
* @return The "executable" Criteria
*/
public Criteria getExecutableCriteria(Session session) {
impl.setSession( ( SessionImplementor ) session );
impl.setSession( (SessionImplementor) session );
return impl;
}
public static DetachedCriteria forEntityName(String entityName) {
return new DetachedCriteria(entityName);
}
public static DetachedCriteria forEntityName(String entityName, String alias) {
return new DetachedCriteria(entityName, alias);
}
public static DetachedCriteria forClass(Class clazz) {
return new DetachedCriteria( clazz.getName() );
}
public static DetachedCriteria forClass(Class clazz, String alias) {
return new DetachedCriteria( clazz.getName() , alias );
}
public DetachedCriteria add(Criterion criterion) {
criteria.add(criterion);
return this;
}
public DetachedCriteria addOrder(Order order) {
criteria.addOrder(order);
return this;
}
public DetachedCriteria createAlias(String associationPath, String alias)
throws HibernateException {
criteria.createAlias(associationPath, alias);
return this;
}
public DetachedCriteria createCriteria(String associationPath, String alias)
throws HibernateException {
return new DetachedCriteria( impl, criteria.createCriteria(associationPath, alias) );
}
public DetachedCriteria createCriteria(String associationPath)
throws HibernateException {
return new DetachedCriteria( impl, criteria.createCriteria(associationPath) );
}
/**
* Obtain the alias associated with this DetachedCriteria
*
* @return The alias
*/
public String getAlias() {
return criteria.getAlias();
}
public DetachedCriteria setFetchMode(String associationPath, FetchMode mode)
throws HibernateException {
criteria.setFetchMode(associationPath, mode);
return this;
}
public DetachedCriteria setProjection(Projection projection) {
criteria.setProjection(projection);
return this;
}
public DetachedCriteria setResultTransformer(ResultTransformer resultTransformer) {
criteria.setResultTransformer(resultTransformer);
return this;
}
public String toString() {
return "DetachableCriteria(" + criteria.toString() + ')';
}
/**
* Retrieve the CriteriaImpl used internally to hold the DetachedCriteria state
*
* @return The internally maintained CriteriaImpl
*/
CriteriaImpl getCriteriaImpl() {
return impl;
}
public DetachedCriteria createAlias(String associationPath, String alias, JoinType joinType) throws HibernateException {
criteria.createAlias(associationPath, alias, joinType);
return this;
}
public DetachedCriteria createAlias(String associationPath, String alias, JoinType joinType, Criterion withClause) throws HibernateException {
criteria.createAlias(associationPath, alias, joinType, withClause);
return this;
}
public DetachedCriteria createCriteria(String associationPath, JoinType joinType) throws HibernateException {
return new DetachedCriteria(impl, criteria.createCriteria(associationPath, joinType));
}
public DetachedCriteria createCriteria(String associationPath, String alias, JoinType joinType) throws HibernateException {
return new DetachedCriteria(impl, criteria.createCriteria(associationPath, alias, joinType));
}
public DetachedCriteria createCriteria(String associationPath, String alias, JoinType joinType, Criterion withClause) throws HibernateException {
return new DetachedCriteria(impl, criteria.createCriteria(associationPath, alias, joinType, withClause));
/**
* Static builder to create a DetachedCriteria for the given entity.
*
* @param entityName The name of the entity to create a DetachedCriteria for
*
* @return The DetachedCriteria
*/
@SuppressWarnings("UnusedDeclaration")
public static DetachedCriteria forEntityName(String entityName) {
return new DetachedCriteria( entityName );
}
/**
* Static builder to create a DetachedCriteria for the given entity.
*
* @param entityName The name of the entity to create a DetachedCriteria for
* @param alias The alias to apply to the entity
*
* @return The DetachedCriteria
*/
@SuppressWarnings("UnusedDeclaration")
public static DetachedCriteria forEntityName(String entityName, String alias) {
return new DetachedCriteria( entityName, alias );
}
/**
* Static builder to create a DetachedCriteria for the given entity, by its Class.
*
* @param clazz The entity class
*
* @return The DetachedCriteria
*/
public static DetachedCriteria forClass(Class clazz) {
return new DetachedCriteria( clazz.getName() );
}
/**
* Static builder to create a DetachedCriteria for the given entity, by its Class.
*
* @param clazz The entity class
* @param alias The alias to apply to the entity
*
* @return The DetachedCriteria
*/
public static DetachedCriteria forClass(Class clazz, String alias) {
return new DetachedCriteria( clazz.getName() , alias );
}
/**
* Add a restriction
*
* @param criterion The restriction
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria add(Criterion criterion) {
criteria.add( criterion );
return this;
}
/**
* Adds an ordering
*
* @param order The ordering
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria addOrder(Order order) {
criteria.addOrder( order );
return this;
}
/**
* Set the fetch mode for a given association
*
* @param associationPath The association path
* @param mode The fetch mode to apply
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria setFetchMode(String associationPath, FetchMode mode) {
criteria.setFetchMode( associationPath, mode );
return this;
}
/**
* Set the projection to use.
*
* @param projection The projection to use
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria setProjection(Projection projection) {
criteria.setProjection( projection );
return this;
}
/**
* Set the result transformer to use.
*
* @param resultTransformer The result transformer to use
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria setResultTransformer(ResultTransformer resultTransformer) {
criteria.setResultTransformer( resultTransformer );
return this;
}
/**
* Creates an association path alias within this DetachedCriteria. The alias can then be used in further
* alias creations or restrictions, etc.
*
* @param associationPath The association path
* @param alias The alias to apply to that association path
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria createAlias(String associationPath, String alias) {
criteria.createAlias( associationPath, alias );
return this;
}
/**
* Creates an association path alias within this DetachedCriteria specifying the type of join. The alias
* can then be used in further alias creations or restrictions, etc.
*
* @param associationPath The association path
* @param alias The alias to apply to that association path
* @param joinType The type of join to use
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria createAlias(String associationPath, String alias, JoinType joinType) {
criteria.createAlias( associationPath, alias, joinType );
return this;
}
/**
* Creates an association path alias within this DetachedCriteria specifying the type of join. The alias
* can then be used in further alias creations or restrictions, etc.
*
* @param associationPath The association path
* @param alias The alias to apply to that association path
* @param joinType The type of join to use
* @param withClause An additional restriction on the join
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria createAlias(String associationPath, String alias, JoinType joinType, Criterion withClause) {
criteria.createAlias( associationPath, alias, joinType, withClause );
return this;
}
/**
* Deprecated!
*
* @param associationPath The association path
* @param alias The alias to apply to that association path
* @param joinType The type of join to use
*
* @return {@code this}, for method chaining
*
* @deprecated use {@link #createAlias(String, String, JoinType)}
*/
@Deprecated
public DetachedCriteria createAlias(String associationPath, String alias, int joinType) throws HibernateException {
public DetachedCriteria createAlias(String associationPath, String alias, int joinType) {
return createAlias( associationPath, alias, JoinType.parse( joinType ) );
}
/**
* Deprecated!
*
* @param associationPath The association path
* @param alias The alias to apply to that association path
* @param joinType The type of join to use
* @param withClause An additional restriction on the join
*
* @return {@code this}, for method chaining
*
* @deprecated use {@link #createAlias(String, String, JoinType, Criterion)}
*/
@Deprecated
public DetachedCriteria createAlias(String associationPath, String alias, int joinType, Criterion withClause) throws HibernateException {
public DetachedCriteria createAlias(String associationPath, String alias, int joinType, Criterion withClause) {
return createAlias( associationPath, alias, JoinType.parse( joinType ), withClause );
}
/**
* Creates an nested DetachedCriteria representing the association path.
*
* @param associationPath The association path
* @param alias The alias to apply to that association path
*
* @return the newly created, nested DetachedCriteria
*/
public DetachedCriteria createCriteria(String associationPath, String alias) {
return new DetachedCriteria( impl, criteria.createCriteria( associationPath, alias ) );
}
/**
* Creates an nested DetachedCriteria representing the association path.
*
* @param associationPath The association path
*
* @return the newly created, nested DetachedCriteria
*/
public DetachedCriteria createCriteria(String associationPath) {
return new DetachedCriteria( impl, criteria.createCriteria( associationPath ) );
}
/**
* Creates an nested DetachedCriteria representing the association path, specifying the type of join to use.
*
* @param associationPath The association path
* @param joinType The type of join to use
*
* @return the newly created, nested DetachedCriteria
*/
public DetachedCriteria createCriteria(String associationPath, JoinType joinType) {
return new DetachedCriteria( impl, criteria.createCriteria( associationPath, joinType ) );
}
/**
* Creates an nested DetachedCriteria representing the association path, specifying the type of join to use.
*
* @param associationPath The association path
* @param alias The alias to associate with this "join".
* @param joinType The type of join to use
*
* @return the newly created, nested DetachedCriteria
*/
public DetachedCriteria createCriteria(String associationPath, String alias, JoinType joinType) {
return new DetachedCriteria( impl, criteria.createCriteria( associationPath, alias, joinType ) );
}
/**
* Creates an nested DetachedCriteria representing the association path, specifying the type of join to use and
* an additional join restriction.
*
* @param associationPath The association path
* @param alias The alias to associate with this "join".
* @param joinType The type of join to use
* @param withClause The additional join restriction
*
* @return the newly created, nested DetachedCriteria
*/
public DetachedCriteria createCriteria(String associationPath, String alias, JoinType joinType, Criterion withClause) {
return new DetachedCriteria(impl, criteria.createCriteria( associationPath, alias, joinType, withClause ) );
}
/**
* Deprecated!
*
* @param associationPath The association path
* @param joinType The type of join to use
*
* @return the newly created, nested DetachedCriteria
*
* @deprecated use {@link #createCriteria(String, JoinType)}
*/
@Deprecated
public DetachedCriteria createCriteria(String associationPath, int joinType) throws HibernateException {
public DetachedCriteria createCriteria(String associationPath, int joinType) {
return createCriteria( associationPath, JoinType.parse( joinType ) );
}
/**
* Deprecated!
*
* @param associationPath The association path
* @param alias The alias
* @param joinType The type of join to use
*
* @return the newly created, nested DetachedCriteria
*
* @deprecated use {@link #createCriteria(String, String, JoinType)}
*/
@Deprecated
public DetachedCriteria createCriteria(String associationPath, String alias, int joinType) throws HibernateException {
public DetachedCriteria createCriteria(String associationPath, String alias, int joinType) {
return createCriteria( associationPath, alias, JoinType.parse( joinType ) );
}
/**
* Deprecated!
*
* @param associationPath The association path
* @param alias The alias to associate with this "join".
* @param joinType The type of join to use
* @param withClause The additional join restriction
*
* @return the newly created, nested DetachedCriteria
*
* @deprecated use {@link #createCriteria(String, String, JoinType, Criterion)}
*/
@Deprecated
public DetachedCriteria createCriteria(String associationPath, String alias, int joinType, Criterion withClause) throws HibernateException {
public DetachedCriteria createCriteria(String associationPath, String alias, int joinType, Criterion withClause) {
return createCriteria( associationPath, alias, JoinType.parse( joinType ), withClause );
}
/**
* Set the SQL comment to use.
*
* @param comment The SQL comment to use
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria setComment(String comment) {
criteria.setComment(comment);
criteria.setComment( comment );
return this;
}
/**
* Set the lock mode to use.
*
* @param lockMode The lock mode to use
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria setLockMode(LockMode lockMode) {
criteria.setLockMode(lockMode);
criteria.setLockMode( lockMode );
return this;
}
/**
* Set an alias-specific lock mode. The specified lock mode applies only to that alias.
*
* @param alias The alias to apply the lock to
* @param lockMode The lock mode to use.
*
* @return {@code this}, for method chaining
*/
public DetachedCriteria setLockMode(String alias, LockMode lockMode) {
criteria.setLockMode(alias, lockMode);
criteria.setLockMode( alias, lockMode );
return this;
}
@Override
public String toString() {
return "DetachableCriteria(" + criteria.toString() + ')';
}
}

View File

@ -24,10 +24,22 @@
package org.hibernate.criterion;
/**
* Defines a disjunction (OR series).
*
* @author Gavin King
* @author Steve Ebersole
*
* @see Conjunction
*/
public class Disjunction extends Junction {
/**
* Constructs a Disjunction
*/
protected Disjunction() {
super( Nature.OR );
}
protected Disjunction(Criterion[] conditions) {
super( Nature.OR, conditions );
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,73 +20,85 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.type.Type;
/**
* A wrappedProjection that is a wrapper around other projections to apply distinction.
*
* @author Gavin King
*/
public class Distinct implements EnhancedProjection {
private final Projection wrappedProjection;
private final Projection projection;
public Distinct(Projection proj) {
this.projection = proj;
/**
* Constructs a Distinct
*
* @param wrappedProjection The wrapped projection
*/
public Distinct(Projection wrappedProjection) {
this.wrappedProjection = wrappedProjection;
}
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery)
throws HibernateException {
return "distinct " + projection.toSqlString(criteria, position, criteriaQuery);
@Override
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) {
return "distinct " + wrappedProjection.toSqlString( criteria, position, criteriaQuery );
}
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return projection.toGroupSqlString(criteria, criteriaQuery);
@Override
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
return wrappedProjection.toGroupSqlString( criteria, criteriaQuery );
}
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return projection.getTypes(criteria, criteriaQuery);
@Override
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) {
return wrappedProjection.getTypes( criteria, criteriaQuery );
}
public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return projection.getTypes(alias, criteria, criteriaQuery);
@Override
public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery) {
return wrappedProjection.getTypes( alias, criteria, criteriaQuery );
}
@Override
public String[] getColumnAliases(int loc) {
return projection.getColumnAliases(loc);
return wrappedProjection.getColumnAliases( loc );
}
@Override
public String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
return projection instanceof EnhancedProjection ?
( ( EnhancedProjection ) projection ).getColumnAliases( loc, criteria, criteriaQuery ) :
getColumnAliases( loc );
return wrappedProjection instanceof EnhancedProjection
? ( (EnhancedProjection) wrappedProjection).getColumnAliases( loc, criteria, criteriaQuery )
: getColumnAliases( loc );
}
@Override
public String[] getColumnAliases(String alias, int loc) {
return projection.getColumnAliases(alias, loc);
return wrappedProjection.getColumnAliases( alias, loc );
}
@Override
public String[] getColumnAliases(String alias, int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
return projection instanceof EnhancedProjection ?
( ( EnhancedProjection ) projection ).getColumnAliases( alias, loc, criteria, criteriaQuery ) :
getColumnAliases( alias, loc );
return wrappedProjection instanceof EnhancedProjection
? ( (EnhancedProjection) wrappedProjection).getColumnAliases( alias, loc, criteria, criteriaQuery )
: getColumnAliases( alias, loc );
}
@Override
public String[] getAliases() {
return projection.getAliases();
return wrappedProjection.getAliases();
}
@Override
public boolean isGrouped() {
return projection.isGrouped();
return wrappedProjection.isGrouped();
}
@Override
public String toString() {
return "distinct " + projection.toString();
return "distinct " + wrappedProjection.toString();
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,22 +20,28 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
/**
* An expression asserting that a collection property is empty
*
* @author Gavin King
*/
public class EmptyExpression extends AbstractEmptinessExpression implements Criterion {
/**
* Constructs an EmptyExpression
*
* @param propertyName The collection property name
*
* @see Restrictions#isEmpty
*/
protected EmptyExpression(String propertyName) {
super( propertyName );
}
@Override
protected boolean excludeEmpty() {
return false;
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
/**

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.criterion;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
@ -30,7 +31,6 @@ import java.util.Set;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.persister.entity.EntityPersister;
@ -39,6 +39,7 @@ import org.hibernate.type.Type;
/**
* Support for query by example.
*
* <pre>
* List results = session.createCriteria(Parent.class)
* .add( Example.create(parent).ignoreCase() )
@ -46,68 +47,57 @@ import org.hibernate.type.Type;
* .add( Example.create( parent.getChild() ) )
* .list();
* </pre>
* "Examples" may be mixed and matched with "Expressions" in the same <tt>Criteria</tt>.
*
* "Examples" may be mixed and matched with "Expressions" in the same Criteria.
*
* @see org.hibernate.Criteria
* @author Gavin King
*/
public class Example implements Criterion {
private final Object entity;
private final Set excludedProperties = new HashSet();
private final Object exampleEntity;
private PropertySelector selector;
private boolean isLikeEnabled;
private Character escapeCharacter;
private boolean isIgnoreCaseEnabled;
private MatchMode matchMode;
private final Set<String> excludedProperties = new HashSet<String>();
/**
* A strategy for choosing property values for inclusion in the query
* criteria
* Create a new Example criterion instance, which includes all non-null properties by default
*
* @param exampleEntity The example bean to use.
*
* @return a new instance of Example
*/
public static interface PropertySelector extends Serializable {
public boolean include(Object propertyValue, String propertyName, Type type);
}
private static final PropertySelector NOT_NULL = new NotNullPropertySelector();
private static final PropertySelector ALL = new AllPropertySelector();
private static final PropertySelector NOT_NULL_OR_ZERO = new NotNullOrZeroPropertySelector();
static final class AllPropertySelector implements PropertySelector {
public boolean include(Object object, String propertyName, Type type) {
return true;
}
private Object readResolve() {
return ALL;
}
}
static final class NotNullPropertySelector implements PropertySelector {
public boolean include(Object object, String propertyName, Type type) {
return object!=null;
}
private Object readResolve() {
return NOT_NULL;
}
}
static final class NotNullOrZeroPropertySelector implements PropertySelector {
public boolean include(Object object, String propertyName, Type type) {
return object!=null && (
!(object instanceof Number) || ( (Number) object ).longValue()!=0
);
}
private Object readResolve() {
return NOT_NULL_OR_ZERO;
public static Example create(Object exampleEntity) {
if ( exampleEntity == null ) {
throw new NullPointerException( "null example entity" );
}
return new Example( exampleEntity, NotNullPropertySelector.INSTANCE );
}
/**
* Set escape character for "like" clause
* Allow subclasses to instantiate as needed.
*
* @param exampleEntity The example bean
* @param selector The property selector to use
*/
protected Example(Object exampleEntity, PropertySelector selector) {
this.exampleEntity = exampleEntity;
this.selector = selector;
}
/**
* Set escape character for "like" clause if like matching was enabled
*
* @param escapeCharacter The escape character
*
* @return {@code this}, for method chaining
*
* @see #enableLike
*/
public Example setEscapeCharacter(Character escapeCharacter) {
this.escapeCharacter = escapeCharacter;
@ -115,7 +105,47 @@ public class Example implements Criterion {
}
/**
* Set the property selector
* Use the "like" operator for all string-valued properties. This form implicitly uses {@link MatchMode#EXACT}
*
* @return {@code this}, for method chaining
*/
public Example enableLike() {
return enableLike( MatchMode.EXACT );
}
/**
* Use the "like" operator for all string-valued properties
*
* @param matchMode The match mode to use.
*
* @return {@code this}, for method chaining
*/
public Example enableLike(MatchMode matchMode) {
this.isLikeEnabled = true;
this.matchMode = matchMode;
return this;
}
/**
* Ignore case for all string-valued properties
*
* @return {@code this}, for method chaining
*/
public Example ignoreCase() {
this.isIgnoreCaseEnabled = true;
return this;
}
/**
* Set the property selector to use.
*
* The property selector operates separate from excluding a property.
*
* @param selector The selector to use
*
* @return {@code this}, for method chaining
*
* @see #excludeProperty
*/
public Example setPropertySelector(PropertySelector selector) {
this.selector = selector;
@ -123,95 +153,63 @@ public class Example implements Criterion {
}
/**
* Exclude zero-valued properties
* Exclude zero-valued properties.
*
* Equivalent to calling {@link #setPropertySelector} passing in {@link NotNullOrZeroPropertySelector#INSTANCE}
*
* @return {@code this}, for method chaining
*
* @see #setPropertySelector
*/
public Example excludeZeroes() {
setPropertySelector(NOT_NULL_OR_ZERO);
setPropertySelector( NotNullOrZeroPropertySelector.INSTANCE );
return this;
}
/**
* Don't exclude null or zero-valued properties
* Include all properties.
*
* Equivalent to calling {@link #setPropertySelector} passing in {@link AllPropertySelector#INSTANCE}
*
* @return {@code this}, for method chaining
*
* @see #setPropertySelector
*/
public Example excludeNone() {
setPropertySelector(ALL);
setPropertySelector( AllPropertySelector.INSTANCE );
return this;
}
/**
* Use the "like" operator for all string-valued properties
*/
public Example enableLike(MatchMode matchMode) {
isLikeEnabled = true;
this.matchMode = matchMode;
return this;
}
/**
* Use the "like" operator for all string-valued properties
*/
public Example enableLike() {
return enableLike(MatchMode.EXACT);
}
/**
* Ignore case for all string-valued properties
*/
public Example ignoreCase() {
isIgnoreCaseEnabled = true;
return this;
}
/**
* Exclude a particular named property
* Exclude a particular property by name.
*
* @param name The name of the property to exclude
*
* @return {@code this}, for method chaining
*
* @see #setPropertySelector
*/
public Example excludeProperty(String name) {
excludedProperties.add(name);
excludedProperties.add( name );
return this;
}
/**
* Create a new instance, which includes all non-null properties
* by default
* @param entity
* @return a new instance of <tt>Example</tt>
*/
public static Example create(Object entity) {
if (entity==null) throw new NullPointerException("null example");
return new Example(entity, NOT_NULL);
}
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
final StringBuilder buf = new StringBuilder().append( '(' );
final EntityPersister meta = criteriaQuery.getFactory().getEntityPersister(
criteriaQuery.getEntityName( criteria )
);
final String[] propertyNames = meta.getPropertyNames();
final Type[] propertyTypes = meta.getPropertyTypes();
protected Example(Object entity, PropertySelector selector) {
this.entity = entity;
this.selector = selector;
}
final Object[] propertyValues = meta.getPropertyValues( exampleEntity );
for ( int i=0; i<propertyNames.length; i++ ) {
final Object propertyValue = propertyValues[i];
final String propertyName = propertyNames[i];
public String toString() {
return "example (" + entity + ')';
}
private boolean isPropertyIncluded(Object value, String name, Type type) {
return !excludedProperties.contains(name) &&
!type.isAssociationType() &&
selector.include(value, name, type);
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
StringBuilder buf = new StringBuilder().append('(');
EntityPersister meta = criteriaQuery.getFactory().getEntityPersister( criteriaQuery.getEntityName(criteria) );
String[] propertyNames = meta.getPropertyNames();
Type[] propertyTypes = meta.getPropertyTypes();
//TODO: get all properties, not just the fetched ones!
Object[] propertyValues = meta.getPropertyValues( entity );
for (int i=0; i<propertyNames.length; i++) {
Object propertyValue = propertyValues[i];
String propertyName = propertyNames[i];
boolean isPropertyIncluded = i!=meta.getVersionProperty() &&
isPropertyIncluded( propertyValue, propertyName, propertyTypes[i] );
if (isPropertyIncluded) {
final boolean isVersionProperty = i == meta.getVersionProperty();
if ( ! isVersionProperty && isPropertyIncluded( propertyValue, propertyName, propertyTypes[i] ) ) {
if ( propertyTypes[i].isComponentType() ) {
appendComponentCondition(
propertyName,
@ -233,61 +231,72 @@ public class Example implements Criterion {
}
}
}
if ( buf.length()==1 ) buf.append("1=1"); //yuck!
return buf.append(')').toString();
if ( buf.length()==1 ) {
buf.append( "1=1" );
}
private static final Object[] TYPED_VALUES = new TypedValue[0];
return buf.append( ')' ).toString();
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
@SuppressWarnings("SimplifiableIfStatement")
private boolean isPropertyIncluded(Object value, String name, Type type) {
if ( excludedProperties.contains( name ) ) {
// was explicitly excluded
return false;
}
EntityPersister meta = criteriaQuery.getFactory()
.getEntityPersister( criteriaQuery.getEntityName(criteria) );
String[] propertyNames = meta.getPropertyNames();
Type[] propertyTypes = meta.getPropertyTypes();
//TODO: get all properties, not just the fetched ones!
Object[] values = meta.getPropertyValues( entity );
List list = new ArrayList();
for (int i=0; i<propertyNames.length; i++) {
Object value = values[i];
Type type = propertyTypes[i];
String name = propertyNames[i];
if ( type.isAssociationType() ) {
// associations are implicitly excluded
return false;
}
boolean isPropertyIncluded = i!=meta.getVersionProperty() &&
isPropertyIncluded(value, name, type);
return selector.include( value, name, type );
}
if (isPropertyIncluded) {
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) {
final EntityPersister meta = criteriaQuery.getFactory().getEntityPersister(
criteriaQuery.getEntityName( criteria )
);
final String[] propertyNames = meta.getPropertyNames();
final Type[] propertyTypes = meta.getPropertyTypes();
final Object[] values = meta.getPropertyValues( exampleEntity );
final List<TypedValue> list = new ArrayList<TypedValue>();
for ( int i=0; i<propertyNames.length; i++ ) {
final Object value = values[i];
final Type type = propertyTypes[i];
final String name = propertyNames[i];
final boolean isVersionProperty = i == meta.getVersionProperty();
if ( ! isVersionProperty && isPropertyIncluded( value, name, type ) ) {
if ( propertyTypes[i].isComponentType() ) {
addComponentTypedValues(name, value, (CompositeType) type, list, criteria, criteriaQuery);
addComponentTypedValues( name, value, (CompositeType) type, list, criteria, criteriaQuery );
}
else {
addPropertyTypedValue(value, type, list);
addPropertyTypedValue( value, type, list );
}
}
}
return (TypedValue[]) list.toArray(TYPED_VALUES);
}
private EntityMode getEntityMode(Criteria criteria, CriteriaQuery criteriaQuery) {
EntityPersister meta = criteriaQuery.getFactory()
.getEntityPersister( criteriaQuery.getEntityName(criteria) );
EntityMode result = meta.getEntityMode();
if ( ! meta.getEntityMetamodel().getTuplizer().isInstance( entity ) ) {
throw new ClassCastException( entity.getClass().getName() );
}
return result;
return list.toArray( new TypedValue[ list.size() ] );
}
protected void addPropertyTypedValue(Object value, Type type, List list) {
if ( value!=null ) {
protected void addPropertyTypedValue(Object value, Type type, List<TypedValue> list) {
if ( value != null ) {
if ( value instanceof String ) {
String string = (String) value;
if (isIgnoreCaseEnabled) string = string.toLowerCase();
if (isLikeEnabled) string = matchMode.toMatchString(string);
if ( isIgnoreCaseEnabled ) {
string = string.toLowerCase();
}
if ( isLikeEnabled ) {
string = matchMode.toMatchString( string );
}
value = string;
}
list.add( new TypedValue(type, value) );
list.add( new TypedValue( type, value ) );
}
}
@ -295,60 +304,73 @@ public class Example implements Criterion {
String path,
Object component,
CompositeType type,
List list,
List<TypedValue> list,
Criteria criteria,
CriteriaQuery criteriaQuery)
throws HibernateException {
if (component!=null) {
String[] propertyNames = type.getPropertyNames();
Type[] subtypes = type.getSubtypes();
Object[] values = type.getPropertyValues( component, getEntityMode(criteria, criteriaQuery) );
for (int i=0; i<propertyNames.length; i++) {
Object value = values[i];
Type subtype = subtypes[i];
String subpath = StringHelper.qualify( path, propertyNames[i] );
if ( isPropertyIncluded(value, subpath, subtype) ) {
CriteriaQuery criteriaQuery) {
if ( component != null ) {
final String[] propertyNames = type.getPropertyNames();
final Type[] subtypes = type.getSubtypes();
final Object[] values = type.getPropertyValues( component, getEntityMode( criteria, criteriaQuery ) );
for ( int i=0; i<propertyNames.length; i++ ) {
final Object value = values[i];
final Type subtype = subtypes[i];
final String subpath = StringHelper.qualify( path, propertyNames[i] );
if ( isPropertyIncluded( value, subpath, subtype ) ) {
if ( subtype.isComponentType() ) {
addComponentTypedValues(subpath, value, (CompositeType) subtype, list, criteria, criteriaQuery);
addComponentTypedValues( subpath, value, (CompositeType) subtype, list, criteria, criteriaQuery );
}
else {
addPropertyTypedValue(value, subtype, list);
addPropertyTypedValue( value, subtype, list );
}
}
}
}
}
private EntityMode getEntityMode(Criteria criteria, CriteriaQuery criteriaQuery) {
final EntityPersister meta = criteriaQuery.getFactory().getEntityPersister(
criteriaQuery.getEntityName( criteria )
);
final EntityMode result = meta.getEntityMode();
if ( ! meta.getEntityMetamodel().getTuplizer().isInstance( exampleEntity ) ) {
throw new ClassCastException( exampleEntity.getClass().getName() );
}
return result;
}
protected void appendPropertyCondition(
String propertyName,
Object propertyValue,
Criteria criteria,
CriteriaQuery cq,
StringBuilder buf)
throws HibernateException {
Criterion crit;
if ( propertyValue!=null ) {
boolean isString = propertyValue instanceof String;
StringBuilder buf) {
final Criterion condition;
if ( propertyValue != null ) {
final boolean isString = propertyValue instanceof String;
if ( isLikeEnabled && isString ) {
crit = new LikeExpression(
condition = new LikeExpression(
propertyName,
( String ) propertyValue,
(String) propertyValue,
matchMode,
escapeCharacter,
isIgnoreCaseEnabled
);
}
else {
crit = new SimpleExpression( propertyName, propertyValue, "=", isIgnoreCaseEnabled && isString );
condition = new SimpleExpression( propertyName, propertyValue, "=", isIgnoreCaseEnabled && isString );
}
}
else {
crit = new NullExpression(propertyName);
condition = new NullExpression(propertyName);
}
final String conditionFragment = condition.toSqlString( criteria, cq );
if ( conditionFragment.trim().length() > 0 ) {
if ( buf.length() > 1 ) {
buf.append( " and " );
}
buf.append( conditionFragment );
}
String critCondition = crit.toSqlString(criteria, cq);
if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
buf.append(critCondition);
}
protected void appendComponentCondition(
@ -357,21 +379,19 @@ public class Example implements Criterion {
CompositeType type,
Criteria criteria,
CriteriaQuery criteriaQuery,
StringBuilder buf)
throws HibernateException {
if (component!=null) {
String[] propertyNames = type.getPropertyNames();
Object[] values = type.getPropertyValues( component, getEntityMode(criteria, criteriaQuery) );
Type[] subtypes = type.getSubtypes();
for (int i=0; i<propertyNames.length; i++) {
String subpath = StringHelper.qualify( path, propertyNames[i] );
Object value = values[i];
if ( isPropertyIncluded( value, subpath, subtypes[i] ) ) {
Type subtype = subtypes[i];
StringBuilder buf) {
if ( component != null ) {
final String[] propertyNames = type.getPropertyNames();
final Object[] values = type.getPropertyValues( component, getEntityMode( criteria, criteriaQuery ) );
final Type[] subtypes = type.getSubtypes();
for ( int i=0; i<propertyNames.length; i++ ) {
final String subPath = StringHelper.qualify( path, propertyNames[i] );
final Object value = values[i];
if ( isPropertyIncluded( value, subPath, subtypes[i] ) ) {
final Type subtype = subtypes[i];
if ( subtype.isComponentType() ) {
appendComponentCondition(
subpath,
subPath,
value,
(CompositeType) subtype,
criteria,
@ -381,7 +401,7 @@ public class Example implements Criterion {
}
else {
appendPropertyCondition(
subpath,
subPath,
value,
criteria,
criteriaQuery,
@ -392,4 +412,89 @@ public class Example implements Criterion {
}
}
}
@Override
public String toString() {
return "example (" + exampleEntity + ')';
}
// PropertySelector definitions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* A strategy for choosing property values for inclusion in the query criteria. Note that
* property selection (for inclusion) operates separately from excluding a property. Excluded
* properties are not even passed in to the PropertySelector for consideration.
*/
public static interface PropertySelector extends Serializable {
/**
* Determine whether the given property should be used in the criteria.
*
* @param propertyValue The property value (from the example bean)
* @param propertyName The name of the property
* @param type The type of the property
*
* @return {@code true} indicates the property should be included; {@code false} indiates it should not.
*/
public boolean include(Object propertyValue, String propertyName, Type type);
}
/**
* Property selector that includes all properties
*/
public static final class AllPropertySelector implements PropertySelector {
/**
* Singleton access
*/
public static final AllPropertySelector INSTANCE = new AllPropertySelector();
@Override
public boolean include(Object object, String propertyName, Type type) {
return true;
}
private Object readResolve() {
return INSTANCE;
}
}
/**
* Property selector that includes only properties that are not {@code null}
*/
public static final class NotNullPropertySelector implements PropertySelector {
/**
* Singleton access
*/
public static final NotNullPropertySelector INSTANCE = new NotNullPropertySelector();
@Override
public boolean include(Object object, String propertyName, Type type) {
return object!=null;
}
private Object readResolve() {
return INSTANCE;
}
}
/**
* Property selector that includes only properties that are not {@code null} and non-zero (if numeric)
*/
public static final class NotNullOrZeroPropertySelector implements PropertySelector {
/**
* Singleton access
*/
public static final NotNullOrZeroPropertySelector INSTANCE = new NotNullOrZeroPropertySelector();
@Override
public boolean include(Object object, String propertyName, Type type) {
return object != null
&& ( !(object instanceof Number) || ( (Number) object ).longValue()!=0
);
}
private Object readResolve() {
return INSTANCE;
}
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,21 +20,32 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
/**
* Expression that checks the existence of rows in a sub-query
*
* @author Gavin King
*/
public class ExistsSubqueryExpression extends SubqueryExpression {
/**
* Constructs the ExistsSubqueryExpression
*
* @param quantifier The "exists"/"not exists" sub-query quantifier
* @param dc The DetachedCriteria representing the sub-query
*
* @see Subqueries#exists
* @see Subqueries#notExists
*/
protected ExistsSubqueryExpression(String quantifier, DetachedCriteria dc) {
super( null, quantifier, dc );
}
@Override
protected String toLeftSqlString(Criteria criteria, CriteriaQuery outerQuery) {
return "";
}
protected ExistsSubqueryExpression(String quantifier, DetachedCriteria dc) {
super(null, quantifier, dc);
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,66 +20,72 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.type.Type;
/**
* @deprecated Use <tt>Restrictions</tt>.
* @see Restrictions
* Factory for Criterion objects. Deprecated!
*
* @author Gavin King
*
* @see Restrictions
*
* @deprecated Use {@link Restrictions} instead
*/
@Deprecated
public final class Expression extends Restrictions {
/**
* Apply a constraint expressed in SQL, with JDBC parameters. Any occurrences of <tt>{alias}</tt> will be
* replaced by the table alias.
*
* @param sql The sql
* @param values The parameter values
* @param types The parameter types
*
* @return Criterion
*
* @deprecated use {@link org.hibernate.criterion.Restrictions#sqlRestriction(String, Object[], Type[])}
*/
@Deprecated
public static Criterion sql(String sql, Object[] values, Type[] types) {
return new SQLCriterion( sql, values, types );
}
/**
* Apply a constraint expressed in SQL, with a JDBC parameter. Any occurrences of <tt>{alias}</tt> will be
* replaced by the table alias.
*
* @param sql The sql
* @param value The parameter value
* @param type The parameter type
*
* @return Criterion
*
* @deprecated use {@link org.hibernate.criterion.Restrictions#sqlRestriction(String, Object, Type)}
*/
@Deprecated
public static Criterion sql(String sql, Object value, Type type) {
return new SQLCriterion( sql, value, type );
}
/**
* Apply a constraint expressed in SQL with no parameters. Any occurrences of <tt>{alias}</tt> will be
* replaced by the table alias.
*
* @param sql The sql
*
* @return Criterion
*
* @deprecated use {@link org.hibernate.criterion.Restrictions#sqlRestriction(String)}
*/
@Deprecated
public static Criterion sql(String sql) {
return new SQLCriterion( sql );
}
private Expression() {
//cannot be instantiated
}
/**
* Apply a constraint expressed in SQL, with the given JDBC
* parameters. Any occurrences of <tt>{alias}</tt> will be
* replaced by the table alias.
*
* @deprecated use {@link org.hibernate.criterion.Restrictions#sqlRestriction(String, Object[], Type[])}
* @param sql
* @param values
* @param types
* @return Criterion
*/
@Deprecated
public static Criterion sql(String sql, Object[] values, Type[] types) {
return new SQLCriterion(sql, values, types);
}
/**
* Apply a constraint expressed in SQL, with the given JDBC
* parameter. Any occurrences of <tt>{alias}</tt> will be replaced
* by the table alias.
*
* @deprecated use {@link org.hibernate.criterion.Restrictions#sqlRestriction(String, Object, Type)}
* @param sql
* @param value
* @param type
* @return Criterion
*/
@Deprecated
public static Criterion sql(String sql, Object value, Type type) {
return new SQLCriterion(sql, new Object[] { value }, new Type[] { type } );
}
/**
* Apply a constraint expressed in SQL. Any occurrences of <tt>{alias}</tt>
* will be replaced by the table alias.
*
* @deprecated use {@link org.hibernate.criterion.Restrictions#sqlRestriction(String)}
* @param sql
* @return Criterion
*/
@Deprecated
public static Criterion sql(String sql) {
return new SQLCriterion(sql, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY);
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,46 +20,49 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.util.StringHelper;
/**
* An identifier constraint
*
* @author Gavin King
*/
public class IdentifierEqExpression implements Criterion {
private final Object value;
/**
* Constructs an IdentifierEqExpression
*
* @param value The identifier value
*
* @see Restrictions#idEq
*/
protected IdentifierEqExpression(Object value) {
this.value = value;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
final String[] columns = criteriaQuery.getIdentifierColumns( criteria );
String[] columns = criteriaQuery.getIdentifierColumns(criteria);
String result = StringHelper.join(
" and ",
StringHelper.suffix( columns, " = ?" )
);
if (columns.length>1) result = '(' + result + ')';
String result = StringHelper.join( " and ", StringHelper.suffix( columns, " = ?" ) );
if ( columns.length > 1) {
result = '(' + result + ')';
}
return result;
//TODO: get SQL rendering out of this package!
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return new TypedValue[] { criteriaQuery.getTypedIdentifierValue(criteria, value) };
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) {
return new TypedValue[] { criteriaQuery.getTypedIdentifierValue( criteria, value ) };
}
@Override
public String toString() {
return "id = " + value;
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,66 +20,77 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.type.Type;
/**
* A property value, or grouped property value
*
* @author Gavin King
*/
public class IdentifierProjection extends SimpleProjection {
private boolean grouped;
protected IdentifierProjection(boolean grouped) {
/**
* Constructs a non-grouped identifier projection
*
* @see Projections#id
*/
protected IdentifierProjection() {
this( false );
}
/**
*
* Not used externally
*/
private IdentifierProjection(boolean grouped) {
this.grouped = grouped;
}
protected IdentifierProjection() {
this(false);
@Override
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) {
return new Type[] { criteriaQuery.getIdentifierType( criteria ) };
}
public String toString() {
return "id";
}
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return new Type[] { criteriaQuery.getIdentifierType(criteria) };
}
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery)
throws HibernateException {
StringBuilder buf = new StringBuilder();
String[] cols = criteriaQuery.getIdentifierColumns(criteria);
@Override
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) {
final StringBuilder buf = new StringBuilder();
final String[] cols = criteriaQuery.getIdentifierColumns( criteria );
for ( int i=0; i<cols.length; i++ ) {
buf.append( cols[i] )
.append(" as y")
.append(position + i)
.append('_');
if (i < cols.length -1)
buf.append(", ");
.append( " as y" )
.append( position + i )
.append( '_' );
if ( i < cols.length -1 ) {
buf.append( ", " );
}
}
return buf.toString();
}
@Override
public boolean isGrouped() {
return grouped;
}
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
if (!grouped) {
return super.toGroupSqlString(criteria, criteriaQuery);
@Override
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
if ( !grouped ) {
return super.toGroupSqlString( criteria, criteriaQuery );
}
else {
return StringHelper.join( ", ", criteriaQuery.getIdentifierColumns(criteria) );
return StringHelper.join( ", ", criteriaQuery.getIdentifierColumns( criteria ) );
}
}
@Override
public String toString() {
return "id";
}
}

View File

@ -31,13 +31,15 @@ import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.engine.spi.TypedValue;
/**
* A case-insensitive "like"
* A case-insensitive "like".
*
* @author Gavin King
*
* @deprecated Prefer {@link LikeExpression} which now has case-insensitivity capability.
*/
@Deprecated
@SuppressWarnings({"deprecation", "UnusedDeclaration"})
public class IlikeExpression implements Criterion {
private final String propertyName;
private final Object value;
@ -50,10 +52,10 @@ public class IlikeExpression implements Criterion {
this( propertyName, matchMode.toMatchString( value ) );
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
Dialect dialect = criteriaQuery.getFactory().getDialect();
String[] columns = criteriaQuery.findColumns( propertyName, criteria );
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
final Dialect dialect = criteriaQuery.getFactory().getDialect();
final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
if ( columns.length != 1 ) {
throw new HibernateException( "ilike may only be used with single-column properties" );
}
@ -63,12 +65,10 @@ public class IlikeExpression implements Criterion {
else {
return dialect.getLowercaseFunction() + '(' + columns[0] + ") like ?";
}
//TODO: get SQL rendering out of this package!
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) {
return new TypedValue[] {
criteriaQuery.getTypedValue(
criteria,
@ -78,6 +78,7 @@ public class IlikeExpression implements Criterion {
};
}
@Override
public String toString() {
return propertyName + " ilike " + value;
}

View File

@ -22,11 +22,11 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.criterion;
import java.util.ArrayList;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.type.CompositeType;
@ -34,72 +34,82 @@ import org.hibernate.type.Type;
/**
* Constrains the property to a specified list of values
*
* @author Gavin King
*/
public class InExpression implements Criterion {
private final String propertyName;
private final Object[] values;
/**
* Constructs an InExpression
*
* @param propertyName The property name to check
* @param values The values to check against
*
* @see Restrictions#in(String, java.util.Collection)
* @see Restrictions#in(String, Object[])
*/
protected InExpression(String propertyName, Object[] values) {
this.propertyName = propertyName;
this.values = values;
}
public String toSqlString( Criteria criteria, CriteriaQuery criteriaQuery )
throws HibernateException {
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
if ( criteriaQuery.getFactory().getDialect()
.supportsRowValueConstructorSyntaxInInList() || columns.length<=1) {
String singleValueParam = StringHelper.repeat( "?, ",
columns.length - 1 )
+ "?";
if ( columns.length > 1 )
@Override
public String toSqlString( Criteria criteria, CriteriaQuery criteriaQuery ) {
final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
if ( criteriaQuery.getFactory().getDialect().supportsRowValueConstructorSyntaxInInList() || columns.length <= 1 ) {
String singleValueParam = StringHelper.repeat( "?, ", columns.length - 1 ) + "?";
if ( columns.length > 1 ) {
singleValueParam = '(' + singleValueParam + ')';
String params = values.length > 0 ? StringHelper.repeat(
singleValueParam + ", ", values.length - 1 )
+ singleValueParam : "";
}
final String params = values.length > 0
? StringHelper.repeat( singleValueParam + ", ", values.length - 1 ) + singleValueParam
: "";
String cols = StringHelper.join( ", ", columns );
if ( columns.length > 1 )
if ( columns.length > 1 ) {
cols = '(' + cols + ')';
}
return cols + " in (" + params + ')';
} else {
}
else {
String cols = " ( " + StringHelper.join( " = ? and ", columns ) + "= ? ) ";
cols = values.length > 0 ? StringHelper.repeat( cols
+ "or ", values.length - 1 )
+ cols : "";
cols = values.length > 0
? StringHelper.repeat( cols + "or ", values.length - 1 ) + cols
: "";
cols = " ( " + cols + " ) ";
return cols;
}
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
ArrayList list = new ArrayList();
Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName);
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) {
final ArrayList<TypedValue> list = new ArrayList<TypedValue>();
final Type type = criteriaQuery.getTypeUsingProjection( criteria, propertyName );
if ( type.isComponentType() ) {
CompositeType actype = (CompositeType) type;
Type[] types = actype.getSubtypes();
for ( int j=0; j<values.length; j++ ) {
for ( int i=0; i<types.length; i++ ) {
Object subval = values[j]==null ?
null :
actype.getPropertyValues( values[j], EntityMode.POJO )[i];
list.add( new TypedValue( types[i], subval ) );
final CompositeType compositeType = (CompositeType) type;
final Type[] subTypes = compositeType.getSubtypes();
for ( Object value : values ) {
for ( int i = 0; i < subTypes.length; i++ ) {
final Object subValue = value == null
? null
: compositeType.getPropertyValues( value, EntityMode.POJO )[i];
list.add( new TypedValue( subTypes[i], subValue ) );
}
}
}
else {
for ( int j=0; j<values.length; j++ ) {
list.add( new TypedValue( type, values[j] ) );
for ( Object value : values ) {
list.add( new TypedValue( type, value ) );
}
}
return (TypedValue[]) list.toArray( new TypedValue[ list.size() ] );
}
return list.toArray( new TypedValue[ list.size() ] );
}
@Override
public String toString() {
return propertyName + " in (" + StringHelper.toString(values) + ')';
return propertyName + " in (" + StringHelper.toString( values ) + ')';
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@ -38,6 +38,7 @@ import org.hibernate.internal.util.StringHelper;
* associative logical operator
*
* @author Gavin King
* @author Steve Ebersole
*/
public class Junction implements Criterion {
private final Nature nature;
@ -47,6 +48,18 @@ public class Junction implements Criterion {
this.nature = nature;
}
protected Junction(Nature nature, Criterion... criterion) {
this( nature );
Collections.addAll( conditions, criterion );
}
/**
* Adds a criterion to the junction (and/or)
*
* @param criterion The criterion to add
*
* @return {@code this}, for method chaining
*/
public Junction add(Criterion criterion) {
conditions.add( criterion );
return this;
@ -56,15 +69,20 @@ public class Junction implements Criterion {
return nature;
}
/**
* Access the conditions making up the junction
*
* @return the criterion
*/
public Iterable<Criterion> conditions() {
return conditions;
}
@Override
public TypedValue[] getTypedValues(Criteria crit, CriteriaQuery criteriaQuery) throws HibernateException {
ArrayList<TypedValue> typedValues = new ArrayList<TypedValue>();
final ArrayList<TypedValue> typedValues = new ArrayList<TypedValue>();
for ( Criterion condition : conditions ) {
TypedValue[] subValues = condition.getTypedValues( crit, criteriaQuery );
final TypedValue[] subValues = condition.getTypedValues( crit, criteriaQuery );
Collections.addAll( typedValues, subValues );
}
return typedValues.toArray( new TypedValue[ typedValues.size() ] );
@ -76,15 +94,18 @@ public class Junction implements Criterion {
return "1=1";
}
StringBuilder buffer = new StringBuilder().append( '(' );
Iterator itr = conditions.iterator();
final StringBuilder buffer = new StringBuilder().append( '(' );
final Iterator itr = conditions.iterator();
while ( itr.hasNext() ) {
buffer.append( ( (Criterion) itr.next() ).toSqlString( crit, criteriaQuery ) );
if ( itr.hasNext() ) {
buffer.append(' ').append( nature.getOperator() ).append(' ');
buffer.append( ' ' )
.append( nature.getOperator() )
.append( ' ' );
}
}
return buffer.append(')').toString();
return buffer.append( ')' ).toString();
}
@Override
@ -92,11 +113,24 @@ public class Junction implements Criterion {
return '(' + StringHelper.join( ' ' + nature.getOperator() + ' ', conditions.iterator() ) + ')';
}
/**
* The type of junction
*/
public static enum Nature {
/**
* An AND
*/
AND,
OR
;
/**
* An OR
*/
OR;
/**
* The corresponding SQL operator
*
* @return SQL operator
*/
public String getOperator() {
return name().toLowerCase();
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
@ -51,16 +51,12 @@ public class LikeExpression implements Criterion {
this.ignoreCase = ignoreCase;
}
protected LikeExpression(
String propertyName,
String value) {
protected LikeExpression(String propertyName, String value) {
this( propertyName, value, null, false );
}
protected LikeExpression(
String propertyName,
String value,
MatchMode matchMode) {
@SuppressWarnings("UnusedDeclaration")
protected LikeExpression(String propertyName, String value, MatchMode matchMode) {
this( propertyName, matchMode.toMatchString( value ) );
}
@ -73,16 +69,16 @@ public class LikeExpression implements Criterion {
this( propertyName, matchMode.toMatchString( value ), escapeChar, ignoreCase );
}
public String toSqlString(
Criteria criteria,
CriteriaQuery criteriaQuery) throws HibernateException {
Dialect dialect = criteriaQuery.getFactory().getDialect();
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
@Override
public String toSqlString(Criteria criteria,CriteriaQuery criteriaQuery) {
final Dialect dialect = criteriaQuery.getFactory().getDialect();
final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
if ( columns.length != 1 ) {
throw new HibernateException( "Like may only be used with single-column properties" );
}
String escape = escapeChar == null ? "" : " escape \'" + escapeChar + "\'";
String column = columns[0];
final String escape = escapeChar == null ? "" : " escape \'" + escapeChar + "\'";
final String column = columns[0];
if ( ignoreCase ) {
if ( dialect.supportsCaseInsensitiveLike() ) {
return column +" " + dialect.getCaseInsensitiveLike() + " ?" + escape;
@ -96,11 +92,10 @@ public class LikeExpression implements Criterion {
}
}
public TypedValue[] getTypedValues(
Criteria criteria,
CriteriaQuery criteriaQuery) throws HibernateException {
return new TypedValue[] {
criteriaQuery.getTypedValue( criteria, propertyName, ignoreCase ? value.toString().toLowerCase() : value.toString() )
};
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) {
final String matchValue = ignoreCase ? value.toString().toLowerCase() : value.toString();
return new TypedValue[] { criteriaQuery.getTypedValue( criteria, propertyName, matchValue ) };
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,19 +20,18 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.TypedValue;
/**
* Superclass of binary logical expressions
*
* @author Gavin King
*/
public class LogicalExpression implements Criterion {
private final Criterion lhs;
private final Criterion rhs;
private final String op;
@ -43,33 +42,33 @@ public class LogicalExpression implements Criterion {
this.op = op;
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) {
final TypedValue[] lhsTypedValues = lhs.getTypedValues( criteria, criteriaQuery );
final TypedValue[] rhsTypedValues = rhs.getTypedValues( criteria, criteriaQuery );
TypedValue[] lhstv = lhs.getTypedValues(criteria, criteriaQuery);
TypedValue[] rhstv = rhs.getTypedValues(criteria, criteriaQuery);
TypedValue[] result = new TypedValue[ lhstv.length + rhstv.length ];
System.arraycopy(lhstv, 0, result, 0, lhstv.length);
System.arraycopy(rhstv, 0, result, lhstv.length, rhstv.length);
final TypedValue[] result = new TypedValue[ lhsTypedValues.length + rhsTypedValues.length ];
System.arraycopy( lhsTypedValues, 0, result, 0, lhsTypedValues.length );
System.arraycopy( rhsTypedValues, 0, result, lhsTypedValues.length, rhsTypedValues.length );
return result;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return '(' +
lhs.toSqlString(criteria, criteriaQuery) +
' ' +
getOp() +
' ' +
rhs.toSqlString(criteria, criteriaQuery) +
')';
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
return '('
+ lhs.toSqlString( criteria, criteriaQuery )
+ ' '
+ getOp()
+ ' '
+ rhs.toSqlString( criteria, criteriaQuery )
+ ')';
}
public String getOp() {
return op;
}
@Override
public String toString() {
return lhs.toString() + ' ' + getOp() + ' ' + rhs.toString();
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
@ -36,6 +35,7 @@ public enum MatchMode {
* Match the entire string to the pattern
*/
EXACT {
@Override
public String toMatchString(String pattern) {
return pattern;
}
@ -45,6 +45,7 @@ public enum MatchMode {
* Match the start of the string to the pattern
*/
START {
@Override
public String toMatchString(String pattern) {
return pattern + '%';
}
@ -54,6 +55,7 @@ public enum MatchMode {
* Match the end of the string to the pattern
*/
END {
@Override
public String toMatchString(String pattern) {
return '%' + pattern;
}
@ -63,13 +65,18 @@ public enum MatchMode {
* Match the pattern anywhere in the string
*/
ANYWHERE {
@Override
public String toMatchString(String pattern) {
return '%' + pattern + '%';
}
};
/**
* convert the pattern, by appending/prepending "%"
* Convert the pattern, by appending/prepending "%"
*
* @param pattern The pattern for convert according to the mode
*
* @return The converted pattern
*/
public abstract String toMatchString(String pattern);

View File

@ -28,27 +28,37 @@ import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.engine.spi.TypedValue;
/**
* An expression pertaining to an entity's defined natural identifier
*
* @author Gavin King
* @see Session#byNaturalId(Class)
* @see Session#byNaturalId(String)
* @see Session#bySimpleNaturalId(Class)
* @see Session#bySimpleNaturalId(String)
*
* @see org.hibernate.Session#byNaturalId(Class)
* @see org.hibernate.Session#byNaturalId(String)
* @see org.hibernate.Session#bySimpleNaturalId(Class)
* @see org.hibernate.Session#bySimpleNaturalId(String)
*/
public class NaturalIdentifier implements Criterion {
private final Conjunction conjunction = new Conjunction();
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return conjunction.getTypedValues( criteria, criteriaQuery );
}
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return conjunction.toSqlString( criteria, criteriaQuery );
}
/**
* Get a map of set of the natural identifier values set on this criterion (for composite natural identifiers
* this need not be the full set of properties).
*
* @return The value map.
*/
public Map<String, Object> getNaturalIdValues() {
final Map<String, Object> naturalIdValueMap = new ConcurrentHashMap<String, Object>();
for ( Criterion condition : conjunction.conditions() ) {
@ -65,6 +75,14 @@ public class NaturalIdentifier implements Criterion {
return naturalIdValueMap;
}
/**
* Set a natural identifier value for this expression
*
* @param property The specific property name
* @param value The value to use
*
* @return {@code this}, for method chaining
*/
public NaturalIdentifier set(String property, Object value) {
conjunction.add( Restrictions.eq( property, value ) );
return this;

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,20 +20,27 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
/**
* An expression asserting that a collection property is empty
*
* @author Gavin King
*/
public class NotEmptyExpression extends AbstractEmptinessExpression implements Criterion {
/**
* Constructs an EmptyExpression
*
* @param propertyName The collection property name
*
* @see Restrictions#isNotEmpty
*/
protected NotEmptyExpression(String propertyName) {
super( propertyName );
}
@Override
protected boolean excludeEmpty() {
return true;
}

View File

@ -28,29 +28,37 @@ import org.hibernate.HibernateException;
import org.hibernate.engine.spi.TypedValue;
/**
* Negates another criterion
* A criterion that is a wrapper for another, negating the wrapped one.
*
* @author Gavin King
* @author Brett Meyer
*/
public class NotExpression implements Criterion {
private Criterion criterion;
/**
* Constructs a NotExpression
*
* @param criterion The expression to wrap and negate
*
* @see Restrictions#not
*/
protected NotExpression(Criterion criterion) {
this.criterion = criterion;
}
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return criteriaQuery.getFactory().getDialect().getNotExpression(
criterion.toSqlString( criteria, criteriaQuery ) );
criterion.toSqlString( criteria, criteriaQuery )
);
}
public TypedValue[] getTypedValues(
Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return criterion.getTypedValues(criteria, criteriaQuery);
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return criterion.getTypedValues( criteria, criteriaQuery );
}
@Override
public String toString() {
return "not " + criterion.toString();
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.TypedValue;
@ -30,36 +30,37 @@ import org.hibernate.internal.util.StringHelper;
/**
* Constrains a property to be non-null
*
* @author Gavin King
*/
public class NotNullExpression implements Criterion {
private static final TypedValue[] NO_VALUES = new TypedValue[0];
private final String propertyName;
private static final TypedValue[] NO_VALUES = new TypedValue[0];
protected NotNullExpression(String propertyName) {
this.propertyName = propertyName;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
String result = StringHelper.join(
" or ",
StringHelper.suffix( columns, " is not null" )
);
if (columns.length>1) result = '(' + result + ')';
if ( columns.length > 1 ) {
result = '(' + result + ')';
}
return result;
//TODO: get SQL rendering out of this package!
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return NO_VALUES;
}
@Override
public String toString() {
return propertyName + " is not null";
}

View File

@ -30,36 +30,44 @@ import org.hibernate.internal.util.StringHelper;
/**
* Constrains a property to be null
*
* @author Gavin King
*/
public class NullExpression implements Criterion {
private static final TypedValue[] NO_VALUES = new TypedValue[0];
private final String propertyName;
private static final TypedValue[] NO_VALUES = new TypedValue[0];
/**
* Constructs a NullExpression
*
* @param propertyName The name of the property to check for null
*
* @see Restrictions#isNull
*/
protected NullExpression(String propertyName) {
this.propertyName = propertyName;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
String result = StringHelper.join(
" and ",
StringHelper.suffix( columns, " is null" )
);
if (columns.length>1) result = '(' + result + ')';
if ( columns.length > 1 ) {
result = '(' + result + ')';
}
return result;
//TODO: get SQL rendering out of this package!
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return NO_VALUES;
}
@Override
public String toString() {
return propertyName + " is null";
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,24 +20,22 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import java.io.Serializable;
import java.sql.Types;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.NullPrecedence;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.type.Type;
/**
* Represents an order imposed upon a <tt>Criteria</tt> result set
* Represents an ordering imposed upon the results of a Criteria
*
* @author Gavin King
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @author Brett Meyer
*/
public class Order implements Serializable {
private boolean ascending;
@ -45,22 +43,33 @@ public class Order implements Serializable {
private String propertyName;
private NullPrecedence nullPrecedence;
public String toString() {
return propertyName + ' ' + ( ascending ? "asc" : "desc" ) + ( nullPrecedence != null ? ' ' + nullPrecedence.name().toLowerCase() : "" );
}
public Order ignoreCase() {
ignoreCase = true;
return this;
}
public Order nulls(NullPrecedence nullPrecedence) {
this.nullPrecedence = nullPrecedence;
return this;
/**
* Ascending order
*
* @param propertyName The property to order on
*
* @return The build Order instance
*/
public static Order asc(String propertyName) {
return new Order( propertyName, true );
}
/**
* Constructor for Order.
* Descending order.
*
* @param propertyName The property to order on
*
* @return The build Order instance
*/
public static Order desc(String propertyName) {
return new Order( propertyName, false );
}
/**
* Constructor for Order. Order instances are generally created by factory methods.
*
* @see #asc
* @see #desc
*/
protected Order(String propertyName, boolean ascending) {
this.propertyName = propertyName;
@ -68,74 +77,96 @@ public class Order implements Serializable {
}
/**
* Render the SQL fragment
* Should this ordering ignore case? Has no effect on non-character properties.
*
* @return {@code this}, for method chaining
*/
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName);
StringBuilder fragment = new StringBuilder();
for ( int i=0; i<columns.length; i++ ) {
final StringBuilder expression = new StringBuilder();
SessionFactoryImplementor factory = criteriaQuery.getFactory();
boolean lower = false;
if ( ignoreCase ) {
int sqlType = type.sqlTypes( factory )[i];
lower = sqlType == Types.VARCHAR
|| sqlType == Types.CHAR
|| sqlType == Types.LONGVARCHAR;
public Order ignoreCase() {
ignoreCase = true;
return this;
}
if (lower) {
expression.append( factory.getDialect().getLowercaseFunction() ).append('(');
}
expression.append( columns[i] );
if (lower) expression.append(')');
fragment.append(
factory.getDialect()
.renderOrderByElement(
expression.toString(),
null,
ascending ? "asc" : "desc",
nullPrecedence != null ? nullPrecedence : factory.getSettings().getDefaultNullPrecedence()
)
);
if ( i<columns.length-1 ) fragment.append(", ");
}
return fragment.toString();
/**
* Defines precedence for nulls.
*
* @param nullPrecedence The null precedence to use
*
* @return {@code this}, for method chaining
*/
public Order nulls(NullPrecedence nullPrecedence) {
this.nullPrecedence = nullPrecedence;
return this;
}
public String getPropertyName() {
return propertyName;
}
@SuppressWarnings("UnusedDeclaration")
public boolean isAscending() {
return ascending;
}
@SuppressWarnings("UnusedDeclaration")
public boolean isIgnoreCase() {
return ignoreCase;
}
/**
* Ascending order
*
* @param propertyName
* @return Order
*/
public static Order asc(String propertyName) {
return new Order(propertyName, true);
}
/**
* Descending order
* Render the SQL fragment
*
* @param propertyName
* @return Order
* @param criteria The criteria
* @param criteriaQuery The overall query
*
* @return The ORDER BY fragment for this ordering
*/
public static Order desc(String propertyName) {
return new Order(propertyName, false);
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
final String[] columns = criteriaQuery.getColumnsUsingProjection( criteria, propertyName );
final Type type = criteriaQuery.getTypeUsingProjection( criteria, propertyName );
final SessionFactoryImplementor factory = criteriaQuery.getFactory();
final int[] sqlTypes = type.sqlTypes( factory );
final StringBuilder fragment = new StringBuilder();
for ( int i=0; i<columns.length; i++ ) {
final StringBuilder expression = new StringBuilder();
boolean lower = false;
if ( ignoreCase ) {
final int sqlType = sqlTypes[i];
lower = sqlType == Types.VARCHAR
|| sqlType == Types.CHAR
|| sqlType == Types.LONGVARCHAR;
}
if ( lower ) {
expression.append( factory.getDialect().getLowercaseFunction() )
.append( '(' );
}
expression.append( columns[i] );
if ( lower ) {
expression.append( ')' );
}
fragment.append(
factory.getDialect().renderOrderByElement(
expression.toString(),
null,
ascending ? "asc" : "desc",
nullPrecedence != null ? nullPrecedence : factory.getSettings().getDefaultNullPrecedence()
)
);
if ( i < columns.length-1 ) {
fragment.append( ", " );
}
}
return fragment.toString();
}
@Override
public String toString() {
return propertyName + ' '
+ ( ascending ? "asc" : "desc" )
+ ( nullPrecedence != null ? ' ' + nullPrecedence.name().toLowerCase() : "" );
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import java.io.Serializable;
import org.hibernate.Criteria;
@ -36,6 +36,7 @@ import org.hibernate.type.Type;
*
* @author Gavin King
* @author Steve Ebersole
*
* @see Projections
* @see Criteria
*/

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,159 +20,223 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.type.Type;
/**
* A projection that wraps other projections to allow selecting multiple values.
*
* @author Gavin King
*/
public class ProjectionList implements EnhancedProjection {
private List<Projection> elements = new ArrayList<Projection>();
private List elements = new ArrayList();
protected ProjectionList() {}
/**
* Constructs a ProjectionList
*
* @see Projections#projectionList()
*/
protected ProjectionList() {
}
/**
* Lol
*
* @return duh
*
* @deprecated an instance factory method does not make sense
*
* @see Projections#projectionList()
*/
@Deprecated
public ProjectionList create() {
return new ProjectionList();
}
public ProjectionList add(Projection proj) {
elements.add(proj);
/**
* Add a projection to this list of projections
*
* @param projection The projection to add
*
* @return {@code this}, for method chaining
*/
public ProjectionList add(Projection projection) {
elements.add( projection );
return this;
}
/**
* Adds a projection to this list of projections after wrapping it with an alias
*
* @param projection The projection to add
* @param alias The alias to apply to the projection
*
* @return {@code this}, for method chaining
*
* @see Projections#alias
*/
public ProjectionList add(Projection projection, String alias) {
return add( Projections.alias( projection, alias ) );
}
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
List types = new ArrayList( getLength() );
for ( int i=0; i<getLength(); i++ ) {
Type[] elemTypes = getProjection(i).getTypes(criteria, criteriaQuery);
ArrayHelper.addAll(types, elemTypes);
@Override
public boolean isGrouped() {
for ( Projection projection : elements ) {
if ( projection.isGrouped() ) {
return true;
}
return ArrayHelper.toTypeArray(types);
}
return false;
}
public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery)
throws HibernateException {
StringBuilder buf = new StringBuilder();
for ( int i=0; i<getLength(); i++ ) {
Projection proj = getProjection(i);
buf.append( proj.toSqlString(criteria, loc, criteriaQuery) );
loc += getColumnAliases(loc, criteria, criteriaQuery, proj ).length;
if ( i<elements.size()-1 ) buf.append(", ");
@Override
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
final List<Type> types = new ArrayList<Type>( getLength() );
for ( Projection projection : elements ) {
final Type[] elemTypes = projection.getTypes( criteria, criteriaQuery );
Collections.addAll( types, elemTypes );
}
return types.toArray( new Type[types.size()] );
}
@Override
public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery) throws HibernateException {
final StringBuilder buf = new StringBuilder();
String separator = "";
for ( Projection projection : elements ) {
buf.append( separator ).append( projection.toSqlString( criteria, loc, criteriaQuery ) );
loc += getColumnAliases( loc, criteria, criteriaQuery, projection ).length;
separator = ", ";
}
return buf.toString();
}
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
StringBuilder buf = new StringBuilder();
for ( int i=0; i<getLength(); i++ ) {
Projection proj = getProjection(i);
if ( proj.isGrouped() ) {
buf.append( proj.toGroupSqlString(criteria, criteriaQuery) )
.append(", ");
@Override
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
final StringBuilder buf = new StringBuilder();
String separator = "";
for ( Projection projection : elements ) {
if ( ! projection.isGrouped() ) {
continue;
}
buf.append( separator ).append( projection.toGroupSqlString( criteria, criteriaQuery ) );
separator = ", ";
}
if ( buf.length()>2 ) buf.setLength( buf.length()-2 ); //pull off the last ", "
return buf.toString();
}
public String[] getColumnAliases(int loc) {
List result = new ArrayList( getLength() );
for ( int i=0; i<getLength(); i++ ) {
String[] colAliases = getProjection(i).getColumnAliases(loc);
ArrayHelper.addAll(result, colAliases);
loc+=colAliases.length;
@Override
public String[] getColumnAliases(final int loc) {
int position = loc;
final List<String> result = new ArrayList<String>( getLength() );
for ( Projection projection : elements ) {
final String[] aliases = projection.getColumnAliases( position );
Collections.addAll( result, aliases );
position += aliases.length;
}
return ArrayHelper.toStringArray(result);
return result.toArray( new String[ result.size() ] );
}
public String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
List result = new ArrayList( getLength() );
for ( int i=0; i<getLength(); i++ ) {
String[] colAliases = getColumnAliases( loc, criteria, criteriaQuery, getProjection( i ) );
ArrayHelper.addAll(result, colAliases);
loc+=colAliases.length;
@Override
public String[] getColumnAliases(final int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
int position = loc;
final List<String> result = new ArrayList<String>( getLength() );
for ( Projection projection : elements ) {
final String[] aliases = getColumnAliases( position, criteria, criteriaQuery, projection );
Collections.addAll( result, aliases );
position += aliases.length;
}
return ArrayHelper.toStringArray(result);
return result.toArray( new String[result.size()] );
}
public String[] getColumnAliases(String alias, int loc) {
for ( int i=0; i<getLength(); i++ ) {
String[] result = getProjection(i).getColumnAliases(alias, loc);
if (result!=null) return result;
loc += getProjection(i).getColumnAliases(loc).length;
@Override
public String[] getColumnAliases(String alias, final int loc) {
int position = loc;
for ( Projection projection : elements ) {
final String[] aliases = projection.getColumnAliases( alias, position );
if ( aliases != null ) {
return aliases;
}
position += projection.getColumnAliases( position ).length;
}
return null;
}
@Override
public String[] getColumnAliases(String alias, int loc, Criteria criteria, CriteriaQuery criteriaQuery) {
for ( int i=0; i<getLength(); i++ ) {
String[] result = getColumnAliases( alias, loc, criteria, criteriaQuery, getProjection(i) );
if (result!=null) return result;
loc += getColumnAliases( loc, criteria, criteriaQuery, getProjection( i ) ).length;
int position = loc;
for ( Projection projection : elements ) {
final String[] aliases = getColumnAliases( alias, position, criteria, criteriaQuery, projection );
if ( aliases != null ) {
return aliases;
}
position += getColumnAliases( position, criteria, criteriaQuery, projection ).length;
}
return null;
}
private static String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery, Projection projection) {
return projection instanceof EnhancedProjection ?
( ( EnhancedProjection ) projection ).getColumnAliases( loc, criteria, criteriaQuery ) :
projection.getColumnAliases( loc );
return projection instanceof EnhancedProjection
? ( (EnhancedProjection) projection ).getColumnAliases( loc, criteria, criteriaQuery )
: projection.getColumnAliases( loc );
}
private static String[] getColumnAliases(String alias, int loc, Criteria criteria, CriteriaQuery criteriaQuery, Projection projection) {
return projection instanceof EnhancedProjection ?
( ( EnhancedProjection ) projection ).getColumnAliases( alias, loc, criteria, criteriaQuery ) :
projection.getColumnAliases( alias, loc );
return projection instanceof EnhancedProjection
? ( (EnhancedProjection) projection ).getColumnAliases( alias, loc, criteria, criteriaQuery )
: projection.getColumnAliases( alias, loc );
}
@Override
public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery) {
for ( int i=0; i<getLength(); i++ ) {
Type[] result = getProjection(i).getTypes(alias, criteria, criteriaQuery);
if (result!=null) return result;
for ( Projection projection : elements ) {
final Type[] types = projection.getTypes( alias, criteria, criteriaQuery );
if ( types != null ) {
return types;
}
}
return null;
}
@Override
public String[] getAliases() {
List result = new ArrayList( getLength() );
for ( int i=0; i<getLength(); i++ ) {
String[] aliases = getProjection(i).getAliases();
ArrayHelper.addAll( result, aliases );
final List<String> result = new ArrayList<String>( getLength() );
for ( Projection projection : elements ) {
final String[] aliases = projection.getAliases();
Collections.addAll( result, aliases );
}
return ArrayHelper.toStringArray(result);
return result.toArray( new String[result.size()] );
}
/**
* Access a wrapped projection by index
*
* @param i The index of the projection to return
*
* @return The projection
*/
@SuppressWarnings("UnusedDeclaration")
public Projection getProjection(int i) {
return (Projection) elements.get(i);
return elements.get( i );
}
public int getLength() {
return elements.size();
}
@Override
public String toString() {
return elements.toString();
}
public boolean isGrouped() {
for ( int i=0; i<getLength(); i++ ) {
if ( getProjection(i).isGrouped() ) return true;
}
return false;
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,38 +20,81 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.type.Type;
/**
* The <tt>criterion</tt> package may be used by applications as a framework for building
* new kinds of <tt>Projection</tt>. However, it is intended that most applications will
* simply use the built-in projection types via the static factory methods of this class.<br/>
* <br/>
* simply use the built-in projection types via the static factory methods of this class.
*
* The factory methods that take an alias allow the projected value to be referred to by
* criterion and order instances.
*
* @see org.hibernate.Criteria
* @see Restrictions factory methods for <tt>Criterion</tt> instances
* See also the {@link Restrictions} factory methods for generating {@link Criterion} instances
*
* @author Gavin King
* @author Steve Ebersole
*
* @see org.hibernate.Criteria
*/
public final class Projections {
private Projections() {
//cannot be instantiated
}
/**
* Create a distinct projection from a projection
* A property value projection
*
* @param propertyName The name of the property whose values should be projected
*
* @return The property projection
*
* @see PropertyProjection
*/
public static Projection distinct(Projection proj) {
return new Distinct(proj);
public static PropertyProjection property(String propertyName) {
return new PropertyProjection( propertyName );
}
/**
* Create a new projection list
* A grouping property value projection
*
* @param propertyName The name of the property to group
*
* @return The grouped projection
*
* @see PropertyProjection
*/
public static PropertyProjection groupProperty(String propertyName) {
return new PropertyProjection( propertyName, true );
}
/**
* An identifier value projection.
*
* @return The identifier projection
*
* @see IdentifierProjection
*/
public static IdentifierProjection id() {
return new IdentifierProjection();
}
/**
* Create a distinct projection from a projection.
*
* @param projection The project to treat distinctly
*
* @return The distinct projection
*
* @see Distinct
*/
public static Projection distinct(Projection projection) {
return new Distinct( projection );
}
/**
* Create a new projection list.
*
* @return The projection list
*/
public static ProjectionList projectionList() {
return new ProjectionList();
@ -59,92 +102,141 @@ public final class Projections {
/**
* The query row count, ie. <tt>count(*)</tt>
*
* @return The projection representing the row count
*
* @see RowCountProjection
*/
public static Projection rowCount() {
return new RowCountProjection();
}
/**
* A property value count
* A property value count projection
*
* @param propertyName The name of the property to count over
*
* @return The count projection
*
* @see CountProjection
*/
public static CountProjection count(String propertyName) {
return new CountProjection(propertyName);
return new CountProjection( propertyName );
}
/**
* A distinct property value count
* A distinct property value count projection
*
* @param propertyName The name of the property to count over
*
* @return The count projection
*
* @see CountProjection
*/
public static CountProjection countDistinct(String propertyName) {
return new CountProjection(propertyName).setDistinct();
return new CountProjection( propertyName ).setDistinct();
}
/**
* A property maximum value
* A property maximum value projection
*
* @param propertyName The property for which to find the max
*
* @return the max projection
*
* @see AggregateProjection
*/
public static AggregateProjection max(String propertyName) {
return new AggregateProjection("max", propertyName);
return new AggregateProjection( "max", propertyName );
}
/**
* A property minimum value
* A property minimum value projection
*
* @param propertyName The property for which to find the min
*
* @return the min projection
*
* @see AggregateProjection
*/
public static AggregateProjection min(String propertyName) {
return new AggregateProjection("min", propertyName);
return new AggregateProjection( "min", propertyName );
}
/**
* A property average value
* A property average value projection
*
* @param propertyName The property over which to find the average
*
* @return the avg projection
*
* @see AvgProjection
*/
public static AggregateProjection avg(String propertyName) {
return new AvgProjection(propertyName);
return new AvgProjection( propertyName );
}
/**
* A property value sum
* A property value sum projection
*
* @param propertyName The property over which to sum
*
* @return the sum projection
*
* @see AggregateProjection
*/
public static AggregateProjection sum(String propertyName) {
return new AggregateProjection("sum", propertyName);
}
/**
* A SQL projection, a typed select clause fragment
*/
public static Projection sqlProjection(String sql, String[] columnAliases, Type[] types) {
return new SQLProjection(sql, columnAliases, types);
}
/**
* A grouping SQL projection, specifying both select clause and group by clause fragments
*/
public static Projection sqlGroupProjection(String sql, String groupBy, String[] columnAliases, Type[] types) {
return new SQLProjection(sql, groupBy, columnAliases, types);
}
/**
* A grouping property value
*/
public static PropertyProjection groupProperty(String propertyName) {
return new PropertyProjection(propertyName, true);
}
/**
* A projected property value
*/
public static PropertyProjection property(String propertyName) {
return new PropertyProjection(propertyName);
}
/**
* A projected identifier value
*/
public static IdentifierProjection id() {
return new IdentifierProjection();
return new AggregateProjection( "sum", propertyName );
}
/**
* Assign an alias to a projection, by wrapping it
*
* @param projection The projection to be aliased
* @param alias The alias to apply
*
* @return The aliased projection
*
* @see AliasedProjection
*/
public static Projection alias(Projection projection, String alias) {
return new AliasedProjection(projection, alias);
return new AliasedProjection( projection, alias );
}
/**
* A SQL projection, a typed select clause fragment
*
* @param sql The SQL fragment
* @param columnAliases The column aliases
* @param types The resulting types
*
* @return The SQL projection
*
* @see SQLProjection
*/
public static Projection sqlProjection(String sql, String[] columnAliases, Type[] types) {
return new SQLProjection( sql, columnAliases, types );
}
/**
* A grouping SQL projection, specifying both select clause and group by clause fragments
*
* @param sql The SQL SELECT fragment
* @param groupBy The SQL GROUP BY fragment
* @param columnAliases The column aliases
* @param types The resulting types
*
* @return The SQL projection
*
* @see SQLProjection
*/
@SuppressWarnings("UnusedDeclaration")
public static Projection sqlGroupProjection(String sql, String groupBy, String[] columnAliases, Type[] types) {
return new SQLProjection(sql, groupBy, columnAliases, types);
}
private Projections() {
//cannot be instantiated
}
}

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
@ -5,6 +28,7 @@ import org.hibernate.internal.util.StringHelper;
/**
* A comparison between several properties value in the outer query and the result of a multicolumn subquery.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class PropertiesSubqueryExpression extends SubqueryExpression {
@ -17,7 +41,7 @@ public class PropertiesSubqueryExpression extends SubqueryExpression {
@Override
protected String toLeftSqlString(Criteria criteria, CriteriaQuery outerQuery) {
StringBuilder left = new StringBuilder( "(" );
final StringBuilder left = new StringBuilder( "(" );
final String[] sqlColumnNames = new String[propertyNames.length];
for ( int i = 0; i < sqlColumnNames.length; ++i ) {
sqlColumnNames[i] = outerQuery.getColumn( criteria, propertyNames[i] );

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,244 +20,737 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import java.util.Collection;
/**
* A factory for property-specific criterion and projection instances
*
* @author Gavin King
* @author Steve Ebersole
*/
public class Property extends PropertyProjection {
//private String propertyName;
/**
* Factory for Property instances.
*
* @param propertyName The name of the property.
*
* @return The Property instance
*/
public static Property forName(String propertyName) {
return new Property( propertyName );
}
/**
* Constructs a Property. non-private to allow subclassing.
*
* @param propertyName The property name.
*/
protected Property(String propertyName) {
super(propertyName);
super( propertyName );
}
/**
* Creates a BETWEEN restriction for this property between the given min and max
*
* @param min The minimum
* @param max The maximum
*
* @return The BETWEEN restriction
*
* @see Restrictions#between(String, Object, Object)
*/
public Criterion between(Object min, Object max) {
return Restrictions.between(getPropertyName(), min, max);
return Restrictions.between( getPropertyName(), min, max );
}
/**
* Creates an IN restriction for this property based on the given list of literals
*
* @param values The literal values
*
* @return The IN restriction
*
* @see Restrictions#in(String, Collection)
*/
public Criterion in(Collection values) {
return Restrictions.in(getPropertyName(), values);
return Restrictions.in( getPropertyName(), values );
}
/**
* Creates an IN restriction for this property based on the given list of literals
*
* @param values The literal values
*
* @return The IN restriction
*
* @see Restrictions#in(String, Object[])
*/
public Criterion in(Object[] values) {
return Restrictions.in(getPropertyName(), values);
return Restrictions.in( getPropertyName(), values );
}
/**
* Creates a LIKE restriction for this property
*
* @param value The value to like compare with
*
* @return The LIKE restriction
*
* @see Restrictions#like(String, Object)
*/
public SimpleExpression like(Object value) {
return Restrictions.like(getPropertyName(), value);
return Restrictions.like( getPropertyName(), value );
}
/**
* Creates a LIKE restriction for this property
*
* @param value The value to like compare with
* @param matchMode The match mode to apply to the LIKE
*
* @return The LIKE restriction
*
* @see Restrictions#like(String, String, MatchMode)
*/
public SimpleExpression like(String value, MatchMode matchMode) {
return Restrictions.like(getPropertyName(), value, matchMode);
return Restrictions.like( getPropertyName(), value, matchMode );
}
/**
* Creates an equality restriction.
*
* @param value The value to check against
*
* @return The equality restriction.
*
* @see Restrictions#eq(String, Object)
*/
public SimpleExpression eq(Object value) {
return Restrictions.eq(getPropertyName(), value);
return Restrictions.eq( getPropertyName(), value );
}
/**
* Creates an equality restriction capable of also rendering as IS NULL if the given value is {@code null}
*
* @param value The value to check against
*
* @return The equality restriction.
*
* @see Restrictions#eqOrIsNull(String, Object)
* @see #eq
* @see #isNull
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion eqOrIsNull(Object value) {
return Restrictions.eqOrIsNull(getPropertyName(), value);
return Restrictions.eqOrIsNull( getPropertyName(), value );
}
/**
* Creates an non-equality restriction.
*
* @param value The value to check against
*
* @return The non-equality restriction.
*
* @see Restrictions#ne(String, Object)
*/
public SimpleExpression ne(Object value) {
return Restrictions.ne(getPropertyName(), value);
return Restrictions.ne( getPropertyName(), value );
}
/**
* Creates an non-equality restriction capable of also rendering as IS NOT NULL if the given value is {@code null}
*
* @param value The value to check against
*
* @return The non-equality restriction.
*
* @see Restrictions#neOrIsNotNull(String, Object)
* @see #ne
* @see #isNotNull
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion neOrIsNotNull(Object value) {
return Restrictions.neOrIsNotNull(getPropertyName(), value);
return Restrictions.neOrIsNotNull( getPropertyName(), value );
}
/**
* Create a greater-than restriction based on this property
*
* @param value The value to check against
*
* @return The greater-than restriction
*
* @see Restrictions#gt(String, Object)
*/
public SimpleExpression gt(Object value) {
return Restrictions.gt(getPropertyName(), value);
return Restrictions.gt( getPropertyName(), value );
}
/**
* Create a less-than restriction based on this property
*
* @param value The value to check against
*
* @return The less-than restriction
*
* @see Restrictions#lt(String, Object)
*/
public SimpleExpression lt(Object value) {
return Restrictions.lt(getPropertyName(), value);
return Restrictions.lt( getPropertyName(), value );
}
/**
* Create a less-than-or-equal-to restriction based on this property
*
* @param value The value to check against
*
* @return The less-than-or-equal-to restriction
*
* @see Restrictions#le(String, Object)
*/
public SimpleExpression le(Object value) {
return Restrictions.le(getPropertyName(), value);
return Restrictions.le( getPropertyName(), value );
}
/**
* Create a greater-than-or-equal-to restriction based on this property
*
* @param value The value to check against
*
* @return The greater-than-or-equal-to restriction
*
* @see Restrictions#ge(String, Object)
*/
public SimpleExpression ge(Object value) {
return Restrictions.ge(getPropertyName(), value);
return Restrictions.ge( getPropertyName(), value );
}
/**
* Creates an equality restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#eqProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression eqProperty(Property other) {
return Restrictions.eqProperty( getPropertyName(), other.getPropertyName() );
}
public PropertyExpression neProperty(Property other) {
return Restrictions.neProperty( getPropertyName(), other.getPropertyName() );
}
public PropertyExpression leProperty(Property other) {
return Restrictions.leProperty( getPropertyName(), other.getPropertyName() );
}
public PropertyExpression geProperty(Property other) {
return Restrictions.geProperty( getPropertyName(), other.getPropertyName() );
}
public PropertyExpression ltProperty(Property other) {
return Restrictions.ltProperty( getPropertyName(), other.getPropertyName() );
}
public PropertyExpression gtProperty(Property other) {
return Restrictions.gtProperty( getPropertyName(), other.getPropertyName() );
}
/**
* Creates an equality restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#eqProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression eqProperty(String other) {
return Restrictions.eqProperty( getPropertyName(), other );
}
/**
* Creates an non-equality restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#neProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression neProperty(Property other) {
return Restrictions.neProperty( getPropertyName(), other.getPropertyName() );
}
/**
* Creates an non-equality restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#neProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression neProperty(String other) {
return Restrictions.neProperty( getPropertyName(), other );
}
/**
* Creates an less-than-or-equal-to restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#leProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression leProperty(Property other) {
return Restrictions.leProperty( getPropertyName(), other.getPropertyName() );
}
/**
* Creates an less-than-or-equal-to restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#leProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression leProperty(String other) {
return Restrictions.leProperty( getPropertyName(), other );
}
/**
* Creates an greater-than-or-equal-to restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#geProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression geProperty(Property other) {
return Restrictions.geProperty( getPropertyName(), other.getPropertyName() );
}
/**
* Creates an greater-than-or-equal-to restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#geProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression geProperty(String other) {
return Restrictions.geProperty( getPropertyName(), other );
}
/**
* Creates an less-than restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#ltProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression ltProperty(Property other) {
return Restrictions.ltProperty( getPropertyName(), other.getPropertyName() );
}
/**
* Creates an less-than restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#ltProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression ltProperty(String other) {
return Restrictions.ltProperty( getPropertyName(), other );
}
/**
* Creates an greater-than restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#geProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression gtProperty(Property other) {
return Restrictions.gtProperty( getPropertyName(), other.getPropertyName() );
}
/**
* Creates an greater-than restriction between 2 properties
*
* @param other The other property to compare against
*
* @return The restriction
*
* @see Restrictions#geProperty(String, String)
*/
@SuppressWarnings("UnusedDeclaration")
public PropertyExpression gtProperty(String other) {
return Restrictions.gtProperty( getPropertyName(), other );
}
/**
* Creates a NULL restriction
*
* @return The restriction
*
* @see Restrictions#isNull(String)
*/
public Criterion isNull() {
return Restrictions.isNull(getPropertyName());
}
public Criterion isNotNull() {
return Restrictions.isNotNull(getPropertyName());
}
public Criterion isEmpty() {
return Restrictions.isEmpty(getPropertyName());
}
public Criterion isNotEmpty() {
return Restrictions.isNotEmpty(getPropertyName());
}
public CountProjection count() {
return Projections.count(getPropertyName());
}
public AggregateProjection max() {
return Projections.max(getPropertyName());
}
public AggregateProjection min() {
return Projections.min(getPropertyName());
}
public AggregateProjection avg() {
return Projections.avg(getPropertyName());
}
/*public PropertyProjection project() {
return Projections.property(getPropertyName());
}*/
public PropertyProjection group() {
return Projections.groupProperty(getPropertyName());
}
public Order asc() {
return Order.asc(getPropertyName());
}
public Order desc() {
return Order.desc(getPropertyName());
}
public static Property forName(String propertyName) {
return new Property(propertyName);
return Restrictions.isNull( getPropertyName() );
}
/**
* Get a component attribute of this property
* Creates a NOT NULL restriction
*
* @return The restriction
*
* @see Restrictions#isNotNull(String)
*/
public Criterion isNotNull() {
return Restrictions.isNotNull( getPropertyName() );
}
/**
* Creates a restriction to check that a collection is empty
*
* @return The restriction
*
* @see Restrictions#isEmpty(String)
*/
public Criterion isEmpty() {
return Restrictions.isEmpty( getPropertyName() );
}
/**
* Creates a restriction to check that a collection is not empty
*
* @return The restriction
*
* @see Restrictions#isNotEmpty(String)
*/
public Criterion isNotEmpty() {
return Restrictions.isNotEmpty( getPropertyName() );
}
/**
* Creates a property count projection
*
* @return The projection
*
* @see Projections#count
*/
public CountProjection count() {
return Projections.count( getPropertyName() );
}
/**
* Creates a property max projection
*
* @return The projection
*
* @see Projections#max
*/
public AggregateProjection max() {
return Projections.max( getPropertyName() );
}
/**
* Creates a property min projection
*
* @return The projection
*
* @see Projections#min
*/
public AggregateProjection min() {
return Projections.min( getPropertyName() );
}
/**
* Creates a property avg projection
*
* @return The projection
*
* @see Projections#avg
*/
public AggregateProjection avg() {
return Projections.avg( getPropertyName() );
}
/**
* Creates a projection for this property as a group expression
*
* @return The group projection
*
* @see Projections#groupProperty
*/
public PropertyProjection group() {
return Projections.groupProperty( getPropertyName() );
}
/**
* Creates an ascending ordering for this property
*
* @return The order
*/
public Order asc() {
return Order.asc( getPropertyName() );
}
/**
* Creates a descending ordering for this property
*
* @return The order
*/
public Order desc() {
return Order.desc( getPropertyName() );
}
/**
* Get a component attribute of this property.
*
* @param propertyName The sub property name
*
* @return The property
*/
public Property getProperty(String propertyName) {
return forName( getPropertyName() + '.' + propertyName );
}
/**
* Creates a sub-query equality expression for this property
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyEq(String, DetachedCriteria)
*/
public Criterion eq(DetachedCriteria subselect) {
return Subqueries.propertyEq( getPropertyName(), subselect );
}
/**
* Creates a sub-query non-equality expression for this property
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyNe(String, DetachedCriteria)
*/
public Criterion ne(DetachedCriteria subselect) {
return Subqueries.propertyNe( getPropertyName(), subselect );
}
/**
* Creates a sub-query less-than expression for this property
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyLt(String, DetachedCriteria)
*/
public Criterion lt(DetachedCriteria subselect) {
return Subqueries.propertyLt( getPropertyName(), subselect );
}
/**
* Creates a sub-query less-than-or-equal-to expression for this property
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyLe(String, DetachedCriteria)
*/
public Criterion le(DetachedCriteria subselect) {
return Subqueries.propertyLe( getPropertyName(), subselect );
}
/**
* Creates a sub-query greater-than expression for this property
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyGt(String, DetachedCriteria)
*/
public Criterion gt(DetachedCriteria subselect) {
return Subqueries.propertyGt( getPropertyName(), subselect );
}
/**
* Creates a sub-query greater-than-or-equal-to expression for this property
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyGe(String, DetachedCriteria)
*/
public Criterion ge(DetachedCriteria subselect) {
return Subqueries.propertyGe( getPropertyName(), subselect );
}
/**
* Creates a sub-query NOT IN expression for this property. I.e., {@code [prop] NOT IN [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyNotIn(String, DetachedCriteria)
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion notIn(DetachedCriteria subselect) {
return Subqueries.propertyNotIn( getPropertyName(), subselect );
}
/**
* Creates a sub-query IN expression for this property. I.e., {@code [prop] IN [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyIn(String, DetachedCriteria)
*/
public Criterion in(DetachedCriteria subselect) {
return Subqueries.propertyIn( getPropertyName(), subselect );
}
/**
* Creates a equals-all sub-query expression for this property. I.e., {@code [prop] = ALL [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyEqAll(String, DetachedCriteria)
*/
public Criterion eqAll(DetachedCriteria subselect) {
return Subqueries.propertyEqAll( getPropertyName(), subselect );
}
/**
* Creates a greater-than-all sub-query expression for this property. I.e., {@code [prop] > ALL [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyGtAll(String, DetachedCriteria)
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion gtAll(DetachedCriteria subselect) {
return Subqueries.propertyGtAll( getPropertyName(), subselect );
}
/**
* Creates a less-than-all sub-query expression for this property. I.e., {@code [prop] < ALL [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyLtAll(String, DetachedCriteria)
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion ltAll(DetachedCriteria subselect) {
return Subqueries.propertyLtAll( getPropertyName(), subselect );
}
/**
* Creates a less-than-or-equal-to-all sub-query expression for this property. I.e., {@code [prop] <= ALL [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyLeAll(String, DetachedCriteria)
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion leAll(DetachedCriteria subselect) {
return Subqueries.propertyLeAll( getPropertyName(), subselect );
}
/**
* Creates a greater-than-or-equal-to-all sub-query expression for this property. I.e., {@code [prop] >= ALL [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyGeAll(String, DetachedCriteria)
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion geAll(DetachedCriteria subselect) {
return Subqueries.propertyGeAll( getPropertyName(), subselect );
}
/**
* Creates a greater-than-some sub-query expression for this property. I.e., {@code [prop] > SOME [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyGtSome(String, DetachedCriteria)
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion gtSome(DetachedCriteria subselect) {
return Subqueries.propertyGtSome( getPropertyName(), subselect );
}
/**
* Creates a less-than-some sub-query expression for this property. I.e., {@code [prop] < SOME [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyLtSome(String, DetachedCriteria)
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion ltSome(DetachedCriteria subselect) {
return Subqueries.propertyLtSome( getPropertyName(), subselect );
}
/**
* Creates a less-than-or-equal-to-some sub-query expression for this property. I.e., {@code [prop] <= SOME [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyLeSome(String, DetachedCriteria)
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion leSome(DetachedCriteria subselect) {
return Subqueries.propertyLeSome( getPropertyName(), subselect );
}
/**
* Creates a greater-than-or-equal-to-some sub-query expression for this property. I.e., {@code [prop] >= SOME [subquery]}
*
* @param subselect The sub-query
*
* @return The expression
*
* @see Subqueries#propertyGeSome(String, DetachedCriteria)
*/
@SuppressWarnings("UnusedDeclaration")
public Criterion geSome(DetachedCriteria subselect) {
return Subqueries.propertyGeSome( getPropertyName(), subselect );
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.TypedValue;
@ -30,46 +30,48 @@ import org.hibernate.internal.util.StringHelper;
/**
* superclass for comparisons between two properties (with SQL binary operators)
*
* @author Gavin King
*/
public class PropertyExpression implements Criterion {
private static final TypedValue[] NO_TYPED_VALUES = new TypedValue[0];
private final String propertyName;
private final String otherPropertyName;
private final String op;
private static final TypedValue[] NO_TYPED_VALUES = new TypedValue[0];
protected PropertyExpression(String propertyName, String otherPropertyName, String op) {
this.propertyName = propertyName;
this.otherPropertyName = otherPropertyName;
this.op = op;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
String[] xcols = criteriaQuery.findColumns(propertyName, criteria);
String[] ycols = criteriaQuery.findColumns(otherPropertyName, criteria);
String result = StringHelper.join(
" and ",
StringHelper.add( xcols, getOp(), ycols )
);
if (xcols.length>1) result = '(' + result + ')';
return result;
//TODO: get SQL rendering out of this package!
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return NO_TYPED_VALUES;
}
public String toString() {
return propertyName + getOp() + otherPropertyName;
}
public String getOp() {
return op;
}
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
final String[] lhsColumns = criteriaQuery.findColumns( propertyName, criteria );
final String[] rhsColumns = criteriaQuery.findColumns( otherPropertyName, criteria );
final String[] comparisons = StringHelper.add( lhsColumns, getOp(), rhsColumns );
if ( comparisons.length > 1 ) {
return '(' + StringHelper.join( " and ", comparisons ) + ')';
}
else {
return comparisons[0];
}
}
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) {
return NO_TYPED_VALUES;
}
@Override
public String toString() {
return propertyName + getOp() + otherPropertyName;
}
}

View File

@ -30,10 +30,11 @@ import org.hibernate.type.Type;
/**
* A property value, or grouped property value
*
* @author Gavin King
* @author Steve Ebersole
*/
public class PropertyProjection extends SimpleProjection {
private String propertyName;
private boolean grouped;
@ -43,49 +44,52 @@ public class PropertyProjection extends SimpleProjection {
}
protected PropertyProjection(String prop) {
this(prop, false);
this( prop, false );
}
@Override
public boolean isGrouped() {
return grouped;
}
public String getPropertyName() {
return propertyName;
}
public String toString() {
return propertyName;
@Override
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return new Type[] { criteriaQuery.getType( criteria, propertyName ) };
}
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return new Type[] { criteriaQuery.getType(criteria, propertyName) };
}
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery)
throws HibernateException {
StringBuilder buf = new StringBuilder();
String[] cols = criteriaQuery.getColumns( propertyName, criteria );
@Override
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) throws HibernateException {
final StringBuilder buf = new StringBuilder();
final String[] cols = criteriaQuery.getColumns( propertyName, criteria );
for ( int i=0; i<cols.length; i++ ) {
buf.append( cols[i] )
.append(" as y")
.append(position + i)
.append('_');
if (i < cols.length -1)
buf.append(", ");
.append( " as y" )
.append( position + i )
.append( '_' );
if (i < cols.length -1) {
buf.append( ", " );
}
}
return buf.toString();
}
public boolean isGrouped() {
return grouped;
}
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
if (!grouped) {
return super.toGroupSqlString(criteria, criteriaQuery);
@Override
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
if ( !grouped ) {
return super.toGroupSqlString( criteria, criteriaQuery );
}
else {
return StringHelper.join( ", ", criteriaQuery.getColumns( propertyName, criteria ) );
}
}
@Override
public String toString() {
return propertyName;
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,26 +20,28 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
/**
* A comparison between a property value in the outer query and the
* result of a subquery
* A comparison between a property value in the outer query and the result of a subquery
*
* @author Gavin King
* @author Steve Ebersole
*/
public class PropertySubqueryExpression extends SubqueryExpression {
private String propertyName;
protected PropertySubqueryExpression(String propertyName, String op, String quantifier, DetachedCriteria dc) {
super(op, quantifier, dc);
super( op, quantifier, dc );
this.propertyName = propertyName;
}
@Override
protected String toLeftSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
return criteriaQuery.getColumn(criteria, propertyName);
return criteriaQuery.getColumn( criteria, propertyName );
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,16 +20,12 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.Session;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.type.Type;
/**
@ -37,105 +33,130 @@ import org.hibernate.type.Type;
* new kinds of <tt>Criterion</tt>. However, it is intended that most applications will
* simply use the built-in criterion types via the static factory methods of this class.
*
* @see org.hibernate.Criteria
* @see Projections factory methods for <tt>Projection</tt> instances
* See also the {@link Projections} factory methods for generating {@link Projection} instances
*
* @author Gavin King
* @author Steve Ebersole
*
* @see org.hibernate.Criteria
*/
public class Restrictions {
Restrictions() {
//cannot be instantiated
}
/**
* Apply an "equal" constraint to the identifier property
* @param value
*
* @param value The value to use in comparison
*
* @return Criterion
*
* @see IdentifierEqExpression
*/
public static Criterion idEq(Object value) {
return new IdentifierEqExpression(value);
return new IdentifierEqExpression( value );
}
/**
* Apply an "equal" constraint to the named property
* @param propertyName
* @param value
*
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return SimpleExpression
*
* @see SimpleExpression
*/
public static SimpleExpression eq(String propertyName, Object value) {
return new SimpleExpression(propertyName, value, "=");
}
/**
* Apply an "equal" constraint to the named property. If the value
* is null, instead apply "is null".
* @param propertyName
* @param value
* @return Criterion
*/
public static Criterion eqOrIsNull(String propertyName, Object value) {
if (value == null) {
return isNull(propertyName);
}
return new SimpleExpression(propertyName, value, "=");
}
/**
* Apply a "not equal" constraint to the named property
* @param propertyName
* @param value
* @return SimpleExpression
*/
public static SimpleExpression ne(String propertyName, Object value) {
return new SimpleExpression(propertyName, value, "<>");
}
/**
* Apply a "not equal" constraint to the named property. If the value
* is null, instead apply "is not null".
* @param propertyName
* @param value
* @return Criterion
*/
public static Criterion neOrIsNotNull(String propertyName, Object value) {
if (value == null) {
return isNotNull(propertyName);
}
return new SimpleExpression(propertyName, value, "<>");
}
/**
* Apply a "like" constraint to the named property
* @param propertyName
* @param value
* @return Criterion
*/
public static SimpleExpression like(String propertyName, Object value) {
return new SimpleExpression(propertyName, value, " like ");
}
/**
* Apply a "like" constraint to the named property
* @param propertyName
* @param value
* @return Criterion
*/
public static SimpleExpression like(String propertyName, String value, MatchMode matchMode) {
return new SimpleExpression(propertyName, matchMode.toMatchString(value), " like " );
return new SimpleExpression( propertyName, value, "=" );
}
/**
* A case-insensitive "like", similar to Postgres <tt>ilike</tt>
* operator
* Apply an "equal" constraint to the named property. If the value
* is null, instead apply "is null".
*
* @param propertyName
* @param value
* @return Criterion
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return The Criterion
*
* @see #eq
* @see #isNull
*/
public static Criterion ilike(String propertyName, String value, MatchMode matchMode) {
return new LikeExpression(propertyName, value, matchMode, null, true);
public static Criterion eqOrIsNull(String propertyName, Object value) {
return value == null
? isNull( propertyName )
: eq( propertyName, value );
}
/**
* A case-insensitive "like", similar to Postgres <tt>ilike</tt>
* operator
* Apply a "not equal" constraint to the named property
*
* @param propertyName
* @param value
* @return Criterion
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return The Criterion
* @see SimpleExpression
*/
public static SimpleExpression ne(String propertyName, Object value) {
return new SimpleExpression( propertyName, value, "<>" );
}
/**
* Apply a "not equal" constraint to the named property. If the value
* is null, instead apply "is not null".
*
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return The Criterion
*
* @see #ne
* @see #isNotNull
*/
public static Criterion neOrIsNotNull(String propertyName, Object value) {
return value == null
? isNotNull( propertyName )
: ne( propertyName, value );
}
/**
* Apply a "like" constraint to the named property
*
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return The Criterion
*
* @see SimpleExpression
*/
public static SimpleExpression like(String propertyName, Object value) {
// todo : update this to use LikeExpression
return new SimpleExpression( propertyName, value, " like " );
}
/**
* Apply a "like" constraint to the named property using the provided match mode
*
* @param propertyName The name of the property
* @param value The value to use in comparison
* @param matchMode The match mode to use in comparison
*
* @return The Criterion
*
* @see SimpleExpression
*/
public static SimpleExpression like(String propertyName, String value, MatchMode matchMode) {
// todo : update this to use LikeExpression
return new SimpleExpression( propertyName, matchMode.toMatchString( value ), " like " );
}
/**
* A case-insensitive "like" (similar to Postgres <tt>ilike</tt> operator)
*
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return The Criterion
*
* @see LikeExpression
*/
public static Criterion ilike(String propertyName, Object value) {
if ( value == null ) {
@ -144,126 +165,239 @@ public class Restrictions {
return ilike( propertyName, value.toString(), MatchMode.EXACT );
}
/**
* A case-insensitive "like" (similar to Postgres <tt>ilike</tt> operator) using the provided match mode
*
* @param propertyName The name of the property
* @param value The value to use in comparison
* @param matchMode The match mode to use in comparison
*
* @return The Criterion
*
* @see LikeExpression
*/
public static Criterion ilike(String propertyName, String value, MatchMode matchMode) {
if ( value == null ) {
throw new IllegalArgumentException( "Comparison value passed to ilike cannot be null" );
}
return new LikeExpression( propertyName, value, matchMode, null, true );
}
/**
* Apply a "greater than" constraint to the named property
* @param propertyName
* @param value
* @return Criterion
*
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return The Criterion
*
* @see SimpleExpression
*/
public static SimpleExpression gt(String propertyName, Object value) {
return new SimpleExpression(propertyName, value, ">");
return new SimpleExpression( propertyName, value, ">" );
}
/**
* Apply a "less than" constraint to the named property
* @param propertyName
* @param value
* @return Criterion
*
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return The Criterion
*
* @see SimpleExpression
*/
public static SimpleExpression lt(String propertyName, Object value) {
return new SimpleExpression(propertyName, value, "<");
return new SimpleExpression( propertyName, value, "<" );
}
/**
* Apply a "less than or equal" constraint to the named property
* @param propertyName
* @param value
* @return Criterion
*
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return The Criterion
*
* @see SimpleExpression
*/
public static SimpleExpression le(String propertyName, Object value) {
return new SimpleExpression(propertyName, value, "<=");
return new SimpleExpression( propertyName, value, "<=" );
}
/**
* Apply a "greater than or equal" constraint to the named property
* @param propertyName
* @param value
* @return Criterion
*
* @param propertyName The name of the property
* @param value The value to use in comparison
*
* @return The Criterion
*
* @see SimpleExpression
*/
public static SimpleExpression ge(String propertyName, Object value) {
return new SimpleExpression(propertyName, value, ">=");
return new SimpleExpression( propertyName, value, ">=" );
}
/**
* Apply a "between" constraint to the named property
* @param propertyName
* @param lo value
* @param hi value
* @return Criterion
*
* @param propertyName The name of the property
* @param lo The low value
* @param hi The high value
*
* @return The Criterion
*
* @see BetweenExpression
*/
public static Criterion between(String propertyName, Object lo, Object hi) {
return new BetweenExpression(propertyName, lo, hi);
return new BetweenExpression( propertyName, lo, hi );
}
/**
* Apply an "in" constraint to the named property
* @param propertyName
* @param values
* @return Criterion
* Apply an "in" constraint to the named property.
*
* @param propertyName The name of the property
* @param values The literal values to use in the IN restriction
*
* @return The Criterion
*
* @see InExpression
*/
public static Criterion in(String propertyName, Object[] values) {
return new InExpression(propertyName, values);
return new InExpression( propertyName, values );
}
/**
* Apply an "in" constraint to the named property
* @param propertyName
* @param values
* @return Criterion
* Apply an "in" constraint to the named property.
*
* @param propertyName The name of the property
* @param values The literal values to use in the IN restriction
*
* @return The Criterion
*
* @see InExpression
*/
public static Criterion in(String propertyName, Collection values) {
return new InExpression( propertyName, values.toArray() );
}
/**
* Apply an "is null" constraint to the named property
*
* @param propertyName The name of the property
*
* @return Criterion
*
* @see NullExpression
*/
public static Criterion isNull(String propertyName) {
return new NullExpression(propertyName);
}
/**
* Apply an "equal" constraint to two properties
*/
public static PropertyExpression eqProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression(propertyName, otherPropertyName, "=");
}
/**
* Apply a "not equal" constraint to two properties
*/
public static PropertyExpression neProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression(propertyName, otherPropertyName, "<>");
}
/**
* Apply a "less than" constraint to two properties
*/
public static PropertyExpression ltProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression(propertyName, otherPropertyName, "<");
}
/**
* Apply a "less than or equal" constraint to two properties
*/
public static PropertyExpression leProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression(propertyName, otherPropertyName, "<=");
}
/**
* Apply a "greater than" constraint to two properties
*/
public static PropertyExpression gtProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression(propertyName, otherPropertyName, ">");
}
/**
* Apply a "greater than or equal" constraint to two properties
*/
public static PropertyExpression geProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression(propertyName, otherPropertyName, ">=");
return new NullExpression( propertyName );
}
/**
* Apply an "is not null" constraint to the named property
* @return Criterion
*
* @param propertyName The property name
*
* @return The Criterion
*
* @see NotNullExpression
*/
public static Criterion isNotNull(String propertyName) {
return new NotNullExpression(propertyName);
return new NotNullExpression( propertyName );
}
/**
* Apply an "equal" constraint to two properties
*
* @param propertyName One property name
* @param otherPropertyName The other property name
*
* @return The Criterion
*
* @see PropertyExpression
*/
public static PropertyExpression eqProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression( propertyName, otherPropertyName, "=" );
}
/**
* Apply a "not equal" constraint to two properties
*
* @param propertyName One property name
* @param otherPropertyName The other property name
*
* @return The Criterion
*
* @see PropertyExpression
*/
public static PropertyExpression neProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression( propertyName, otherPropertyName, "<>" );
}
/**
* Apply a "less than" constraint to two properties
*
* @param propertyName One property name
* @param otherPropertyName The other property name
*
* @return The Criterion
*
* @see PropertyExpression
*/
public static PropertyExpression ltProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression( propertyName, otherPropertyName, "<" );
}
/**
* Apply a "less than or equal" constraint to two properties
*
* @param propertyName One property name
* @param otherPropertyName The other property name
*
* @return The Criterion
*
* @see PropertyExpression
*/
public static PropertyExpression leProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression( propertyName, otherPropertyName, "<=" );
}
/**
* Apply a "greater than" constraint to two properties
*
* @param propertyName One property name
* @param otherPropertyName The other property name
*
* @return The Criterion
*
* @see PropertyExpression
*/
public static PropertyExpression gtProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression( propertyName, otherPropertyName, ">" );
}
/**
* Apply a "greater than or equal" constraint to two properties
*
* @param propertyName One property name
* @param otherPropertyName The other property name
*
* @return The Criterion
*
* @see PropertyExpression
*/
public static PropertyExpression geProperty(String propertyName, String otherPropertyName) {
return new PropertyExpression( propertyName, otherPropertyName, ">=" );
}
/**
* Return the conjuction of two expressions
*
* @param lhs
* @param rhs
* @return Criterion
* @param lhs One expression
* @param rhs The other expression
*
* @return The Criterion
*/
public static LogicalExpression and(Criterion lhs, Criterion rhs) {
return new LogicalExpression(lhs, rhs, "and");
@ -276,24 +410,21 @@ public class Restrictions {
* @return The conjunction
*/
public static Conjunction and(Criterion... predicates) {
Conjunction conjunction = conjunction();
if ( predicates != null ) {
for ( Criterion predicate : predicates ) {
conjunction.add( predicate );
}
}
return conjunction;
return conjunction( predicates );
}
/**
* Return the disjuction of two expressions
*
* @param lhs
* @param rhs
* @return Criterion
* @param lhs One expression
* @param rhs The other expression
*
* @return The Criterion
*/
public static LogicalExpression or(Criterion lhs, Criterion rhs) {
return new LogicalExpression(lhs, rhs, "or");
return new LogicalExpression( lhs, rhs, "or" );
}
/**
* Return the disjuction of multiple expressions
*
@ -302,62 +433,72 @@ public class Restrictions {
* @return The conjunction
*/
public static Disjunction or(Criterion... predicates) {
Disjunction disjunction = disjunction();
if ( predicates != null ) {
for ( Criterion predicate : predicates ) {
disjunction.add( predicate );
}
}
return disjunction;
}
/**
* Return the negation of an expression
*
* @param expression
* @return Criterion
*/
public static Criterion not(Criterion expression) {
return new NotExpression(expression);
}
/**
* Apply a constraint expressed in SQL, with the given JDBC
* parameters. Any occurrences of <tt>{alias}</tt> will be
* replaced by the table alias.
*
* @param sql
* @param values
* @param types
* @return Criterion
*/
public static Criterion sqlRestriction(String sql, Object[] values, Type[] types) {
return new SQLCriterion(sql, values, types);
}
/**
* Apply a constraint expressed in SQL, with the given JDBC
* parameter. Any occurrences of <tt>{alias}</tt> will be replaced
* by the table alias.
*
* @param sql
* @param value
* @param type
* @return Criterion
*/
public static Criterion sqlRestriction(String sql, Object value, Type type) {
return new SQLCriterion(sql, new Object[] { value }, new Type[] { type } );
}
/**
* Apply a constraint expressed in SQL. Any occurrences of <tt>{alias}</tt>
* will be replaced by the table alias.
*
* @param sql
* @return Criterion
*/
public static Criterion sqlRestriction(String sql) {
return new SQLCriterion(sql, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY);
return disjunction( predicates );
}
/**
* Group expressions together in a single conjunction (A and B and C...)
* Return the negation of an expression
*
* @param expression The expression to be negated
*
* @return Criterion
*
* @see NotExpression
*/
public static Criterion not(Criterion expression) {
return new NotExpression( expression );
}
/**
* Create a restriction expressed in SQL with JDBC parameters. Any occurrences of <tt>{alias}</tt> will be
* replaced by the table alias.
*
* @param sql The SQL restriction
* @param values The parameter values
* @param types The parameter types
*
* @return The Criterion
*
* @see SQLCriterion
*/
public static Criterion sqlRestriction(String sql, Object[] values, Type[] types) {
return new SQLCriterion( sql, values, types );
}
/**
* Create a restriction expressed in SQL with one JDBC parameter. Any occurrences of <tt>{alias}</tt> will be
* replaced by the table alias.
*
* @param sql The SQL restriction
* @param value The parameter value
* @param type The parameter type
*
* @return The Criterion
*
* @see SQLCriterion
*/
public static Criterion sqlRestriction(String sql, Object value, Type type) {
return new SQLCriterion( sql, value, type );
}
/**
* Apply a constraint expressed in SQL with no JDBC parameters. Any occurrences of <tt>{alias}</tt> will be
* replaced by the table alias.
*
* @param sql The SQL restriction
*
* @return The Criterion
*
* @see SQLCriterion
*/
public static Criterion sqlRestriction(String sql) {
return new SQLCriterion( sql );
}
/**
* Group expressions together in a single conjunction (A and B and C...).
*
* This form creates an empty conjunction. See {@link Conjunction#add(Criterion)}
*
* @return Conjunction
*/
@ -366,7 +507,20 @@ public class Restrictions {
}
/**
* Group expressions together in a single disjunction (A or B or C...)
* Group expressions together in a single conjunction (A and B and C...).
*
* @param conditions The initial set of conditions to put into the Conjunction
*
* @return Conjunction
*/
public static Conjunction conjunction(Criterion... conditions) {
return new Conjunction( conditions );
}
/**
* Group expressions together in a single disjunction (A or B or C...).
*
* This form creates an empty disjunction. See {@link Disjunction#add(Criterion)}
*
* @return Conjunction
*/
@ -375,89 +529,169 @@ public class Restrictions {
}
/**
* Apply an "equals" constraint to each property in the
* key set of a <tt>Map</tt>
* Group expressions together in a single disjunction (A or B or C...).
*
* @param conditions The initial set of conditions to put into the Disjunction
*
* @return Conjunction
*/
public static Disjunction disjunction(Criterion... conditions) {
return new Disjunction( conditions );
}
/**
* Apply an "equals" constraint to each property in the key set of a <tt>Map</tt>
*
* @param propertyNameValues a map from property names to values
*
* @return Criterion
*
* @see Conjunction
*/
public static Criterion allEq(Map propertyNameValues) {
Conjunction conj = conjunction();
Iterator iter = propertyNameValues.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry me = (Map.Entry) iter.next();
conj.add( eq( (String) me.getKey(), me.getValue() ) );
@SuppressWarnings("UnusedDeclaration")
public static Criterion allEq(Map<String,?> propertyNameValues) {
final Conjunction conj = conjunction();
for ( Map.Entry<String,?> entry : propertyNameValues.entrySet() ) {
conj.add( eq( entry.getKey(), entry.getValue() ) );
}
return conj;
}
/**
* Constrain a collection valued property to be empty
*
* @param propertyName The name of the collection property
*
* @return The Criterion
*
* @see EmptyExpression
*/
public static Criterion isEmpty(String propertyName) {
return new EmptyExpression(propertyName);
return new EmptyExpression( propertyName );
}
/**
* Constrain a collection valued property to be non-empty
*
* @param propertyName The name of the collection property
*
* @return The Criterion
*
* @see NotEmptyExpression
*/
public static Criterion isNotEmpty(String propertyName) {
return new NotEmptyExpression(propertyName);
return new NotEmptyExpression( propertyName );
}
/**
* Constrain a collection valued property by size
*
* @param propertyName The name of the collection property
* @param size The size to use in comparison
*
* @return The Criterion
*
* @see SizeExpression
*/
public static Criterion sizeEq(String propertyName, int size) {
return new SizeExpression(propertyName, size, "=");
return new SizeExpression( propertyName, size, "=" );
}
/**
* Constrain a collection valued property by size
*
* @param propertyName The name of the collection property
* @param size The size to use in comparison
*
* @return The Criterion
*
* @see SizeExpression
*/
@SuppressWarnings("UnusedDeclaration")
public static Criterion sizeNe(String propertyName, int size) {
return new SizeExpression(propertyName, size, "<>");
return new SizeExpression( propertyName, size, "<>" );
}
/**
* Constrain a collection valued property by size
*
* @param propertyName The name of the collection property
* @param size The size to use in comparison
*
* @return The Criterion
*
* @see SizeExpression
*/
@SuppressWarnings("UnusedDeclaration")
public static Criterion sizeGt(String propertyName, int size) {
return new SizeExpression(propertyName, size, "<");
return new SizeExpression( propertyName, size, "<" );
}
/**
* Constrain a collection valued property by size
*
* @param propertyName The name of the collection property
* @param size The size to use in comparison
*
* @return The Criterion
*
* @see SizeExpression
*/
@SuppressWarnings("UnusedDeclaration")
public static Criterion sizeLt(String propertyName, int size) {
return new SizeExpression(propertyName, size, ">");
return new SizeExpression( propertyName, size, ">" );
}
/**
* Constrain a collection valued property by size
*
* @param propertyName The name of the collection property
* @param size The size to use in comparison
*
* @return The Criterion
*
* @see SizeExpression
*/
@SuppressWarnings("UnusedDeclaration")
public static Criterion sizeGe(String propertyName, int size) {
return new SizeExpression(propertyName, size, "<=");
return new SizeExpression( propertyName, size, "<=" );
}
/**
* Constrain a collection valued property by size
*
* @param propertyName The name of the collection property
* @param size The size to use in comparison
*
* @return The Criterion
*
* @see SizeExpression
*/
@SuppressWarnings("UnusedDeclaration")
public static Criterion sizeLe(String propertyName, int size) {
return new SizeExpression(propertyName, size, ">=");
return new SizeExpression( propertyName, size, ">=" );
}
/**
* Consider using any of the natural id based loading stuff from session instead, especially in cases
* where the restriction is the full set of natural id values.
*
* @see Session#byNaturalId(Class)
* @see Session#byNaturalId(String)
* @see Session#bySimpleNaturalId(Class)
* @see Session#bySimpleNaturalId(String)
* @return The Criterion
*
* @see NaturalIdentifier
*
* @see org.hibernate.Session#byNaturalId(Class)
* @see org.hibernate.Session#byNaturalId(String)
* @see org.hibernate.Session#bySimpleNaturalId(Class)
* @see org.hibernate.Session#bySimpleNaturalId(String)
*/
public static NaturalIdentifier naturalId() {
return new NaturalIdentifier();
}
protected Restrictions() {
// cannot be instantiated, but needs to be protected so Expression can extend it
}
}

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* Copyright (c) 2010, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -22,11 +22,13 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.criterion;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.dialect.function.SQLFunctionRegistry;
import org.hibernate.type.Type;
/**
@ -35,30 +37,30 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public class RowCountProjection extends SimpleProjection {
private static List ARGS = java.util.Collections.singletonList( "*" );
public String toString() {
return "count(*)";
}
private static final List ARGS = java.util.Collections.singletonList( "*" );
@Override
public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return new Type[] {
getFunction( criteriaQuery ).getReturnType( null, criteriaQuery.getFactory() )
};
final Type countFunctionReturnType = getFunction( criteriaQuery ).getReturnType( null, criteriaQuery.getFactory() );
return new Type[] { countFunctionReturnType };
}
@Override
public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) throws HibernateException {
return getFunction( criteriaQuery ).render( null, ARGS, criteriaQuery.getFactory() )
+ " as y" + position + '_';
return getFunction( criteriaQuery ).render( null, ARGS, criteriaQuery.getFactory() ) + " as y" + position + '_';
}
protected SQLFunction getFunction(CriteriaQuery criteriaQuery) {
SQLFunction function = criteriaQuery.getFactory()
.getSqlFunctionRegistry()
.findSQLFunction( "count" );
final SQLFunctionRegistry sqlFunctionRegistry = criteriaQuery.getFactory().getSqlFunctionRegistry();
final SQLFunction function = sqlFunctionRegistry.findSQLFunction( "count" );
if ( function == null ) {
throw new HibernateException( "Unable to locate count function mapping" );
}
return function;
}
@Override
public String toString() {
return "count(*)";
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,12 +20,10 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.type.Type;
@ -35,32 +33,39 @@ import org.hibernate.type.Type;
* alias of the root entity.
*/
public class SQLCriterion implements Criterion {
private final String sql;
private final TypedValue[] typedValues;
public String toSqlString(
Criteria criteria,
CriteriaQuery criteriaQuery)
throws HibernateException {
return StringHelper.replace( sql, "{alias}", criteriaQuery.getSQLAlias( criteria ) );
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return typedValues;
}
public String toString() {
return sql;
}
protected SQLCriterion(String sql, Object[] values, Type[] types) {
this.sql = sql;
typedValues = new TypedValue[values.length];
this.typedValues = new TypedValue[values.length];
for ( int i=0; i<typedValues.length; i++ ) {
typedValues[i] = new TypedValue( types[i], values[i] );
}
}
protected SQLCriterion(String sql, Object value, Type type) {
this.sql = sql;
this.typedValues = new TypedValue[] { new TypedValue( type, value ) };
}
protected SQLCriterion(String sql) {
this.sql = sql;
this.typedValues = new TypedValue[0];
}
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
return StringHelper.replace( sql, "{alias}", criteriaQuery.getSQLAlias( criteria ) );
}
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) {
return typedValues;
}
@Override
public String toString() {
return sql;
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,11 +20,10 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.criterion;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.type.Type;
@ -33,7 +32,6 @@ import org.hibernate.type.Type;
* alias of the root entity.
*/
public class SQLProjection implements Projection {
private final String sql;
private final String groupBy;
private final Type[] types;
@ -41,30 +39,8 @@ public class SQLProjection implements Projection {
private String[] columnAliases;
private boolean grouped;
public String toSqlString(
Criteria criteria,
int loc,
CriteriaQuery criteriaQuery)
throws HibernateException {
return StringHelper.replace( sql, "{alias}", criteriaQuery.getSQLAlias(criteria) );
}
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
return StringHelper.replace( groupBy, "{alias}", criteriaQuery.getSQLAlias( criteria ) );
}
public Type[] getTypes(Criteria crit, CriteriaQuery criteriaQuery)
throws HibernateException {
return types;
}
public String toString() {
return sql;
}
protected SQLProjection(String sql, String[] columnAliases, Type[] types) {
this(sql, null, columnAliases, types);
this( sql, null, columnAliases, types );
}
protected SQLProjection(String sql, String groupBy, String[] columnAliases, Type[] types) {
@ -76,23 +52,48 @@ public class SQLProjection implements Projection {
this.groupBy = groupBy;
}
@Override
public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery) {
return StringHelper.replace( sql, "{alias}", criteriaQuery.getSQLAlias( criteria ) );
}
@Override
public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
return StringHelper.replace( groupBy, "{alias}", criteriaQuery.getSQLAlias( criteria ) );
}
@Override
public Type[] getTypes(Criteria crit, CriteriaQuery criteriaQuery) {
return types;
}
@Override
public String toString() {
return sql;
}
@Override
public String[] getAliases() {
return aliases;
}
@Override
public String[] getColumnAliases(int loc) {
return columnAliases;
}
@Override
public boolean isGrouped() {
return grouped;
}
@Override
public Type[] getTypes(String alias, Criteria crit, CriteriaQuery criteriaQuery) {
return null; //unsupported
return null;
}
@Override
public String[] getColumnAliases(String alias, int loc) {
return null; //unsupported
return null;
}
}

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2012, Red Hat Inc. or third-party contributors as
* Copyright (c) 2008, 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -55,55 +55,6 @@ public class SimpleExpression implements Criterion {
this.op = op;
}
public SimpleExpression ignoreCase() {
ignoreCase = true;
return this;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
String[] columns = criteriaQuery.findColumns( propertyName, criteria );
Type type = criteriaQuery.getTypeUsingProjection( criteria, propertyName );
StringBuilder fragment = new StringBuilder();
if ( columns.length > 1 ) {
fragment.append( '(' );
}
SessionFactoryImplementor factory = criteriaQuery.getFactory();
int[] sqlTypes = type.sqlTypes( factory );
for ( int i = 0; i < columns.length; i++ ) {
boolean lower = ignoreCase &&
(sqlTypes[i] == Types.VARCHAR || sqlTypes[i] == Types.CHAR);
if ( lower ) {
fragment.append( factory.getDialect().getLowercaseFunction() )
.append( '(' );
}
fragment.append( columns[i] );
if ( lower ) {
fragment.append( ')' );
}
fragment.append( getOp() ).append( "?" );
if ( i < columns.length - 1 ) {
fragment.append( " and " );
}
}
if ( columns.length > 1 ) {
fragment.append( ')' );
}
return fragment.toString();
}
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
Object icvalue = ignoreCase ? value.toString().toLowerCase() : value;
return new TypedValue[] {criteriaQuery.getTypedValue( criteria, propertyName, icvalue )};
}
public String toString() {
return propertyName + getOp() + value;
}
protected final String getOp() {
return op;
}
@ -115,4 +66,58 @@ public class SimpleExpression implements Criterion {
public Object getValue() {
return value;
}
/**
* Make case insensitive. No effect for non-String values
*
* @return {@code this}, for method chaining
*/
public SimpleExpression ignoreCase() {
ignoreCase = true;
return this;
}
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
final Type type = criteriaQuery.getTypeUsingProjection( criteria, propertyName );
final StringBuilder fragment = new StringBuilder();
if ( columns.length > 1 ) {
fragment.append( '(' );
}
final SessionFactoryImplementor factory = criteriaQuery.getFactory();
final int[] sqlTypes = type.sqlTypes( factory );
for ( int i = 0; i < columns.length; i++ ) {
final boolean lower = ignoreCase && (sqlTypes[i] == Types.VARCHAR || sqlTypes[i] == Types.CHAR);
if ( lower ) {
fragment.append( factory.getDialect().getLowercaseFunction() ).append( '(' );
}
fragment.append( columns[i] );
if ( lower ) {
fragment.append( ')' );
}
fragment.append( getOp() ).append( "?" );
if ( i < columns.length - 1 ) {
fragment.append( " and " );
}
}
if ( columns.length > 1 ) {
fragment.append( ')' );
}
return fragment.toString();
}
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
final Object casedValue = ignoreCase ? value.toString().toLowerCase() : value;
return new TypedValue[] { criteriaQuery.getTypedValue( criteria, propertyName, casedValue ) };
}
@Override
public String toString() {
return propertyName + getOp() + value;
}
}

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