From 141a0d9358d60a2b670a63510dc6ddf5f7b0433c Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 29 May 2018 00:35:31 +1200 Subject: [PATCH] #1390 - ENH: Support explicit @Id @GeneratedValue ... mapping (where absence of @GeneratedValue means externally supplied id values) --- .../java/io/ebean/config/ServerConfig.java | 25 +++++++++++- .../server/deploy/BeanDescriptorManager.java | 40 +++++++++++-------- .../deploy/meta/DeployBeanDescriptor.java | 19 +++++++++ .../server/deploy/parse/AnnotationFields.java | 2 + .../io/ebean/config/ServerConfigTest.java | 13 ++++++ 5 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index 5b14d2bfc..222129a65 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -493,6 +493,11 @@ public class ServerConfig { */ private List mappingLocations = new ArrayList<>(); + /** + * When true we do not need explicit GeneratedValue mapping. + */ + private boolean idGeneratorAutomatic = true; + /** * Construct a Server Configuration for programmatically creating an EbeanServer. */ @@ -1967,7 +1972,7 @@ public class ServerConfig { * This is the same as serverConfig.getMigrationConfig().setRunMigration(). We have added this method here * as it is often the only thing we need to configure for migrations. */ - public void setRunMigration(boolean runMigration){ + public void setRunMigration(boolean runMigration) { migrationConfig.setRunMigration(runMigration); } @@ -2772,6 +2777,7 @@ public class ServerConfig { useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager); useJavaxValidationNotNull = p.getBoolean("useJavaxValidationNotNull", useJavaxValidationNotNull); autoReadOnlyDataSource = p.getBoolean("autoReadOnlyDataSource", autoReadOnlyDataSource); + idGeneratorAutomatic = p.getBoolean("idGeneratorAutomatic", idGeneratorAutomatic); backgroundExecutorSchedulePoolSize = p.getInt("backgroundExecutorSchedulePoolSize", backgroundExecutorSchedulePoolSize); backgroundExecutorShutdownSecs = p.getInt("backgroundExecutorShutdownSecs", backgroundExecutorShutdownSecs); @@ -3109,6 +3115,23 @@ public class ServerConfig { this.mappingLocations = mappingLocations; } + /** + * When false we need explicit @GeneratedValue mapping to assign + * Identity or Sequence generated values. When true Id properties are automatically + * assigned Identity or Sequence without the GeneratedValue mapping. + */ + public boolean isIdGeneratorAutomatic() { + return idGeneratorAutomatic; + } + + /** + * Set to false such that Id properties require explicit @GeneratedValue + * mapping before they are assigned Identity or Sequence generation based on platform. + */ + public void setIdGeneratorAutomatic(boolean idGeneratorAutomatic) { + this.idGeneratorAutomatic = idGeneratorAutomatic; + } + public enum UuidVersion { VERSION4, VERSION1, diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 91738c3ab..22dcf6ad5 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -1369,9 +1369,15 @@ public class BeanDescriptorManager implements BeanDescriptorMap { desc.setIdType(IdType.EXTERNAL); return; } - // use the default. IDENTITY or SEQUENCE. - desc.setIdType(dbIdentity.getIdType()); - desc.setIdTypePlatformDefault(); + if (desc.isIdGeneratorAuto() || serverConfig.isIdGeneratorAutomatic()) { + // use IDENTITY or SEQUENCE based on platform + desc.setIdType(dbIdentity.getIdType()); + desc.setIdTypePlatformDefault(); + } else { + // externally/application supplied Id values + desc.setIdType(IdType.EXTERNAL); + return; + } } if (desc.getBaseTable() == null) { @@ -1387,21 +1393,23 @@ public class BeanDescriptorManager implements BeanDescriptorMap { return; } - String seqName = desc.getIdGeneratorName(); - if (seqName != null) { - logger.debug("explicit sequence {} on {}", seqName, desc.getFullName()); - } else { - String primaryKeyColumn = desc.getSinglePrimaryKeyColumn(); - // use namingConvention to define sequence name - seqName = namingConvention.getSequenceName(desc.getBaseTable(), primaryKeyColumn); - } + if (IdType.SEQUENCE == desc.getIdType()) { + String seqName = desc.getIdGeneratorName(); + if (seqName != null) { + logger.debug("explicit sequence {} on {}", seqName, desc.getFullName()); + } else { + String primaryKeyColumn = desc.getSinglePrimaryKeyColumn(); + // use namingConvention to define sequence name + seqName = namingConvention.getSequenceName(desc.getBaseTable(), primaryKeyColumn); + } - if (databasePlatform.isSequenceBatchMode()) { - // use sequence next step 1 as we are going to batch fetch them instead - desc.setSequenceAllocationSize(1); + if (databasePlatform.isSequenceBatchMode()) { + // use sequence next step 1 as we are going to batch fetch them instead + desc.setSequenceAllocationSize(1); + } + int stepSize = desc.getSequenceAllocationSize(); + desc.setIdGenerator(createSequenceIdGenerator(seqName, stepSize)); } - int stepSize = desc.getSequenceAllocationSize(); - desc.setIdGenerator(createSequenceIdGenerator(seqName, stepSize)); } private PlatformIdGenerator createSequenceIdGenerator(String seqName, int stepSize) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 1855dee14..98d878a56 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -106,6 +106,11 @@ public class DeployBeanDescriptor { private PlatformIdGenerator idGenerator; + /** + * Set true when explicit auto generated Id. + */ + private boolean idGeneratorAuto; + /** * The database sequence name (optional). */ @@ -848,6 +853,20 @@ public class DeployBeanDescriptor { } } + /** + * Return true for automatic Id generation strategy. + */ + public boolean isIdGeneratorAuto() { + return idGeneratorAuto; + } + + /** + * Set when GeneratedValue explicitly mapped on Id property. + */ + public void setGeneratedAuto() { + this.idGeneratorAuto = true; + } + /** * Assign the standard UUID generator. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java index 4be082b93..c1e3ca89b 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java @@ -547,6 +547,8 @@ public class AnnotationFields extends AnnotationParser { descriptor.setCustomIdGenerator(idGenerator); } else if (prop.getPropertyType().equals(UUID.class)) { descriptor.setUuidGenerator(); + } else { + descriptor.setGeneratedAuto(); } } } diff --git a/src/test/java/io/ebean/config/ServerConfigTest.java b/src/test/java/io/ebean/config/ServerConfigTest.java index b404b7451..fc24bc40c 100644 --- a/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/src/test/java/io/ebean/config/ServerConfigTest.java @@ -66,6 +66,7 @@ public class ServerConfigTest { props.setProperty("idType", "SEQUENCE"); props.setProperty("mappingLocations", "classpath:/foo;bar"); props.setProperty("namingConvention", "io.ebean.config.MatchingNamingConvention"); + props.setProperty("idGeneratorAutomatic", "true"); serverConfig.loadFromProperties(props); @@ -74,6 +75,8 @@ public class ServerConfigTest { assertTrue(serverConfig.isNotifyL2CacheInForeground()); assertTrue(serverConfig.isDbOffline()); assertTrue(serverConfig.isAutoReadOnlyDataSource()); + assertTrue(serverConfig.isIdGeneratorAutomatic()); + assertThat(serverConfig.getNamingConvention()).isInstanceOf(MatchingNamingConvention.class); assertEquals(IdType.SEQUENCE, serverConfig.getIdType()); @@ -108,4 +111,14 @@ public class ServerConfigTest { assertEquals(PersistBatch.ALL, serverConfig.getPersistBatch()); assertEquals(PersistBatch.ALL, serverConfig.getPersistBatchOnCascade()); } + + @Test + public void test_defaults() { + + ServerConfig serverConfig = new ServerConfig(); + assertTrue(serverConfig.isIdGeneratorAutomatic()); + + serverConfig.setIdGeneratorAutomatic(false); + assertFalse(serverConfig.isIdGeneratorAutomatic()); + } }