diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallback.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallback.java new file mode 100644 index 000000000..7d6f988d0 --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallback.java @@ -0,0 +1,71 @@ +/* + * Copyright 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.jdbc.core.convert; + +import org.springframework.data.mapping.PersistentPropertyAccessor; +import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.relational.core.conversion.MutableAggregateChange; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; +import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; +import org.springframework.data.relational.core.mapping.event.BeforeSaveCallback; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.util.Assert; + +/** + * Callback for generating identifier values through a database sequence. + * + * @author Mikhail Polivakha + * @author Mark Paluch + * @since 3.5 + */ +public class IdGeneratingEntityCallback implements BeforeSaveCallback { + + private final MappingContext, ? extends RelationalPersistentProperty> context; + private final SequenceEntityCallbackDelegate delegate; + + public IdGeneratingEntityCallback( + MappingContext, ? extends RelationalPersistentProperty> context, Dialect dialect, + NamedParameterJdbcOperations operations) { + + this.context = context; + this.delegate = new SequenceEntityCallbackDelegate(dialect, operations); + } + + @Override + public Object onBeforeSave(Object aggregate, MutableAggregateChange aggregateChange) { + + Assert.notNull(aggregate, "aggregate must not be null"); + + RelationalPersistentEntity entity = context.getRequiredPersistentEntity(aggregate.getClass()); + + if (!entity.hasIdProperty()) { + return aggregate; + } + + RelationalPersistentProperty property = entity.getRequiredIdProperty(); + PersistentPropertyAccessor accessor = entity.getPropertyAccessor(aggregate); + + if (!entity.isNew(aggregate) || delegate.hasValue(property, accessor) || !property.hasSequence()) { + return aggregate; + } + + delegate.generateSequenceValue(property, accessor); + + return accessor.getBean(); + } + +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SequenceEntityCallbackDelegate.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SequenceEntityCallbackDelegate.java new file mode 100644 index 000000000..00efd7fcf --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SequenceEntityCallbackDelegate.java @@ -0,0 +1,102 @@ +/* + * Copyright 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.jdbc.core.convert; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.mapping.PersistentPropertyAccessor; +import org.springframework.data.relational.core.dialect.Dialect; +import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; +import org.springframework.data.relational.core.sql.SqlIdentifier; +import org.springframework.data.util.ReflectionUtils; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.lang.Nullable; +import org.springframework.util.ClassUtils; +import org.springframework.util.NumberUtils; + +/** + * Support class for generating identifier values through a database sequence. + * + * @author Mikhail Polivakha + * @author Mark Paluch + * @since 3.5 + * @see org.springframework.data.relational.core.mapping.Sequence + */ +class SequenceEntityCallbackDelegate { + + private static final Log LOG = LogFactory.getLog(SequenceEntityCallbackDelegate.class); + private final static MapSqlParameterSource EMPTY_PARAMETERS = new MapSqlParameterSource(); + + private final Dialect dialect; + private final NamedParameterJdbcOperations operations; + + public SequenceEntityCallbackDelegate(Dialect dialect, NamedParameterJdbcOperations operations) { + this.dialect = dialect; + this.operations = operations; + } + + @SuppressWarnings("unchecked") + protected void generateSequenceValue(RelationalPersistentProperty property, + PersistentPropertyAccessor accessor) { + + Object sequenceValue = getSequenceValue(property); + + if (sequenceValue == null) { + return; + } + + Class targetType = ClassUtils.resolvePrimitiveIfNecessary(property.getType()); + if (sequenceValue instanceof Number && Number.class.isAssignableFrom(targetType)) { + sequenceValue = NumberUtils.convertNumberToTargetClass((Number) sequenceValue, + (Class) targetType); + } + + accessor.setProperty(property, sequenceValue); + } + + protected boolean hasValue(PersistentProperty property, PersistentPropertyAccessor propertyAccessor) { + + Object identifier = propertyAccessor.getProperty(property); + + if (property.getType().isPrimitive()) { + + Object primitiveDefault = ReflectionUtils.getPrimitiveDefault(property.getType()); + return !primitiveDefault.equals(identifier); + } + + return identifier != null; + } + + private @Nullable Object getSequenceValue(RelationalPersistentProperty property) { + + SqlIdentifier sequence = property.getSequence(); + + if (sequence != null && !dialect.getIdGeneration().sequencesSupported()) { + LOG.warn(""" + Aggregate type '%s' is marked for sequence usage but configured dialect '%s' + does not support sequences. Falling back to identity columns. + """.formatted(property.getOwner().getType(), ClassUtils.getQualifiedName(dialect.getClass()))); + return null; + } + + String sql = dialect.getIdGeneration().createSequenceQuery(sequence); + return operations.queryForObject(sql, EMPTY_PARAMETERS, (rs, rowNum) -> rs.getObject(1)); + } + +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/mapping/IdGeneratingBeforeSaveCallback.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/mapping/IdGeneratingBeforeSaveCallback.java deleted file mode 100644 index a05503eba..000000000 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/mapping/IdGeneratingBeforeSaveCallback.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.springframework.data.jdbc.core.mapping; - -import java.util.Optional; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.data.mapping.PersistentProperty; -import org.springframework.data.mapping.PersistentPropertyAccessor; -import org.springframework.data.mapping.context.MappingContext; -import org.springframework.data.relational.core.conversion.MutableAggregateChange; -import org.springframework.data.relational.core.dialect.Dialect; -import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; -import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; -import org.springframework.data.relational.core.mapping.event.BeforeSaveCallback; -import org.springframework.data.relational.core.sql.SqlIdentifier; -import org.springframework.data.util.ReflectionUtils; -import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.NumberUtils; - -/** - * Callback for generating identifier values through a database sequence. - * - * @author Mikhail Polivakha - * @author Mark Paluch - * @since 3.5 - * @see org.springframework.data.relational.core.mapping.Sequence - */ -public class IdGeneratingBeforeSaveCallback implements BeforeSaveCallback { - - private static final Log LOG = LogFactory.getLog(IdGeneratingBeforeSaveCallback.class); - private final static MapSqlParameterSource EMPTY_PARAMETERS = new MapSqlParameterSource(); - - private final MappingContext, ? extends RelationalPersistentProperty> mappingContext; - private final Dialect dialect; - private final NamedParameterJdbcOperations operations; - - public IdGeneratingBeforeSaveCallback( - MappingContext, ? extends RelationalPersistentProperty> mappingContext, - Dialect dialect, NamedParameterJdbcOperations operations) { - this.mappingContext = mappingContext; - this.dialect = dialect; - this.operations = operations; - } - - @Override - public Object onBeforeSave(Object aggregate, MutableAggregateChange aggregateChange) { - - Assert.notNull(aggregate, "aggregate must not be null"); - - RelationalPersistentEntity entity = mappingContext.getRequiredPersistentEntity(aggregate.getClass()); - - if (!entity.hasIdProperty()) { - return aggregate; - } - - RelationalPersistentProperty idProperty = entity.getRequiredIdProperty(); - PersistentPropertyAccessor accessor = entity.getPropertyAccessor(aggregate); - - if (!entity.isNew(aggregate) || hasIdentifierValue(idProperty, accessor)) { - return aggregate; - } - - potentiallyFetchIdFromSequence(idProperty, entity, accessor); - return accessor.getBean(); - } - - private boolean hasIdentifierValue(PersistentProperty idProperty, - PersistentPropertyAccessor propertyAccessor) { - - Object identifier = propertyAccessor.getProperty(idProperty); - - if (idProperty.getType().isPrimitive()) { - - Object primitiveDefault = ReflectionUtils.getPrimitiveDefault(idProperty.getType()); - return !primitiveDefault.equals(identifier); - } - - return identifier != null; - } - - @SuppressWarnings("unchecked") - private void potentiallyFetchIdFromSequence(PersistentProperty idProperty, - RelationalPersistentEntity persistentEntity, PersistentPropertyAccessor accessor) { - - Optional idSequence = persistentEntity.getIdSequence(); - - if (idSequence.isPresent() && !dialect.getIdGeneration().sequencesSupported()) { - LOG.warn(""" - Aggregate type '%s' is marked for sequence usage but configured dialect '%s' - does not support sequences. Falling back to identity columns. - """.formatted(persistentEntity.getType(), ClassUtils.getQualifiedName(dialect.getClass()))); - return; - } - - idSequence.map(s -> dialect.getIdGeneration().createSequenceQuery(s)).ifPresent(sql -> { - - Object idValue = operations.queryForObject(sql, EMPTY_PARAMETERS, (rs, rowNum) -> rs.getObject(1)); - - Class targetType = ClassUtils.resolvePrimitiveIfNecessary(idProperty.getType()); - if (idValue instanceof Number && Number.class.isAssignableFrom(targetType)) { - accessor.setProperty(idProperty, - NumberUtils.convertNumberToTargetClass((Number) idValue, (Class) targetType)); - } else { - accessor.setProperty(idProperty, idValue); - } - }); - } -} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java index 0a8a1c7a8..ac4483069 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java @@ -25,6 +25,7 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; @@ -38,7 +39,6 @@ import org.springframework.data.jdbc.core.JdbcAggregateOperations; import org.springframework.data.jdbc.core.JdbcAggregateTemplate; import org.springframework.data.jdbc.core.convert.*; import org.springframework.data.jdbc.core.dialect.JdbcDialect; -import org.springframework.data.jdbc.core.mapping.IdGeneratingBeforeSaveCallback; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes; import org.springframework.data.mapping.model.SimpleTypeHolder; @@ -121,7 +121,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware { } /** - * Creates a {@link IdGeneratingBeforeSaveCallback} bean using the configured + * Creates a {@link IdGeneratingEntityCallback} bean using the configured * {@link #jdbcMappingContext(Optional, JdbcCustomConversions, RelationalManagedTypes)} and * {@link #jdbcDialect(NamedParameterJdbcOperations)}. * @@ -129,9 +129,9 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware { * @since 3.5 */ @Bean - public IdGeneratingBeforeSaveCallback idGeneratingBeforeSaveCallback(JdbcMappingContext mappingContext, + public IdGeneratingEntityCallback idGeneratingBeforeSaveCallback(JdbcMappingContext mappingContext, NamedParameterJdbcOperations operations, Dialect dialect) { - return new IdGeneratingBeforeSaveCallback(mappingContext, dialect, operations); + return new IdGeneratingEntityCallback(mappingContext, dialect, operations); } /** diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/IdGeneratingBeforeSaveCallbackTest.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallbackTest.java similarity index 86% rename from spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/IdGeneratingBeforeSaveCallbackTest.java rename to spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallbackTest.java index aaea4ad03..240d47f59 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/IdGeneratingBeforeSaveCallbackTest.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/IdGeneratingEntityCallbackTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 the original author or authors. + * Copyright 2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.jdbc.core.mapping; +package org.springframework.data.jdbc.core.convert; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -41,13 +41,13 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.SqlParameterSource; /** - * Unit tests for {@link IdGeneratingBeforeSaveCallback} + * Unit tests for {@link IdGeneratingEntityCallback} * * @author Mikhail Polivakha * @author Mark Paluch */ @MockitoSettings(strictness = Strictness.LENIENT) -class IdGeneratingBeforeSaveCallbackTest { +class IdGeneratingEntityCallbackTest { @Mock NamedParameterJdbcOperations operations; RelationalMappingContext relationalMappingContext; @@ -64,7 +64,7 @@ class IdGeneratingBeforeSaveCallbackTest { NamedParameterJdbcOperations operations = mock(NamedParameterJdbcOperations.class); - IdGeneratingBeforeSaveCallback subject = new IdGeneratingBeforeSaveCallback(relationalMappingContext, + IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, MySqlDialect.INSTANCE, operations); EntityWithSequence processed = (EntityWithSequence) subject.onBeforeSave(new EntityWithSequence(), @@ -76,7 +76,7 @@ class IdGeneratingBeforeSaveCallbackTest { @Test // GH-1923 void entityIsNotMarkedWithTargetSequence() { - IdGeneratingBeforeSaveCallback subject = new IdGeneratingBeforeSaveCallback(relationalMappingContext, + IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, MySqlDialect.INSTANCE, operations); NoSequenceEntity processed = (NoSequenceEntity) subject.onBeforeSave(new NoSequenceEntity(), @@ -92,7 +92,7 @@ class IdGeneratingBeforeSaveCallbackTest { when(operations.queryForObject(anyString(), any(SqlParameterSource.class), any(RowMapper.class))) .thenReturn(generatedId); - IdGeneratingBeforeSaveCallback subject = new IdGeneratingBeforeSaveCallback(relationalMappingContext, + IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, PostgresDialect.INSTANCE, operations); EntityWithSequence processed = (EntityWithSequence) subject.onBeforeSave(new EntityWithSequence(), @@ -108,7 +108,7 @@ class IdGeneratingBeforeSaveCallbackTest { when(operations.queryForObject(anyString(), any(SqlParameterSource.class), any(RowMapper.class))) .thenReturn(generatedId); - IdGeneratingBeforeSaveCallback subject = new IdGeneratingBeforeSaveCallback(relationalMappingContext, + IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, PostgresDialect.INSTANCE, operations); EntityWithIntSequence processed = (EntityWithIntSequence) subject.onBeforeSave(new EntityWithIntSequence(), @@ -124,7 +124,7 @@ class IdGeneratingBeforeSaveCallbackTest { when(operations.queryForObject(anyString(), any(SqlParameterSource.class), any(RowMapper.class))) .thenReturn(generatedId); - IdGeneratingBeforeSaveCallback subject = new IdGeneratingBeforeSaveCallback(relationalMappingContext, + IdGeneratingEntityCallback subject = new IdGeneratingEntityCallback(relationalMappingContext, PostgresDialect.INSTANCE, operations); EntityWithUuidSequence processed = (EntityWithUuidSequence) subject.onBeforeSave(new EntityWithUuidSequence(), diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java index 0e8ece8be..75fdc528a 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java @@ -35,7 +35,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceCreator; import org.springframework.data.annotation.Transient; import org.springframework.data.domain.Persistable; -import org.springframework.data.jdbc.core.mapping.IdGeneratingBeforeSaveCallback; +import org.springframework.data.jdbc.core.convert.IdGeneratingEntityCallback; import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository; import org.springframework.data.jdbc.testing.IntegrationTest; @@ -66,7 +66,7 @@ class JdbcRepositoryIdGenerationIntegrationTests { @Autowired SimpleSeqRepository simpleSeqRepository; @Autowired PersistableSeqRepository persistableSeqRepository; @Autowired PrimitiveIdSeqRepository primitiveIdSeqRepository; - @Autowired IdGeneratingBeforeSaveCallback idGeneratingCallback; + @Autowired IdGeneratingEntityCallback idGeneratingCallback; @Test // DATAJDBC-98 void idWithoutSetterGetsSet() { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java index e6ffebf37..ea3e5482c 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java @@ -24,6 +24,7 @@ import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mockito.Mockito; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -37,7 +38,6 @@ import org.springframework.context.annotation.Profile; import org.springframework.data.convert.CustomConversions; import org.springframework.data.jdbc.core.convert.*; import org.springframework.data.jdbc.core.dialect.JdbcDialect; -import org.springframework.data.jdbc.core.mapping.IdGeneratingBeforeSaveCallback; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes; import org.springframework.data.jdbc.repository.config.DialectResolver; @@ -45,7 +45,6 @@ import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.mapping.callback.EntityCallback; import org.springframework.data.mapping.callback.EntityCallbacks; import org.springframework.data.mapping.model.SimpleTypeHolder; -import org.springframework.data.relational.RelationalManagedTypes; import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.mapping.DefaultNamingStrategy; import org.springframework.data.relational.core.mapping.NamingStrategy; @@ -182,15 +181,15 @@ public class TestConfiguration { } /** - * Creates a {@link IdGeneratingBeforeSaveCallback} bean using the configured + * Creates a {@link IdGeneratingEntityCallback} bean using the configured * {@link #jdbcDialect(NamedParameterJdbcOperations)}. * * @return must not be {@literal null}. */ @Bean - public IdGeneratingBeforeSaveCallback idGeneratingBeforeSaveCallback(JdbcMappingContext mappingContext, + public IdGeneratingEntityCallback idGeneratingBeforeSaveCallback(JdbcMappingContext mappingContext, NamedParameterJdbcOperations operations, Dialect dialect) { - return Mockito.spy(new IdGeneratingBeforeSaveCallback(mappingContext, dialect, operations)); + return Mockito.spy(new IdGeneratingEntityCallback(mappingContext, dialect, operations)); } @Bean diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/IdValueSource.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/IdValueSource.java index 047fa4353..d863d8240 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/IdValueSource.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/IdValueSource.java @@ -49,12 +49,13 @@ public enum IdValueSource { */ public static IdValueSource forInstance(Object instance, RelationalPersistentEntity persistentEntity) { - if (persistentEntity.getIdSequence().isPresent()) { + RelationalPersistentProperty idProperty = persistentEntity.getIdProperty(); + + if (idProperty != null && idProperty.hasSequence()) { return IdValueSource.PROVIDED; } Object idValue = persistentEntity.getIdentifierAccessor(instance).getIdentifier(); - RelationalPersistentProperty idProperty = persistentEntity.getIdProperty(); if (idProperty == null) { return IdValueSource.NONE; } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentEntity.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentEntity.java index cc84a9501..99b48363f 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentEntity.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentEntity.java @@ -17,8 +17,6 @@ package org.springframework.data.relational.core.mapping; import java.util.Optional; -import org.springframework.core.annotation.MergedAnnotation; -import org.springframework.core.annotation.MergedAnnotations; import org.springframework.data.mapping.model.BasicPersistentEntity; import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.data.util.Lazy; @@ -47,9 +45,6 @@ class BasicRelationalPersistentEntity extends BasicPersistentEntity tableName; private final @Nullable Expression tableNameExpression; - - private final Lazy idSequenceName; - private final Lazy> schemaName; private final @Nullable Expression schemaNameExpression; private final ExpressionEvaluator expressionEvaluator; @@ -91,8 +86,6 @@ class BasicRelationalPersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity getIdSequence() { - return idSequenceName.getOptional(); - } - @Override public String toString() { return String.format("BasicRelationalPersistentEntity<%s>", getType()); } - private @Nullable SqlIdentifier determineSequenceName() { - - RelationalPersistentProperty idProperty = getIdProperty(); - - if (idProperty != null && idProperty.isAnnotationPresent(Sequence.class)) { - - Sequence requiredAnnotation = idProperty.getRequiredAnnotation(Sequence.class); - - MergedAnnotation targetSequence = MergedAnnotations.from(requiredAnnotation) - .get(Sequence.class); - - String sequence = targetSequence.getString("sequence"); - String schema = targetSequence.getString("schema"); - - SqlIdentifier sequenceIdentifier = SqlIdentifier.quoted(sequence); - if (StringUtils.hasText(schema)) { - sequenceIdentifier = SqlIdentifier.from(SqlIdentifier.quoted(schema), sequenceIdentifier); - } - - return sequenceIdentifier; - } else { - return null; - } - } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java index 4aa0fe335..0538a9810 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java @@ -52,12 +52,13 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent private final Lazy columnName; private final boolean hasExplicitColumnName; private final @Nullable Expression columnNameExpression; + private final SqlIdentifier sequence; private final Lazy> collectionIdColumnName; private final Lazy collectionKeyColumnName; private final @Nullable Expression collectionKeyColumnNameExpression; private final boolean isEmbedded; - private final String embeddedPrefix; + private final NamingStrategy namingStrategy; private boolean forceQuote = true; private ExpressionEvaluator expressionEvaluator = new ExpressionEvaluator(EvaluationContextProvider.DEFAULT); @@ -80,7 +81,6 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent Assert.notNull(namingStrategy, "NamingStrategy must not be null"); this.isEmbedded = isAnnotationPresent(Embedded.class); - this.embeddedPrefix = Optional.ofNullable(findAnnotation(Embedded.class)) // .map(Embedded::prefix) // .orElse(""); @@ -126,6 +126,8 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent this.columnNameExpression = null; } + this.sequence = determineSequenceName(); + if (collectionIdColumnName == null) { collectionIdColumnName = Lazy.of(Optional.empty()); } @@ -269,8 +271,34 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent return findAnnotation(InsertOnlyProperty.class) != null; } + @Nullable + @Override + public SqlIdentifier getSequence() { + return this.sequence; + } + private boolean isListLike() { return isCollectionLike() && !Set.class.isAssignableFrom(this.getType()); } + private @Nullable SqlIdentifier determineSequenceName() { + + if (isAnnotationPresent(Sequence.class)) { + + Sequence annotation = getRequiredAnnotation(Sequence.class); + + String sequence = annotation.sequence(); + String schema = annotation.schema(); + + SqlIdentifier sequenceIdentifier = SqlIdentifier.quoted(sequence); + if (StringUtils.hasText(schema)) { + sequenceIdentifier = SqlIdentifier.from(SqlIdentifier.quoted(schema), sequenceIdentifier); + } + + return sequenceIdentifier; + } else { + return null; + } + } + } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/EmbeddedRelationalPersistentEntity.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/EmbeddedRelationalPersistentEntity.java index 5e23e1d51..27359f759 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/EmbeddedRelationalPersistentEntity.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/EmbeddedRelationalPersistentEntity.java @@ -17,7 +17,6 @@ package org.springframework.data.relational.core.mapping; import java.lang.annotation.Annotation; import java.util.Iterator; -import java.util.Optional; import org.springframework.core.env.Environment; import org.springframework.data.mapping.*; @@ -56,11 +55,6 @@ class EmbeddedRelationalPersistentEntity implements RelationalPersistentEntit throw new MappingException("Embedded entity does not have an id column"); } - @Override - public Optional getIdSequence() { - return Optional.empty(); - } - @Override public void addPersistentProperty(RelationalPersistentProperty property) { throw new UnsupportedOperationException(); diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/EmbeddedRelationalPersistentProperty.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/EmbeddedRelationalPersistentProperty.java index 7a0c42c0e..bcfc2ddb5 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/EmbeddedRelationalPersistentProperty.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/EmbeddedRelationalPersistentProperty.java @@ -105,6 +105,12 @@ class EmbeddedRelationalPersistentProperty implements RelationalPersistentProper return delegate.isInsertOnly(); } + @Nullable + @Override + public SqlIdentifier getSequence() { + return delegate.getSequence(); + } + @Override public String getName() { return delegate.getName(); diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java index f111d77bc..49e9b929c 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentEntity.java @@ -15,8 +15,6 @@ */ package org.springframework.data.relational.core.mapping; -import java.util.Optional; - import org.springframework.data.mapping.model.MutablePersistentEntity; import org.springframework.data.relational.core.sql.SqlIdentifier; @@ -55,10 +53,4 @@ public interface RelationalPersistentEntity extends MutablePersistentEntity getIdSequence(); - } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java index 1aaceaa77..6d05df923 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java @@ -25,6 +25,7 @@ import org.springframework.lang.Nullable; * @author Jens Schauder * @author Oliver Gierke * @author Bastian Wilhelm + * @author Mark Paluch */ public interface RelationalPersistentProperty extends PersistentProperty { @@ -94,4 +95,20 @@ public interface RelationalPersistentProperty extends PersistentProperty entity = mappingContext.getRequiredPersistentEntity(DummySubEntity.class); - - assertThat(entity.getIdSequence()).isEmpty(); - } - - @Test // GH-1923 - void determineSequenceName() { - - RelationalPersistentEntity persistentEntity = mappingContext - .getRequiredPersistentEntity(EntityWithSequence.class); - - assertThat(persistentEntity.getIdSequence()).contains(SqlIdentifier.quoted("my_seq")); - } - - @Test // GH-1923 - void determineSequenceNameFromValue() { - - RelationalPersistentEntity persistentEntity = mappingContext - .getRequiredPersistentEntity(EntityWithSequenceValueAlias.class); - - assertThat(persistentEntity.getIdSequence()).contains(SqlIdentifier.quoted("my_seq")); - } - - @Test // GH-1923 - void determineSequenceNameWithSchemaSpecified() { - - RelationalPersistentEntity persistentEntity = mappingContext - .getRequiredPersistentEntity(EntityWithSequenceAndSchema.class); - - assertThat(persistentEntity.getIdSequence()) - .contains(SqlIdentifier.from(SqlIdentifier.quoted("public"), SqlIdentifier.quoted("my_seq"))); - } - @Test // DATAJDBC-294 void considerIdColumnName() { @@ -239,26 +203,6 @@ class BasicRelationalPersistentEntityUnitTests { @Column("renamedId") Long id; } - @Table("entity_with_sequence") - static class EntityWithSequence { - @Id - @Sequence(sequence = "my_seq") Long id; - } - - @Table("entity_with_sequence_value_alias") - static class EntityWithSequenceValueAlias { - @Id - @Column("myId") - @Sequence(value = "my_seq") Long id; - } - - @Table("entity_with_sequence_and_schema") - static class EntityWithSequenceAndSchema { - @Id - @Column("myId") - @Sequence(sequence = "my_seq", schema = "public") Long id; - } - @Table() static class DummyEntityWithEmptyAnnotation { @Id diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java index dd9ac027c..86f3c5385 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java @@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test; import org.springframework.data.annotation.Id; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.relational.core.mapping.Embedded.OnEmpty; +import org.springframework.data.relational.core.sql.SqlIdentifier; /** * Unit tests for the {@link BasicRelationalPersistentProperty}. @@ -40,14 +41,15 @@ import org.springframework.data.relational.core.mapping.Embedded.OnEmpty; * @author Florian Lüdiger * @author Bastian Wilhelm * @author Kurt Niemi + * @author Mark Paluch */ -public class BasicRelationalPersistentPropertyUnitTests { +class BasicRelationalPersistentPropertyUnitTests { - RelationalMappingContext context = new RelationalMappingContext(); - RelationalPersistentEntity entity = context.getRequiredPersistentEntity(DummyEntity.class); + private RelationalMappingContext context = new RelationalMappingContext(); + private RelationalPersistentEntity entity = context.getRequiredPersistentEntity(DummyEntity.class); @Test // DATAJDBC-106 - public void detectsAnnotatedColumnName() { + void detectsAnnotatedColumnName() { assertThat(entity.getRequiredPersistentProperty("name").getColumnName()).isEqualTo(quoted("dummy_name")); assertThat(entity.getRequiredPersistentProperty("localDateTime").getColumnName()) @@ -55,7 +57,7 @@ public class BasicRelationalPersistentPropertyUnitTests { } @Test // DATAJDBC-218 - public void detectsAnnotatedColumnAndKeyName() { + void detectsAnnotatedColumnAndKeyName() { RelationalPersistentProperty listProperty = entity.getRequiredPersistentProperty("someList"); @@ -91,7 +93,7 @@ public class BasicRelationalPersistentPropertyUnitTests { } @Test // DATAJDBC-111 - public void detectsEmbeddedEntity() { + void detectsEmbeddedEntity() { final RelationalPersistentEntity requiredPersistentEntity = context .getRequiredPersistentEntity(DummyEntity.class); @@ -120,7 +122,7 @@ public class BasicRelationalPersistentPropertyUnitTests { } @Test // DATAJDBC-259 - public void classificationOfCollectionLikeProperties() { + void classificationOfCollectionLikeProperties() { RelationalPersistentProperty listOfString = entity.getRequiredPersistentProperty("listOfString"); RelationalPersistentProperty arrayOfString = entity.getRequiredPersistentProperty("arrayOfString"); @@ -150,11 +152,45 @@ public class BasicRelationalPersistentPropertyUnitTests { softly.assertAll(); } + @Test // GH-1923 + void entityWithNoSequence() { + + RelationalPersistentEntity entity = context.getRequiredPersistentEntity(DummyEntity.class); + + assertThat(entity.getRequiredIdProperty().getSequence()).isNull(); + } + + @Test // GH-1923 + void determineSequenceName() { + + RelationalPersistentEntity persistentEntity = context.getRequiredPersistentEntity(EntityWithSequence.class); + + assertThat(persistentEntity.getRequiredIdProperty().getSequence()).isEqualTo(SqlIdentifier.quoted("my_seq")); + } + + @Test // GH-1923 + void determineSequenceNameFromValue() { + + RelationalPersistentEntity persistentEntity = context + .getRequiredPersistentEntity(EntityWithSequenceValueAlias.class); + + assertThat(persistentEntity.getRequiredIdProperty().getSequence()).isEqualTo(SqlIdentifier.quoted("my_seq")); + } + + @Test // GH-1923 + void determineSequenceNameWithSchemaSpecified() { + + RelationalPersistentEntity persistentEntity = context + .getRequiredPersistentEntity(EntityWithSequenceAndSchema.class); + + assertThat(persistentEntity.getRequiredIdProperty().getSequence()) + .isEqualTo(SqlIdentifier.from(SqlIdentifier.quoted("public"), SqlIdentifier.quoted("my_seq"))); + } + @SuppressWarnings("unused") - private static class DummyEntity { + static class DummyEntity { - @Id - private final Long id; + @Id private final Long id; private final SomeEnum someEnum; private final LocalDateTime localDateTime; private final ZonedDateTime zonedDateTime; @@ -166,8 +202,7 @@ public class BasicRelationalPersistentPropertyUnitTests { private final OtherEntity[] arrayOfEntity; @MappedCollection(idColumn = "dummy_column_name", - keyColumn = "dummy_key_column_name") - private List someList; + keyColumn = "dummy_key_column_name") private List someList; // DATACMNS-106 private @Column("dummy_name") String name; @@ -177,17 +212,14 @@ public class BasicRelationalPersistentPropertyUnitTests { public static String littleBobbyTablesValue = "--; DROP ALL TABLES;--"; @Column(value = "#{T(org.springframework.data.relational.core.mapping." + "BasicRelationalPersistentPropertyUnitTests$DummyEntity" - + ").spelExpression1Value}") - private String spelExpression1; + + ").spelExpression1Value}") private String spelExpression1; @Column(value = "#{T(org.springframework.data.relational.core.mapping." + "BasicRelationalPersistentPropertyUnitTests$DummyEntity" - + ").littleBobbyTablesValue}") - private String littleBobbyTables; + + ").littleBobbyTablesValue}") private String littleBobbyTables; @Column( - value = "--; DROP ALL TABLES;--") - private String poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot; + value = "--; DROP ALL TABLES;--") private String poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot; // DATAJDBC-111 private @Embedded(onEmpty = OnEmpty.USE_NULL) EmbeddableEntity embeddableEntity; @@ -195,7 +227,9 @@ public class BasicRelationalPersistentPropertyUnitTests { // DATAJDBC-111 private @Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix") EmbeddableEntity prefixedEmbeddableEntity; - public DummyEntity(Long id, SomeEnum someEnum, LocalDateTime localDateTime, ZonedDateTime zonedDateTime, List listOfString, String[] arrayOfString, List listOfEntity, OtherEntity[] arrayOfEntity) { + public DummyEntity(Long id, SomeEnum someEnum, LocalDateTime localDateTime, ZonedDateTime zonedDateTime, + List listOfString, String[] arrayOfString, List listOfEntity, + OtherEntity[] arrayOfEntity) { this.id = id; this.someEnum = someEnum; this.localDateTime = localDateTime; @@ -219,59 +253,59 @@ public class BasicRelationalPersistentPropertyUnitTests { return null; } - public Long getId() { + Long getId() { return this.id; } - public SomeEnum getSomeEnum() { + SomeEnum getSomeEnum() { return this.someEnum; } - public ZonedDateTime getZonedDateTime() { + ZonedDateTime getZonedDateTime() { return this.zonedDateTime; } - public List getListOfString() { + List getListOfString() { return this.listOfString; } - public String[] getArrayOfString() { + String[] getArrayOfString() { return this.arrayOfString; } - public List getListOfEntity() { + List getListOfEntity() { return this.listOfEntity; } - public OtherEntity[] getArrayOfEntity() { + OtherEntity[] getArrayOfEntity() { return this.arrayOfEntity; } - public List getSomeList() { + List getSomeList() { return this.someList; } - public String getName() { + String getName() { return this.name; } - public String getSpelExpression1() { + String getSpelExpression1() { return this.spelExpression1; } - public String getLittleBobbyTables() { + String getLittleBobbyTables() { return this.littleBobbyTables; } - public String getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot() { + String getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot() { return this.poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot; } - public EmbeddableEntity getEmbeddableEntity() { + EmbeddableEntity getEmbeddableEntity() { return this.embeddableEntity; } - public EmbeddableEntity getPrefixedEmbeddableEntity() { + EmbeddableEntity getPrefixedEmbeddableEntity() { return this.prefixedEmbeddableEntity; } @@ -291,7 +325,8 @@ public class BasicRelationalPersistentPropertyUnitTests { this.littleBobbyTables = littleBobbyTables; } - public void setPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot(String poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot) { + public void setPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot( + String poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot) { this.poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot = poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot; } @@ -304,16 +339,21 @@ public class BasicRelationalPersistentPropertyUnitTests { } public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof DummyEntity)) return false; + if (o == this) + return true; + if (!(o instanceof DummyEntity)) + return false; final DummyEntity other = (DummyEntity) o; - if (!other.canEqual((Object) this)) return false; + if (!other.canEqual((Object) this)) + return false; final Object this$id = this.getId(); final Object other$id = other.getId(); - if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false; + if (this$id == null ? other$id != null : !this$id.equals(other$id)) + return false; final Object this$someEnum = this.getSomeEnum(); final Object other$someEnum = other.getSomeEnum(); - if (this$someEnum == null ? other$someEnum != null : !this$someEnum.equals(other$someEnum)) return false; + if (this$someEnum == null ? other$someEnum != null : !this$someEnum.equals(other$someEnum)) + return false; final Object this$localDateTime = this.getLocalDateTime(); final Object other$localDateTime = other.getLocalDateTime(); if (this$localDateTime == null ? other$localDateTime != null : !this$localDateTime.equals(other$localDateTime)) @@ -326,42 +366,55 @@ public class BasicRelationalPersistentPropertyUnitTests { final Object other$listOfString = other.getListOfString(); if (this$listOfString == null ? other$listOfString != null : !this$listOfString.equals(other$listOfString)) return false; - if (!java.util.Arrays.deepEquals(this.getArrayOfString(), other.getArrayOfString())) return false; + if (!java.util.Arrays.deepEquals(this.getArrayOfString(), other.getArrayOfString())) + return false; final Object this$listOfEntity = this.getListOfEntity(); final Object other$listOfEntity = other.getListOfEntity(); if (this$listOfEntity == null ? other$listOfEntity != null : !this$listOfEntity.equals(other$listOfEntity)) return false; - if (!java.util.Arrays.deepEquals(this.getArrayOfEntity(), other.getArrayOfEntity())) return false; + if (!java.util.Arrays.deepEquals(this.getArrayOfEntity(), other.getArrayOfEntity())) + return false; final Object this$someList = this.getSomeList(); final Object other$someList = other.getSomeList(); - if (this$someList == null ? other$someList != null : !this$someList.equals(other$someList)) return false; + if (this$someList == null ? other$someList != null : !this$someList.equals(other$someList)) + return false; final Object this$name = this.getName(); final Object other$name = other.getName(); - if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; + if (this$name == null ? other$name != null : !this$name.equals(other$name)) + return false; final Object this$spelExpression1 = this.getSpelExpression1(); final Object other$spelExpression1 = other.getSpelExpression1(); - if (this$spelExpression1 == null ? other$spelExpression1 != null : !this$spelExpression1.equals(other$spelExpression1)) + if (this$spelExpression1 == null ? other$spelExpression1 != null + : !this$spelExpression1.equals(other$spelExpression1)) return false; final Object this$littleBobbyTables = this.getLittleBobbyTables(); final Object other$littleBobbyTables = other.getLittleBobbyTables(); - if (this$littleBobbyTables == null ? other$littleBobbyTables != null : !this$littleBobbyTables.equals(other$littleBobbyTables)) + if (this$littleBobbyTables == null ? other$littleBobbyTables != null + : !this$littleBobbyTables.equals(other$littleBobbyTables)) return false; - final Object this$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot = this.getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot(); - final Object other$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot = other.getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot(); - if (this$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot == null ? other$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot != null : !this$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot.equals(other$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot)) + final Object this$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot = this + .getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot(); + final Object other$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot = other + .getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot(); + if (this$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot == null + ? other$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot != null + : !this$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot + .equals(other$poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot)) return false; final Object this$embeddableEntity = this.getEmbeddableEntity(); final Object other$embeddableEntity = other.getEmbeddableEntity(); - if (this$embeddableEntity == null ? other$embeddableEntity != null : !this$embeddableEntity.equals(other$embeddableEntity)) + if (this$embeddableEntity == null ? other$embeddableEntity != null + : !this$embeddableEntity.equals(other$embeddableEntity)) return false; final Object this$prefixedEmbeddableEntity = this.getPrefixedEmbeddableEntity(); final Object other$prefixedEmbeddableEntity = other.getPrefixedEmbeddableEntity(); - if (this$prefixedEmbeddableEntity == null ? other$prefixedEmbeddableEntity != null : !this$prefixedEmbeddableEntity.equals(other$prefixedEmbeddableEntity)) + if (this$prefixedEmbeddableEntity == null ? other$prefixedEmbeddableEntity != null + : !this$prefixedEmbeddableEntity.equals(other$prefixedEmbeddableEntity)) return false; return true; } - protected boolean canEqual(final Object other) { + boolean canEqual(final Object other) { return other instanceof DummyEntity; } @@ -390,8 +443,10 @@ public class BasicRelationalPersistentPropertyUnitTests { result = result * PRIME + ($spelExpression1 == null ? 43 : $spelExpression1.hashCode()); final Object $littleBobbyTables = this.getLittleBobbyTables(); result = result * PRIME + ($littleBobbyTables == null ? 43 : $littleBobbyTables.hashCode()); - final Object $poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot = this.getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot(); - result = result * PRIME + ($poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot == null ? 43 : $poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot.hashCode()); + final Object $poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot = this + .getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot(); + result = result * PRIME + ($poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot == null ? 43 + : $poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot.hashCode()); final Object $embeddableEntity = this.getEmbeddableEntity(); result = result * PRIME + ($embeddableEntity == null ? 43 : $embeddableEntity.hashCode()); final Object $prefixedEmbeddableEntity = this.getPrefixedEmbeddableEntity(); @@ -400,11 +455,20 @@ public class BasicRelationalPersistentPropertyUnitTests { } public String toString() { - return "BasicRelationalPersistentPropertyUnitTests.DummyEntity(id=" + this.getId() + ", someEnum=" + this.getSomeEnum() + ", localDateTime=" + this.getLocalDateTime() + ", zonedDateTime=" + this.getZonedDateTime() + ", listOfString=" + this.getListOfString() + ", arrayOfString=" + java.util.Arrays.deepToString(this.getArrayOfString()) + ", listOfEntity=" + this.getListOfEntity() + ", arrayOfEntity=" + java.util.Arrays.deepToString(this.getArrayOfEntity()) + ", someList=" + this.getSomeList() + ", name=" + this.getName() + ", spelExpression1=" + this.getSpelExpression1() + ", littleBobbyTables=" + this.getLittleBobbyTables() + ", poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot=" + this.getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot() + ", embeddableEntity=" + this.getEmbeddableEntity() + ", prefixedEmbeddableEntity=" + this.getPrefixedEmbeddableEntity() + ")"; + return "BasicRelationalPersistentPropertyUnitTests.DummyEntity(id=" + this.getId() + ", someEnum=" + + this.getSomeEnum() + ", localDateTime=" + this.getLocalDateTime() + ", zonedDateTime=" + + this.getZonedDateTime() + ", listOfString=" + this.getListOfString() + ", arrayOfString=" + + java.util.Arrays.deepToString(this.getArrayOfString()) + ", listOfEntity=" + this.getListOfEntity() + + ", arrayOfEntity=" + java.util.Arrays.deepToString(this.getArrayOfEntity()) + ", someList=" + + this.getSomeList() + ", name=" + this.getName() + ", spelExpression1=" + this.getSpelExpression1() + + ", littleBobbyTables=" + this.getLittleBobbyTables() + + ", poorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot=" + + this.getPoorDeveloperProgrammaticallyAskingToShootThemselvesInTheFoot() + ", embeddableEntity=" + + this.getEmbeddableEntity() + ", prefixedEmbeddableEntity=" + this.getPrefixedEmbeddableEntity() + ")"; } } - static class WithMappedCollection { + private static class WithMappedCollection { @MappedCollection(idColumn = "#{'id_col'}", keyColumn = "#{'key_col'}") private List someList; } @@ -422,15 +486,18 @@ public class BasicRelationalPersistentPropertyUnitTests { this.embeddedTest = embeddedTest; } - public String getEmbeddedTest() { + String getEmbeddedTest() { return this.embeddedTest; } public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof EmbeddableEntity)) return false; + if (o == this) + return true; + if (!(o instanceof EmbeddableEntity)) + return false; final EmbeddableEntity other = (EmbeddableEntity) o; - if (!other.canEqual((Object) this)) return false; + if (!other.canEqual((Object) this)) + return false; final Object this$embeddedTest = this.getEmbeddedTest(); final Object other$embeddedTest = other.getEmbeddedTest(); if (this$embeddedTest == null ? other$embeddedTest != null : !this$embeddedTest.equals(other$embeddedTest)) @@ -438,7 +505,7 @@ public class BasicRelationalPersistentPropertyUnitTests { return true; } - protected boolean canEqual(final Object other) { + boolean canEqual(final Object other) { return other instanceof EmbeddableEntity; } @@ -457,4 +524,24 @@ public class BasicRelationalPersistentPropertyUnitTests { @SuppressWarnings("unused") private static class OtherEntity {} + + @Table("entity_with_sequence") + static class EntityWithSequence { + @Id + @Sequence(sequence = "my_seq") Long id; + } + + @Table("entity_with_sequence_value_alias") + static class EntityWithSequenceValueAlias { + @Id + @Column("myId") + @Sequence(value = "my_seq") Long id; + } + + @Table("entity_with_sequence_and_schema") + static class EntityWithSequenceAndSchema { + @Id + @Column("myId") + @Sequence(sequence = "my_seq", schema = "public") Long id; + } }