diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java
index 074f975994..d7be98e426 100644
--- a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java
+++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java
@@ -6,28 +6,15 @@
*/
package org.hibernate.loader.entity;
-import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
-import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.spi.LoadQueryInfluencers;
-import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
-import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.persister.entity.OuterJoinLoadable;
-import org.hibernate.type.AbstractType;
import org.hibernate.type.Type;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
/**
* Loads an entity instance using outerjoin fetching to fetch associated entities.
*
@@ -162,23 +149,14 @@ public class EntityLoader extends AbstractEntityLoader {
LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
super( persister, new NaturalIdType( persister, valueNullness ), factory, loadQueryInfluencers );
- EntityJoinWalker walker = new EntityJoinWalker(
+ EntityJoinWalker walker = new NaturalIdEntityJoinWalker(
persister,
- naturalIdColumns( valueNullness ),
+ valueNullness,
batchSize,
lockOptions,
factory,
loadQueryInfluencers
- ) {
- @Override
- protected StringBuilder whereString(String alias, String[] columnNames, int batchSize) {
- StringBuilder sql = super.whereString(alias, columnNames, batchSize);
- for (String nullCol : naturalIdColumns( ArrayHelper.negate( valueNullness ) ) ) {
- sql.append(" and ").append( getAlias() ).append('.').append(nullCol).append(" is null");
- }
- return sql;
- }
- };
+ );
initFromWalker( walker );
compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices();
postInstantiate();
@@ -194,17 +172,6 @@ public class EntityLoader extends AbstractEntityLoader {
}
}
- private String[] naturalIdColumns(boolean[] valueNullness) {
- int i = 0;
- List columns = new ArrayList<>();
- for ( int p : persister.getNaturalIdentifierProperties() ) {
- if ( !valueNullness[i++] ) {
- columns.addAll( Arrays.asList( persister.getPropertyColumnNames(p) ) );
- }
- }
- return columns.toArray(ArrayHelper.EMPTY_STRING_ARRAY);
- }
-
public Object loadByUniqueKey(SharedSessionContractImplementor session, Object key) {
return loadByUniqueKey( session, key, null );
}
@@ -223,117 +190,4 @@ public class EntityLoader extends AbstractEntityLoader {
return compositeKeyManyToOneTargetIndices;
}
- static class NaturalIdType extends AbstractType {
- private OuterJoinLoadable persister;
- private boolean[] valueNullness;
-
- NaturalIdType(OuterJoinLoadable persister, boolean[] valueNullness) {
- this.persister = persister;
- this.valueNullness = valueNullness;
- }
-
- @Override
- public int getColumnSpan(Mapping mapping) throws MappingException {
- int span = 0;
- int i = 0;
- for ( int p : persister.getNaturalIdentifierProperties() ) {
- if ( !valueNullness[i++] ) {
- span += persister.getPropertyColumnNames(p).length;
- }
- }
- return span;
- }
-
- @Override
- public int[] sqlTypes(Mapping mapping) throws MappingException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Size[] dictatedSizes(Mapping mapping) throws MappingException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Size[] defaultSizes(Mapping mapping) throws MappingException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Class getReturnedClass() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isDirty(Object oldState, Object currentState, boolean[] checkable, SharedSessionContractImplementor session)
- throws HibernateException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
- throws HibernateException, SQLException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner)
- throws HibernateException, SQLException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session)
- throws HibernateException, SQLException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
- throws HibernateException, SQLException {
- Object[] keys = (Object[]) value;
- int i = 0;
- for ( int p : persister.getNaturalIdentifierProperties() ) {
- if ( !valueNullness[i] ) {
- persister.getPropertyTypes()[p].nullSafeSet( st, keys[i], index++, session );
- }
- i++;
- }
- }
-
- @Override
- public String toLoggableString(Object value, SessionFactoryImplementor factory) {
- return "natural id";
- }
-
- @Override
- public String getName() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object deepCopy(Object value, SessionFactoryImplementor factory) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isMutable() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean[] toColumnNullness(Object value, Mapping mapping) {
- throw new UnsupportedOperationException();
- }
- }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java
new file mode 100644
index 0000000000..46ea96e9e5
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java
@@ -0,0 +1,56 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.loader.entity;
+
+import org.hibernate.LockOptions;
+import org.hibernate.MappingException;
+import org.hibernate.engine.spi.LoadQueryInfluencers;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.util.Arrays.asList;
+import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY;
+import static org.hibernate.internal.util.collections.ArrayHelper.negate;
+
+/**
+ * An {@link EntityJoinWalker} that uses 'is null' predicates to match
+ * null {@link org.hibernate.annotations.NaturalId} properties.
+ *
+ * @author Gavin King
+ */
+public class NaturalIdEntityJoinWalker extends EntityJoinWalker {
+
+ private static String[] naturalIdColumns(Loadable persister, boolean[] valueNullness) {
+ int i = 0;
+ List columns = new ArrayList<>();
+ for ( int p : persister.getNaturalIdentifierProperties() ) {
+ if ( !valueNullness[i++] ) {
+ columns.addAll( asList( persister.getPropertyColumnNames(p) ) );
+ }
+ }
+ return columns.toArray(EMPTY_STRING_ARRAY);
+ }
+
+ public NaturalIdEntityJoinWalker(
+ OuterJoinLoadable persister,
+ boolean[] valueNullness,
+ int batchSize,
+ LockOptions lockOptions,
+ SessionFactoryImplementor factory,
+ LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+ super(persister, naturalIdColumns( persister, valueNullness ), batchSize, lockOptions, factory, loadQueryInfluencers);
+ StringBuilder sql = new StringBuilder( getSQLString() );
+ for ( String nullCol : naturalIdColumns( getPersister(), negate( valueNullness ) ) ) {
+ sql.append(" and ").append( getAlias() ).append('.').append( nullCol ).append(" is null");
+ }
+ setSql( sql.toString() );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java
new file mode 100644
index 0000000000..c515660d5c
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java
@@ -0,0 +1,142 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.loader.entity;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.jdbc.Size;
+import org.hibernate.engine.spi.Mapping;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.type.AbstractType;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+
+/**
+ * Workaround for the fact that we don't have a well-defined Hibernate
+ * type when loading by multiple {@link org.hibernate.annotations.NaturalId}
+ * properties.
+ *
+ * @author Gavin King
+ */
+public class NaturalIdType extends AbstractType {
+ private OuterJoinLoadable persister;
+ private boolean[] valueNullness;
+
+ public NaturalIdType(OuterJoinLoadable persister, boolean[] valueNullness) {
+ this.persister = persister;
+ this.valueNullness = valueNullness;
+ }
+
+ @Override
+ public int getColumnSpan(Mapping mapping) throws MappingException {
+ int span = 0;
+ int i = 0;
+ for (int p : persister.getNaturalIdentifierProperties() ) {
+ if ( !valueNullness[i++] ) {
+ span += persister.getPropertyColumnNames(p).length;
+ }
+ }
+ return span;
+ }
+
+ @Override
+ public int[] sqlTypes(Mapping mapping) throws MappingException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Size[] dictatedSizes(Mapping mapping) throws MappingException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Size[] defaultSizes(Mapping mapping) throws MappingException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Class getReturnedClass() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isDirty(Object oldState, Object currentState, boolean[] checkable, SharedSessionContractImplementor session)
+ throws HibernateException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
+ throws HibernateException, SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner)
+ throws HibernateException, SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session)
+ throws HibernateException, SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
+ throws HibernateException, SQLException {
+ Object[] keys = (Object[]) value;
+ int i = 0;
+ for ( int p : persister.getNaturalIdentifierProperties() ) {
+ if ( !valueNullness[i] ) {
+ persister.getPropertyTypes()[p].nullSafeSet( st, keys[i], index++, session );
+ }
+ i++;
+ }
+ }
+
+ @Override
+ public String toLoggableString(Object value, SessionFactoryImplementor factory) {
+ return "natural id";
+ }
+
+ @Override
+ public String getName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object deepCopy(Object value, SessionFactoryImplementor factory) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMutable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean[] toColumnNullness(Object value, Mapping mapping) {
+ throw new UnsupportedOperationException();
+ }
+}