From 35ab8baa0affd88deede314bf36bb39d635389d7 Mon Sep 17 00:00:00 2001 From: "Renat R. Safiullin" Date: Wed, 17 Jun 2026 15:36:56 +0300 Subject: [PATCH] Add java.time option to Entity Classes from Database wizard The "Entity Classes from Database" wizard always mapped temporal columns (DATE/TIME/TIMESTAMP) to java.util.Date with a @Temporal annotation. Add a "Date/Time API" mapping option, alongside the existing Collection Type option, that lets the user choose java.time types instead: java.sql.Date -> java.time.LocalDate java.sql.Time -> java.time.LocalTime java.sql.Timestamp -> java.time.LocalDateTime java.time types are mapped natively by JPA 2.2+, so no @Temporal annotation is emitted for them. The default stays java.util.Date for backward compatibility. Fixes #3755 Co-Authored-By: Claude Opus 4.8 --- .../netbeans/modules/usersguide/f1_jpa005.htm | 8 +++ .../entitygenerator/DateTimeType.java | 45 ++++++++++++ .../wizard/fromdb/Bundle.properties | 3 + .../fromdb/JavaPersistenceGenerator.java | 52 +++++++++----- .../wizard/fromdb/MappingOptionsPanel.form | 42 ++++++++++-- .../wizard/fromdb/MappingOptionsPanel.java | 68 ++++++++++++++++--- .../wizard/fromdb/RelatedCMPHelper.java | 14 +++- .../persistence/wizard/fromdb/JPAGenTest.java | 53 +++++++++++++-- 8 files changed, 246 insertions(+), 39 deletions(-) create mode 100644 java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/entitygenerator/DateTimeType.java diff --git a/ide/usersguide/javahelp/org/netbeans/modules/usersguide/f1_jpa005.htm b/ide/usersguide/javahelp/org/netbeans/modules/usersguide/f1_jpa005.htm index 73c36d034963..85414c283551 100755 --- a/ide/usersguide/javahelp/org/netbeans/modules/usersguide/f1_jpa005.htm +++ b/ide/usersguide/javahelp/org/netbeans/modules/usersguide/f1_jpa005.htm @@ -65,6 +65,14 @@

New Entity Classes from Database Wizard: Mapping Options

+ +

Date/Time API

+ +Select the Java type family used for temporal columns (DATE, TIME, TIMESTAMP). +

When java.util.Date is selected, columns are mapped to java.util.Date with a @Temporal annotation. When java.time (Java 8+) is selected, columns are mapped to java.time.LocalDate, java.time.LocalTime and java.time.LocalDateTime, which are mapped natively by JPA 2.2 and later and therefore need no @Temporal annotation. java.util.Date is selected by default.

+ + +

Fully Qualified Database Table Names

diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/entitygenerator/DateTimeType.java b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/entitygenerator/DateTimeType.java new file mode 100644 index 000000000000..1e2846355a3c --- /dev/null +++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/entitygenerator/DateTimeType.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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.netbeans.modules.j2ee.persistence.entitygenerator; + +/** + * The Java type family used to map temporal database columns + * ({@code DATE}, {@code TIME}, {@code TIMESTAMP}) when generating entity + * classes from a database. + * + * @see NETBEANS-3755 + */ +public enum DateTimeType { + + /** + * Legacy mapping: every temporal column becomes a {@code java.util.Date} + * annotated with {@code @Temporal}. This is the default for backward + * compatibility. + */ + LEGACY, + + /** + * Modern mapping using the {@code java.time} classes introduced in Java 8 + * ({@code LocalDate}, {@code LocalTime}, {@code LocalDateTime}). These are + * mapped natively by JPA 2.2+ and therefore need no {@code @Temporal} + * annotation. + */ + JAVA_8; +} diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/Bundle.properties b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/Bundle.properties index 5c71586c9553..cc9b27dae7ba 100644 --- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/Bundle.properties +++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/Bundle.properties @@ -212,6 +212,9 @@ LBL_FETCH_EAGER=eager LBL_TABLE_NAME=Fully &Qualified Database Table Names LBL_REGENERATE_TABLES=Attributes for &Regenerating Tables LBL_COLLECTOIN_TYPE=&Collection Type: +LBL_DATE_TIME_TYPE=&Date/Time API: +LBL_DATE_TIME_LEGACY=java.util.Date +LBL_DATE_TIME_JAVA8=java.time (Java 8+) TXT_SelectedTables=Selected Tables TXT_AvailableTables=Available Tables LBL_Progress_Adding_Classpath=Adding J2EE apis to project classpath. diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/JavaPersistenceGenerator.java b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/JavaPersistenceGenerator.java index 9f40d7f23e52..53793366db68 100644 --- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/JavaPersistenceGenerator.java +++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/JavaPersistenceGenerator.java @@ -54,6 +54,7 @@ import org.netbeans.modules.j2ee.persistence.entitygenerator.CMPMappingModel.ColumnData; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityClass; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityMember; +import org.netbeans.modules.j2ee.persistence.entitygenerator.DateTimeType; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.CollectionType; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.FetchType; import org.netbeans.modules.j2ee.persistence.entitygenerator.RelationshipRole; @@ -150,7 +151,7 @@ public void generateBeans(final ProgressPanel progressPanel, helper.isFullyQualifiedTableNames(), helper.isRegenTablesAttrs(), helper.isUseDefaults(), helper.isGenerateMappedSuperclasses(), - helper.getFetchType(), helper.getCollectionType(), + helper.getFetchType(), helper.getCollectionType(), helper.getDateTimeType(), handle, progressPanel, helper.getProject()); } @@ -159,15 +160,15 @@ void generateBeans(EntityClass[] entityClasses, boolean generateNamedQueries, boolean generateJAXBAnnotations, boolean generateValidationConstraints, boolean fullyQualifiedTableNames, boolean regenTablesAttrs, - FetchType fetchType, CollectionType collectionType, + FetchType fetchType, CollectionType collectionType, DateTimeType dateTimeType, ProgressContributor progressContributor, ProgressPanel panel, Project prj) throws IOException { - - generateBeans(entityClasses, generateNamedQueries, generateJAXBAnnotations, - generateValidationConstraints, fullyQualifiedTableNames, regenTablesAttrs, - false, false, fetchType, collectionType, progressContributor, panel, prj); - + + generateBeans(entityClasses, generateNamedQueries, generateJAXBAnnotations, + generateValidationConstraints, fullyQualifiedTableNames, regenTablesAttrs, + false, false, fetchType, collectionType, dateTimeType, progressContributor, panel, prj); + } - + private void generateBeans(EntityClass[] entityClasses, boolean generateNamedQueries, boolean generateJAXBAnnotations, @@ -175,7 +176,7 @@ private void generateBeans(EntityClass[] entityClasses, boolean generateNamedQue boolean fullyQualifiedTableNames, boolean regenTablesAttrs, boolean useDefaults, boolean generateMappedSC, - FetchType fetchType, CollectionType collectionType, + FetchType fetchType, CollectionType collectionType, DateTimeType dateTimeType, ProgressContributor progressContributor, ProgressPanel panel, Project prj) throws IOException { int progressMax = entityClasses.length * 3; @@ -200,7 +201,7 @@ private void generateBeans(EntityClass[] entityClasses, boolean generateNamedQue fullyQualifiedTableNames, regenTablesAttrs, useDefaults, generateMappedSC, - fetchType, collectionType, + fetchType, collectionType, dateTimeType, progressContributor, panel, this).run(); addToPersistenceUnit(result); progressContributor.progress(progressMax); @@ -329,6 +330,7 @@ private static final class Generator { private final boolean regenTablesAttrs, generateMappedSC; private final FetchType fetchType; private final CollectionType collectionType; + private final DateTimeType dateTimeType; private final Set generatedEntityFOs; private final Set generatedFOs; private final PersistenceGenerator persistenceGen; @@ -342,7 +344,7 @@ public Generator(EntityClass[] entityClasses, boolean generateNamedQueries, boolean fullyQualifiedTableNames, boolean regenTablesAttrs, boolean useDefaults, boolean generateMappedSC, - FetchType fetchType, CollectionType collectionType, + FetchType fetchType, CollectionType collectionType, DateTimeType dateTimeType, ProgressContributor progressContributor, ProgressPanel progressPanel, PersistenceGenerator persistenceGen) { this.entityClasses = entityClasses; @@ -355,6 +357,7 @@ public Generator(EntityClass[] entityClasses, boolean generateNamedQueries, this.regenTablesAttrs = regenTablesAttrs; this.fetchType = fetchType; this.collectionType = collectionType; + this.dateTimeType = dateTimeType; this.progressContributor = progressContributor; this.progressPanel = progressPanel; generatedFOs = new HashSet(); @@ -811,12 +814,22 @@ protected VariableTree createVariable(EntityMember m) { String getMemberType(EntityMember m) { String memberType = m.getMemberType(); - if ("java.sql.Date".equals(memberType)) { //NOI18N - memberType = "java.util.Date"; - } else if ("java.sql.Time".equals(memberType)) { //NOI18N - memberType = "java.util.Date"; - } else if ("java.sql.Timestamp".equals(memberType)) { //NOI18N - memberType = "java.util.Date"; + if (DateTimeType.JAVA_8.equals(dateTimeType)) { + if ("java.sql.Date".equals(memberType)) { //NOI18N + memberType = "java.time.LocalDate"; //NOI18N + } else if ("java.sql.Time".equals(memberType)) { //NOI18N + memberType = "java.time.LocalTime"; //NOI18N + } else if ("java.sql.Timestamp".equals(memberType)) { //NOI18N + memberType = "java.time.LocalDateTime"; //NOI18N + } + } else { + if ("java.sql.Date".equals(memberType)) { //NOI18N + memberType = "java.util.Date"; //NOI18N + } else if ("java.sql.Time".equals(memberType)) { //NOI18N + memberType = "java.util.Date"; //NOI18N + } else if ("java.sql.Timestamp".equals(memberType)) { //NOI18N + memberType = "java.util.Date"; //NOI18N + } } return memberType; } @@ -834,6 +847,11 @@ private boolean isDecimalType(String type) { } private String getMemberTemporalType(EntityMember m) { + // java.time types are mapped natively by JPA 2.2+ and must not + // carry a @Temporal annotation. + if (DateTimeType.JAVA_8.equals(dateTimeType)) { + return null; + } String memberType = m.getMemberType(); String temporalType = null; if ("java.sql.Date".equals(memberType)) { //NOI18N diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/MappingOptionsPanel.form b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/MappingOptionsPanel.form index 2556baf1a6a2..32b58a72171f 100644 --- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/MappingOptionsPanel.form +++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/MappingOptionsPanel.form @@ -83,7 +83,7 @@ - + @@ -98,14 +98,14 @@ - + - + @@ -161,7 +161,7 @@ - + @@ -179,7 +179,7 @@ - + @@ -197,7 +197,37 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/MappingOptionsPanel.java b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/MappingOptionsPanel.java index a8c415f4a4c7..592858d4938a 100644 --- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/MappingOptionsPanel.java +++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/MappingOptionsPanel.java @@ -21,6 +21,7 @@ import javax.swing.DefaultComboBoxModel; import javax.swing.event.ChangeListener; +import org.netbeans.modules.j2ee.persistence.entitygenerator.DateTimeType; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.CollectionType; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.FetchType; import org.openide.WizardDescriptor; @@ -45,9 +46,15 @@ public MappingOptionsPanel() { collectionTypeComboBox.setModel(new DefaultComboBoxModel( new String[]{"java.util.Collection", "java.util.List", "java.util.Set"})); // NOI18N collectionTypeComboBox.setSelectedIndex(0); + + dateTimeComboBox.setModel(new DefaultComboBoxModel( + new String[]{NbBundle.getMessage(MappingOptionsPanel.class, "LBL_DATE_TIME_LEGACY"), + NbBundle.getMessage(MappingOptionsPanel.class, "LBL_DATE_TIME_JAVA8") + })); + dateTimeComboBox.setSelectedIndex(0); } - - public void initialize(CollectionType collectionType, FetchType fetchType, boolean fullyQualifiedTblName, boolean regenSchemaAttrs, boolean useColumnNamesInRelationships) { + + public void initialize(CollectionType collectionType, DateTimeType dateTimeType, FetchType fetchType, boolean fullyQualifiedTblName, boolean regenSchemaAttrs, boolean useColumnNamesInRelationships) { switch(fetchType) { case EAGER: @@ -72,7 +79,16 @@ public void initialize(CollectionType collectionType, FetchType fetchType, boole default: collectionTypeComboBox.setSelectedIndex(0); } - + + switch(dateTimeType) { + case JAVA_8: + dateTimeComboBox.setSelectedIndex(1); + break; + case LEGACY: + default: + dateTimeComboBox.setSelectedIndex(0); + } + tableNameCheckBox.setSelected(fullyQualifiedTblName); regenTablesCheckBox.setSelected(regenSchemaAttrs); relationshipColumnNamesCheckBox.setSelected(useColumnNamesInRelationships); @@ -100,6 +116,15 @@ public CollectionType getCollectionType() { } } + public DateTimeType getDateTimeType() { + int selected = dateTimeComboBox.getSelectedIndex(); + if(selected == 1 ) { + return DateTimeType.JAVA_8; + } else { + return DateTimeType.LEGACY; + } + } + public boolean isFullyQualifiedTableName() { return tableNameCheckBox.isSelected(); } @@ -136,6 +161,8 @@ private void initComponents() { descLabel = new javax.swing.JLabel(); collectionTypeLabel = new javax.swing.JLabel(); collectionTypeComboBox = new javax.swing.JComboBox(); + dateTimeLabel = new javax.swing.JLabel(); + dateTimeComboBox = new javax.swing.JComboBox(); relationshipColumnNamesCheckBox = new javax.swing.JCheckBox(); defaultsCheckBox = new javax.swing.JCheckBox(); relationshipsUnresolvedCheckBox = new javax.swing.JCheckBox(); @@ -163,7 +190,7 @@ private void initComponents() { org.openide.awt.Mnemonics.setLocalizedText(tableNameCheckBox, org.openide.util.NbBundle.getMessage(MappingOptionsPanel.class, "LBL_TABLE_NAME")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 3; + gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); @@ -172,14 +199,14 @@ private void initComponents() { org.openide.awt.Mnemonics.setLocalizedText(regenTablesCheckBox, org.openide.util.NbBundle.getMessage(MappingOptionsPanel.class, "LBL_REGENERATE_TABLES")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 4; + gridBagConstraints.gridy = 5; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); add(regenTablesCheckBox, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 8; + gridBagConstraints.gridy = 9; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weighty = 1.0; @@ -210,10 +237,27 @@ private void initComponents() { gridBagConstraints.insets = new java.awt.Insets(5, 12, 0, 0); add(collectionTypeComboBox, gridBagConstraints); + dateTimeLabel.setLabelFor(dateTimeComboBox); + org.openide.awt.Mnemonics.setLocalizedText(dateTimeLabel, org.openide.util.NbBundle.getMessage(MappingOptionsPanel.class, "LBL_DATE_TIME_TYPE")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); + add(dateTimeLabel, gridBagConstraints); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(5, 12, 0, 0); + add(dateTimeComboBox, gridBagConstraints); + org.openide.awt.Mnemonics.setLocalizedText(relationshipColumnNamesCheckBox, org.openide.util.NbBundle.getMessage(MappingOptionsPanel.class, "MappingOptionsPanel.relationshipColumnNamesCheckBox.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 5; + gridBagConstraints.gridy = 6; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); @@ -222,7 +266,7 @@ private void initComponents() { org.openide.awt.Mnemonics.setLocalizedText(defaultsCheckBox, org.openide.util.NbBundle.getMessage(MappingOptionsPanel.class, "MappingOptionsPanel.defaultsCheckBox.text_1")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 6; + gridBagConstraints.gridy = 7; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); @@ -231,7 +275,7 @@ private void initComponents() { org.openide.awt.Mnemonics.setLocalizedText(relationshipsUnresolvedCheckBox, org.openide.util.NbBundle.getMessage(MappingOptionsPanel.class, "MappingOptionsPanel.relationshipsUnresolvedCheckBox.text_1")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 7; + gridBagConstraints.gridy = 8; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); @@ -242,6 +286,8 @@ private void initComponents() { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JComboBox collectionTypeComboBox; private javax.swing.JLabel collectionTypeLabel; + private javax.swing.JComboBox dateTimeComboBox; + private javax.swing.JLabel dateTimeLabel; private javax.swing.JCheckBox defaultsCheckBox; private javax.swing.JLabel descLabel; private javax.swing.JComboBox fetchComboBox; @@ -286,7 +332,8 @@ public void readSettings(WizardDescriptor settings) { boolean regenSchema = helper.isRegenTablesAttrs(); boolean useColumnNamesInRelationships = helper.isUseColumnNamesInRelationships(); CollectionType clcType = helper.getCollectionType(); - getComponent().initialize(clcType, fetchType, fullTblName, regenSchema, useColumnNamesInRelationships); + DateTimeType dtType = helper.getDateTimeType(); + getComponent().initialize(clcType, dtType, fetchType, fullTblName, regenSchema, useColumnNamesInRelationships); } } @@ -304,6 +351,7 @@ public void storeSettings(WizardDescriptor settings) { helper.setRegenTablesAttrs(mPanel.isRegenSchemaAttributes()); helper.setUseColumnNamesInRelationships(mPanel.isUseColumnNamesInRelationships()); helper.setCollectionType(mPanel.getCollectionType()); + helper.setDateTimeType(mPanel.getDateTimeType()); helper.setUseDefaults(mPanel.isUseDefaults()); helper.setGenerateUnresolvedRelationships(mPanel.isGenerateUnresolved()); } diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/RelatedCMPHelper.java b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/RelatedCMPHelper.java index b84b48face96..286939a0fc9b 100644 --- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/RelatedCMPHelper.java +++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/RelatedCMPHelper.java @@ -30,6 +30,7 @@ import org.openide.filesystems.*; import org.netbeans.api.project.SourceGroup; import org.netbeans.modules.dbschema.SchemaElement; +import org.netbeans.modules.j2ee.persistence.entitygenerator.DateTimeType; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.CollectionType; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.FetchType; @@ -88,7 +89,8 @@ public void setCreatePU(boolean createPU) { private FetchType fetchType = FetchType.DEFAULT; private boolean regenTablesAttrs = false; private CollectionType collectionType = CollectionType.COLLECTION; - + private DateTimeType dateTimeType = DateTimeType.LEGACY; + public RelatedCMPHelper(Project project, FileObject configFilesFolder, PersistenceGenerator persistenceGen) { this.project = project; this.configFilesFolder = configFilesFolder; @@ -293,7 +295,15 @@ public CollectionType getCollectionType() { public void setCollectionType(CollectionType type) { collectionType = type; } - + + public DateTimeType getDateTimeType() { + return dateTimeType; + } + + public void setDateTimeType(DateTimeType type) { + dateTimeType = type; + } + /** * Public because used in J2EE functional tests. */ diff --git a/java/j2ee.persistence/test/unit/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/JPAGenTest.java b/java/j2ee.persistence/test/unit/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/JPAGenTest.java index ddcbef4b7014..29926f980a42 100644 --- a/java/j2ee.persistence/test/unit/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/JPAGenTest.java +++ b/java/j2ee.persistence/test/unit/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/JPAGenTest.java @@ -31,6 +31,7 @@ import org.netbeans.modules.j2ee.persistence.entitygenerator.DbSchemaEjbGenerator; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityClass; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityMember; +import org.netbeans.modules.j2ee.persistence.entitygenerator.DateTimeType; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.CollectionType; import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.FetchType; import org.netbeans.modules.j2ee.persistence.entitygenerator.GeneratedTables; @@ -69,13 +70,57 @@ public void testGenerateOneEntity() throws IOException{ EntityClass user = getUserEntity(); generator.generateBeans(new EntityClass[]{user}, true, false, false, false, false, - FetchType.DEFAULT, CollectionType.COLLECTION, getProgressContributor(), null, null); + FetchType.DEFAULT, CollectionType.COLLECTION, DateTimeType.LEGACY, getProgressContributor(), null, null); assertEquals(1,generator.createdObjects().size()); FileObject result = generator.createdObjects().iterator().next(); assertFile(FileUtil.toFile(result), getGoldenFile("testGenEntity/" + result.getName() + ".pass")); } + public void testGenerateJavaTimeTypes() throws IOException{ + EntityClass event = new EntityClass(null, null, "EVENT", + getWorkDirFO(), packageName, "Event", UpdateType.NEW, false, null); + event.usePkField(true); + + EntityMemberImpl eventDate = temporalMember("eventDate", "EVENT_DATE", "java.sql.Date", "EVENT"); + EntityMemberImpl eventTime = temporalMember("eventTime", "EVENT_TIME", "java.sql.Time", "EVENT"); + EntityMemberImpl created = temporalMember("created", "CREATED", "java.sql.Timestamp", "EVENT"); + + List fields = new ArrayList<>(); + fields.add(getId("EVENT")); + fields.add(eventDate); + fields.add(eventTime); + fields.add(created); + event.setFields(fields); + + generator.generateBeans(new EntityClass[]{event}, true, false, false, false, false, + FetchType.DEFAULT, CollectionType.COLLECTION, DateTimeType.JAVA_8, getProgressContributor(), null, null); + assertEquals(1, generator.createdObjects().size()); + + FileObject result = generator.createdObjects().iterator().next(); + String content = result.asText(); + + // java.time types are used instead of java.util.Date ... + assertTrue("expected LocalDate", content.contains("java.time.LocalDate") || content.contains("LocalDate")); + assertTrue("expected LocalTime", content.contains("java.time.LocalTime") || content.contains("LocalTime")); + assertTrue("expected LocalDateTime", content.contains("java.time.LocalDateTime") || content.contains("LocalDateTime")); + assertFalse("java.util.Date must not be generated", content.contains("java.util.Date")); + // ... and java.time types are mapped natively, without @Temporal. + assertFalse("@Temporal must not be generated for java.time types", content.contains("@Temporal")); + } + + private EntityMemberImpl temporalMember(String memberName, String columnName, String memberType, String tableName){ + EntityMemberImpl member = new EntityMemberImpl(); + member.setMemberName(memberName); + member.setColumnName(columnName); + member.setSupportsFinder(true); + member.setNullable(true); + member.setPrimaryKey(false); + member.setMemberType(memberType); + member.setTableName(tableName); + return member; + } + public void testGenerateTwoUnrelated() throws IOException{ EntityClass user = getUserEntity(); @@ -103,7 +148,7 @@ public void testGenerateTwoUnrelated() throws IOException{ generator.generateBeans(new EntityClass[]{user, product}, true, false, false, - false, false, FetchType.DEFAULT, CollectionType.COLLECTION, + false, false, FetchType.DEFAULT, CollectionType.COLLECTION, DateTimeType.LEGACY, getProgressContributor(), null, null); Set result = generator.createdObjects(); assertEquals(2, result.size()); @@ -128,10 +173,10 @@ public void testGenerateEntityFromSampleSchema() throws Exception{ EntityClass[] beans = new DbSchemaEjbGenerator(genTables, schema).getBeans(); - generator.generateBeans(beans, true, false, false, false, false, FetchType.DEFAULT, CollectionType.COLLECTION, getProgressContributor(), null, null); + generator.generateBeans(beans, true, false, false, false, false, FetchType.DEFAULT, CollectionType.COLLECTION, DateTimeType.LEGACY, getProgressContributor(), null, null); Set result = generator.createdObjects(); assertEquals(1, result.size()); - + for(FileObject each : result){ assertFile(FileUtil.toFile(each), getGoldenFile("testGenFromSample/" + each.getName() + ".pass")); }