You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by db...@apache.org on 2022/02/18 13:11:16 UTC
[netbeans] branch master updated: Support for generating Micronaut Data entity classes end repository interfaces added. (#3584)
This is an automated email from the ASF dual-hosted git repository.
dbalek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new 9310f3d Support for generating Micronaut Data entity classes end repository interfaces added. (#3584)
9310f3d is described below
commit 9310f3d51c8ea2da7db55f336382ea120610bb20
Author: Dusan Balek <du...@oracle.com>
AuthorDate: Fri Feb 18 14:10:56 2022 +0100
Support for generating Micronaut Data entity classes end repository interfaces added. (#3584)
---
enterprise/micronaut/nbproject/project.properties | 1 +
enterprise/micronaut/nbproject/project.xml | 41 +-
.../modules/micronaut/db/Bundle.properties | 44 ++
.../modules/micronaut/db/EntityClassesPanel.form | 247 ++++++
.../modules/micronaut/db/EntityClassesPanel.java | 398 ++++++++++
.../modules/micronaut/db/MicronautEntity.java | 831 +++++++++++++++++++++
.../modules/micronaut/db/MicronautRepository.java | 357 +++++++++
.../org/netbeans/modules/micronaut/db/Utils.java | 41 +
.../micronaut/resources/EntityDatabase.html | 29 +
.../modules/micronaut/resources/Micronaut.html | 28 +
.../modules/micronaut/resources/Repository.html | 29 +
.../netbeans/modules/micronaut/resources/layer.xml | 28 +
java/j2ee.core.utilities/manifest.mf | 2 +-
java/j2ee.core.utilities/nbproject/project.xml | 1 +
java/j2ee.persistence/nbproject/project.properties | 2 +-
java/j2ee.persistence/nbproject/project.xml | 1 +
.../entity/generator/EntitiesFromDBGenerator.java | 40 +-
.../wizard/fromdb/DatabaseTablesPanel.java | 4 +-
.../wizard/fromdb/EntityClassesPanel.java | 23 +-
.../wizard/fromdb/RelatedCMPWizard.java | 26 +-
.../netbeans/modules/nbcode/integration/layer.xml | 1 +
java/java.lsp.server/nbproject/project.xml | 10 +-
.../java/lsp/server/protocol/LspTemplateUI.java | 89 +--
.../lsp/server/protocol/WorkspaceUIContext.java | 5 +
.../lsp/server/ui/NotifyDescriptorAdapter.java | 18 +
.../modules/java/lsp/server/ui/UIContext.java | 13 +
.../lsp/server/ui/AbstractDialogDisplayerTest.java | 9 +
java/java.lsp.server/vscode/src/extension.ts | 9 +-
platform/openide.dialogs/apichanges.xml | 14 +
platform/openide.dialogs/manifest.mf | 2 +-
.../src/org/openide/NotifyDescriptor.java | 173 +++++
31 files changed, 2433 insertions(+), 83 deletions(-)
diff --git a/enterprise/micronaut/nbproject/project.properties b/enterprise/micronaut/nbproject/project.properties
index 2f2157d..5ed4049 100644
--- a/enterprise/micronaut/nbproject/project.properties
+++ b/enterprise/micronaut/nbproject/project.properties
@@ -20,3 +20,4 @@ javac.compilerargs=-Xlint -Xlint:-serial
release.external/spring-boot-configuration-metadata-2.4.4.jar=modules/ext/spring-boot-configuration-metadata-2.4.4.jar
release.external/android-json-0.0.20131108.vaadin1.jar=modules/ext/android-json-0.0.20131108.vaadin1.jar
spec.version.base=1.5.0
+requires.nb.javac=true
diff --git a/enterprise/micronaut/nbproject/project.xml b/enterprise/micronaut/nbproject/project.xml
index 61dc5d8..e6d3c51 100644
--- a/enterprise/micronaut/nbproject/project.xml
+++ b/enterprise/micronaut/nbproject/project.xml
@@ -34,6 +34,15 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.api.java</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>1</release-version>
+ <specification-version>1.82</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.api.java.classpath</code-name-base>
<build-prerequisite/>
<compile-dependency/>
@@ -80,9 +89,7 @@
<code-name-base>org.netbeans.libs.javacapi</code-name-base>
<build-prerequisite/>
<compile-dependency/>
- <run-dependency>
- <specification-version>8.33</specification-version>
- </run-dependency>
+ <run-dependency/>
</dependency>
<dependency>
<code-name-base>org.netbeans.modules.csl.api</code-name-base>
@@ -103,6 +110,15 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.db</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>1</release-version>
+ <specification-version>1.85</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.editor.codetemplates</code-name-base>
<build-prerequisite/>
<compile-dependency/>
@@ -165,6 +181,23 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.j2ee.core.utilities</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>0-1</release-version>
+ <specification-version>1.50</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.j2ee.persistence</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>1.71</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.java.lexer</code-name-base>
<build-prerequisite/>
<compile-dependency/>
@@ -264,7 +297,7 @@
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>7.53</specification-version>
+ <specification-version>7.60</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/Bundle.properties b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/Bundle.properties
new file mode 100644
index 0000000..071d369
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/Bundle.properties
@@ -0,0 +1,44 @@
+# 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.
+
+Templates/Micronaut=Micronaut
+Templates/Micronaut/Entity=Micronaut Data Entity Classes from Database
+Templates/Micronaut/Repository=Micronaut Data Repository Interfaces from Entities
+
+# {0} = entity class name
+TXT_GeneratingClass=Generating the {0} entity class
+# {0} = entity class name
+MSG_Entity_Class=Entity class {0}\n
+
+USG_PERSISTENCE_ENTITY_DB_CREATED={0} entity classes was generated from db
+
+LBL_EntityClasses=Entity Classes
+LBL_AvailableEntities=Available &Entity Classes:
+TXT_AvailableEntities=Available Entity Classes
+ACSN_AvailableEntities=Available entity classes
+ACSD_AvailableEntities=List of all available entity classes
+LBL_SelectedEntities=S&elected Entity Classes:
+TXT_SelectedEntities=Selected Entity Classes
+LBL_AddAll=Add A&ll >>
+LBL_Add=&Add >
+LBL_Remove=< &Remove
+LBL_RemoveAll=<< Re&move All
+ACSN_SelectedEntities=Selected entity classes
+ACSD_SelectedEntities=List of selected entity classes
+ERR_SelectEntities=Select at least one entity class
+# {0} = project name
+ERR_NoEntities=No entity class found in {0}
\ No newline at end of file
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/EntityClassesPanel.form b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/EntityClassesPanel.form
new file mode 100644
index 0000000..0a3bcbb
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/EntityClassesPanel.form
@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+
+ 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.
+
+-->
+
+<Form version="1.3" maxVersion="1.3" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+ <Properties>
+ <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[200, 300]"/>
+ </Property>
+ <Property name="name" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/micronaut/db/Bundle.properties" key="LBL_EntityClasses" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[496, 350]"/>
+ </Property>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+ <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+ <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+ <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+ <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+ <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+ <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,91,0,0,2,115"/>
+ </AuxValues>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+ <SubComponents>
+ <Container class="javax.swing.JPanel" name="entitiesPanel">
+ <Properties>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[440, 174]"/>
+ </Property>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new EntitiesPanel();"/>
+ </AuxValues>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="80" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="2.0"/>
+ </Constraint>
+ </Constraints>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+ <SubComponents>
+ <Component class="javax.swing.JLabel" name="availableEntitiesLabel">
+ <Properties>
+ <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+ <ComponentRef name="availableEntitiesList"/>
+ </Property>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/micronaut/db/Bundle.properties" key="LBL_AvailableEntities" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/micronaut/db/Bundle.properties" key="TXT_AvailableEntities" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
+ </Constraint>
+ </Constraints>
+ </Component>
+ <Container class="javax.swing.JScrollPane" name="availableEntitiesScrollPane">
+ <Properties>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[160, 130]"/>
+ </Property>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+ </AuxValues>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="1.0"/>
+ </Constraint>
+ </Constraints>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+ <SubComponents>
+ <Component class="javax.swing.JList" name="availableEntitiesList">
+ <Properties>
+ <Property name="nextFocusableComponent" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+ <ComponentRef name="addButton"/>
+ </Property>
+ </Properties>
+ <AccessibilityProperties>
+ <Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/micronaut/db/Bundle.properties" key="ACSN_AvailableEntities" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ <Property name="AccessibleContext.accessibleDescription" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/micronaut/db/Bundle.properties" key="ACSD_AvailableEntities" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </AccessibilityProperties>
+ <AuxValues>
+ <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
+ </AuxValues>
+ </Component>
+ </SubComponents>
+ </Container>
+ <Component class="javax.swing.JLabel" name="selectedEntitiesLabel">
+ <Properties>
+ <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+ <ComponentRef name="selectedEntitiesList"/>
+ </Property>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/micronaut/db/Bundle.properties" key="LBL_SelectedEntities" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/micronaut/db/Bundle.properties" key="TXT_SelectedEntities" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
+ </Constraint>
+ </Constraints>
+ </Component>
+ <Container class="javax.swing.JScrollPane" name="selectedEntitiesScrollPane">
+ <Properties>
+ <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+ <Dimension value="[160, 130]"/>
+ </Property>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+ </AuxValues>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="2" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="1.0"/>
+ </Constraint>
+ </Constraints>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+ <SubComponents>
+ <Component class="javax.swing.JList" name="selectedEntitiesList">
+ <AccessibilityProperties>
+ <Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/micronaut/db/Bundle.properties" key="ACSN_SelectedEntities" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ <Property name="AccessibleContext.accessibleDescription" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/micronaut/db/Bundle.properties" key="ACSD_SelectedEntities" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </AccessibilityProperties>
+ <AuxValues>
+ <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
+ </AuxValues>
+ </Component>
+ </SubComponents>
+ </Container>
+ <Container class="javax.swing.JPanel" name="buttonPanel">
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="2" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="11" insetsBottom="0" insetsRight="11" anchor="10" weightX="0.0" weightY="0.0"/>
+ </Constraint>
+ </Constraints>
+
+ <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+ <SubComponents>
+ <Component class="javax.swing.JButton" name="addButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/j2ee/persistence/wizard/fromdb/Bundle.properties" key="LBL_Add" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="addButtonActionPerformed"/>
+ </Events>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
+ </Constraint>
+ </Constraints>
+ </Component>
+ <Component class="javax.swing.JButton" name="removeButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/j2ee/persistence/wizard/fromdb/Bundle.properties" key="LBL_Remove" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="removeButtonActionPerformed"/>
+ </Events>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
+ </Constraint>
+ </Constraints>
+ </Component>
+ <Component class="javax.swing.JButton" name="addAllButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/j2ee/persistence/wizard/fromdb/Bundle.properties" key="LBL_AddAll" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="addAllButtonActionPerformed"/>
+ </Events>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="17" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
+ </Constraint>
+ </Constraints>
+ </Component>
+ <Component class="javax.swing.JButton" name="removeAllButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/j2ee/persistence/wizard/fromdb/Bundle.properties" key="LBL_RemoveAll" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="removeAllButtonActionPerformed"/>
+ </Events>
+ <Constraints>
+ <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+ <GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
+ </Constraint>
+ </Constraints>
+ </Component>
+ </SubComponents>
+ </Container>
+ </SubComponents>
+ </Container>
+ </SubComponents>
+</Form>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/EntityClassesPanel.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/EntityClassesPanel.java
new file mode 100644
index 0000000..ef4515e
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/EntityClassesPanel.java
@@ -0,0 +1,398 @@
+/*
+ * 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.micronaut.db;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Rectangle;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.swing.JPanel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.spi.project.ui.templates.support.Templates;
+import org.openide.WizardDescriptor;
+import org.openide.util.ChangeSupport;
+import org.openide.util.HelpCtx;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class EntityClassesPanel extends javax.swing.JPanel {
+
+ private final ChangeSupport changeSupport = new ChangeSupport(this);
+ private final Set<String> availableEntities = new HashSet<>();
+ private final Set<String> selectedEntities = new HashSet<>();
+
+ public EntityClassesPanel() {
+ initComponents();
+ ListSelectionListener selectionListener = new ListSelectionListener() {
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ updateButtons();
+ }
+ };
+ availableEntitiesList.getSelectionModel().addListSelectionListener(selectionListener);
+ selectedEntitiesList.getSelectionModel().addListSelectionListener(selectionListener);
+ }
+
+ public void addChangeListener(ChangeListener listener) {
+ changeSupport.addChangeListener(listener);
+ }
+
+ public void initialize(Set<String> entities) {
+ availableEntities.addAll(entities);
+ availableEntitiesList.setListData(availableEntities.toArray(new String[availableEntities.size()]));
+ selectedEntitiesList.setListData(selectedEntities.toArray(new String[selectedEntities.size()]));
+ updateButtons();
+ }
+
+ public Set<String> getSelectedEntities() {
+ return selectedEntities;
+ }
+
+ private void updateButtons() {
+ addButton.setEnabled(availableEntitiesList.getSelectedIndices().length > 0);
+ addAllButton.setEnabled(!availableEntities.isEmpty());
+ removeButton.setEnabled(selectedEntitiesList.getSelectedIndices().length > 0);
+ removeAllButton.setEnabled(!selectedEntities.isEmpty());
+ }
+
+ /** This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+ private void initComponents() {
+ java.awt.GridBagConstraints gridBagConstraints;
+
+ entitiesPanel = new EntitiesPanel();
+ availableEntitiesLabel = new javax.swing.JLabel();
+ availableEntitiesScrollPane = new javax.swing.JScrollPane();
+ availableEntitiesList = new javax.swing.JList<>();
+ selectedEntitiesLabel = new javax.swing.JLabel();
+ selectedEntitiesScrollPane = new javax.swing.JScrollPane();
+ selectedEntitiesList = new javax.swing.JList<>();
+ buttonPanel = new javax.swing.JPanel();
+ addButton = new javax.swing.JButton();
+ removeButton = new javax.swing.JButton();
+ addAllButton = new javax.swing.JButton();
+ removeAllButton = new javax.swing.JButton();
+
+ setMinimumSize(new java.awt.Dimension(200, 300));
+ setName(org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "LBL_EntityClasses")); // NOI18N
+ setPreferredSize(new java.awt.Dimension(496, 350));
+ setLayout(new java.awt.GridBagLayout());
+
+ entitiesPanel.setPreferredSize(new java.awt.Dimension(440, 174));
+ entitiesPanel.setLayout(new java.awt.GridBagLayout());
+
+ availableEntitiesLabel.setLabelFor(availableEntitiesList);
+ org.openide.awt.Mnemonics.setLocalizedText(availableEntitiesLabel, org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "LBL_AvailableEntities")); // NOI18N
+ availableEntitiesLabel.setToolTipText(org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "TXT_AvailableEntities")); // NOI18N
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+ gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
+ entitiesPanel.add(availableEntitiesLabel, gridBagConstraints);
+
+ availableEntitiesScrollPane.setPreferredSize(new java.awt.Dimension(160, 130));
+
+ availableEntitiesList.setNextFocusableComponent(addButton);
+ availableEntitiesScrollPane.setViewportView(availableEntitiesList);
+ availableEntitiesList.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "ACSN_AvailableEntities")); // NOI18N
+ availableEntitiesList.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "ACSD_AvailableEntities")); // NOI18N
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.weightx = 1.0;
+ gridBagConstraints.weighty = 1.0;
+ entitiesPanel.add(availableEntitiesScrollPane, gridBagConstraints);
+
+ selectedEntitiesLabel.setLabelFor(selectedEntitiesList);
+ org.openide.awt.Mnemonics.setLocalizedText(selectedEntitiesLabel, org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "LBL_SelectedEntities")); // NOI18N
+ selectedEntitiesLabel.setToolTipText(org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "TXT_SelectedEntities")); // NOI18N
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 2;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+ gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
+ entitiesPanel.add(selectedEntitiesLabel, gridBagConstraints);
+
+ selectedEntitiesScrollPane.setPreferredSize(new java.awt.Dimension(160, 130));
+ selectedEntitiesScrollPane.setViewportView(selectedEntitiesList);
+ selectedEntitiesList.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "ACSN_SelectedEntities")); // NOI18N
+ selectedEntitiesList.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "ACSD_SelectedEntities")); // NOI18N
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 2;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.weightx = 1.0;
+ gridBagConstraints.weighty = 1.0;
+ entitiesPanel.add(selectedEntitiesScrollPane, gridBagConstraints);
+
+ buttonPanel.setLayout(new java.awt.GridBagLayout());
+
+ org.openide.awt.Mnemonics.setLocalizedText(addButton, org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "LBL_Add")); // NOI18N
+ addButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ addButtonActionPerformed(evt);
+ }
+ });
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ buttonPanel.add(addButton, gridBagConstraints);
+
+ org.openide.awt.Mnemonics.setLocalizedText(removeButton, org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "LBL_Remove")); // NOI18N
+ removeButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ removeButtonActionPerformed(evt);
+ }
+ });
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
+ buttonPanel.add(removeButton, gridBagConstraints);
+
+ org.openide.awt.Mnemonics.setLocalizedText(addAllButton, org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "LBL_AddAll")); // NOI18N
+ addAllButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ addAllButtonActionPerformed(evt);
+ }
+ });
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 3;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(17, 0, 0, 0);
+ buttonPanel.add(addAllButton, gridBagConstraints);
+
+ org.openide.awt.Mnemonics.setLocalizedText(removeAllButton, org.openide.util.NbBundle.getMessage(EntityClassesPanel.class, "LBL_RemoveAll")); // NOI18N
+ removeAllButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ removeAllButtonActionPerformed(evt);
+ }
+ });
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 4;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
+ buttonPanel.add(removeAllButton, gridBagConstraints);
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.gridheight = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.insets = new java.awt.Insets(0, 11, 0, 11);
+ entitiesPanel.add(buttonPanel, gridBagConstraints);
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.ipady = 80;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+ gridBagConstraints.weighty = 2.0;
+ gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
+ add(entitiesPanel, gridBagConstraints);
+ }// </editor-fold>//GEN-END:initComponents
+
+ private void removeAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeAllButtonActionPerformed
+ availableEntities.addAll(selectedEntities);
+ selectedEntities.clear();
+ availableEntitiesList.setListData(availableEntities.toArray(new String[availableEntities.size()]));
+ selectedEntitiesList.setListData(selectedEntities.toArray(new String[selectedEntities.size()]));
+ updateButtons();
+ changeSupport.fireChange();
+ }//GEN-LAST:event_removeAllButtonActionPerformed
+
+ private void addAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addAllButtonActionPerformed
+ selectedEntities.addAll(availableEntities);
+ availableEntities.clear();
+ availableEntitiesList.setListData(availableEntities.toArray(new String[availableEntities.size()]));
+ selectedEntitiesList.setListData(selectedEntities.toArray(new String[selectedEntities.size()]));
+ updateButtons();
+ changeSupport.fireChange();
+ }//GEN-LAST:event_addAllButtonActionPerformed
+
+ private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeButtonActionPerformed
+ availableEntities.addAll(selectedEntitiesList.getSelectedValuesList());
+ selectedEntities.removeAll(selectedEntitiesList.getSelectedValuesList());
+ availableEntitiesList.setListData(availableEntities.toArray(new String[availableEntities.size()]));
+ selectedEntitiesList.setListData(selectedEntities.toArray(new String[selectedEntities.size()]));
+ updateButtons();
+ changeSupport.fireChange();
+ }//GEN-LAST:event_removeButtonActionPerformed
+
+ private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed
+ selectedEntities.addAll(availableEntitiesList.getSelectedValuesList());
+ availableEntities.removeAll(availableEntitiesList.getSelectedValuesList());
+ availableEntitiesList.setListData(availableEntities.toArray(new String[availableEntities.size()]));
+ selectedEntitiesList.setListData(selectedEntities.toArray(new String[selectedEntities.size()]));
+ updateButtons();
+ changeSupport.fireChange();
+ }//GEN-LAST:event_addButtonActionPerformed
+
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JButton addAllButton;
+ private javax.swing.JButton addButton;
+ private javax.swing.JLabel availableEntitiesLabel;
+ private javax.swing.JList<String> availableEntitiesList;
+ private javax.swing.JScrollPane availableEntitiesScrollPane;
+ private javax.swing.JPanel buttonPanel;
+ private javax.swing.JPanel entitiesPanel;
+ private javax.swing.JButton removeAllButton;
+ private javax.swing.JButton removeButton;
+ private javax.swing.JLabel selectedEntitiesLabel;
+ private javax.swing.JList<String> selectedEntitiesList;
+ private javax.swing.JScrollPane selectedEntitiesScrollPane;
+ // End of variables declaration//GEN-END:variables
+
+ private final class EntitiesPanel extends JPanel {
+
+ @Override
+ public void doLayout() {
+ super.doLayout();
+
+ Rectangle availableBounds = availableEntitiesScrollPane.getBounds();
+ Rectangle selectedBounds = selectedEntitiesScrollPane.getBounds();
+
+ if (Math.abs(availableBounds.width - selectedBounds.width) > 1) {
+ GridBagConstraints buttonPanelConstraints = ((GridBagLayout)getLayout()).getConstraints(buttonPanel);
+ int totalWidth = getWidth() - buttonPanel.getWidth() - buttonPanelConstraints.insets.left - buttonPanelConstraints.insets.right;
+ int equalWidth = totalWidth / 2;
+ int xOffset = equalWidth - availableBounds.width;
+
+ availableBounds.width = equalWidth;
+ availableEntitiesScrollPane.setBounds(availableBounds);
+
+ Rectangle buttonBounds = buttonPanel.getBounds();
+ buttonBounds.x += xOffset;
+ buttonPanel.setBounds(buttonBounds);
+
+ Rectangle labelBounds = selectedEntitiesLabel.getBounds();
+ labelBounds.x += xOffset;
+ selectedEntitiesLabel.setBounds(labelBounds);
+
+ selectedBounds.x += xOffset;
+ selectedBounds.width = totalWidth - equalWidth;
+ selectedEntitiesScrollPane.setBounds(selectedBounds);
+ }
+ }
+ }
+
+ public static final class WizardPanel implements WizardDescriptor.Panel<WizardDescriptor>, ChangeListener {
+
+ private final ChangeSupport changeSupport = new ChangeSupport(this);
+ private final String title;
+ private EntityClassesPanel component;
+ private boolean componentInitialized;
+ private WizardDescriptor wizardDescriptor;
+ private Map<String, String> entities;
+
+ public WizardPanel(String wizardTitle) {
+ title = wizardTitle;
+ }
+
+ @Override
+ public EntityClassesPanel getComponent() {
+ if (component == null) {
+ component = new EntityClassesPanel();
+ component.addChangeListener(this);
+ }
+ return component;
+ }
+
+ @Override
+ public HelpCtx getHelp() {
+ return new HelpCtx(EntityClassesPanel.class);
+ }
+
+ @Override
+ public void addChangeListener(ChangeListener listener) {
+ changeSupport.addChangeListener(listener);
+ }
+
+ @Override
+ public void removeChangeListener(ChangeListener listener) {
+ changeSupport.removeChangeListener(listener);
+ }
+
+ @Override
+ public void readSettings(WizardDescriptor settings) {
+ wizardDescriptor = settings;
+ if (title != null) {
+ wizardDescriptor.putProperty("NewFileWizard_Title", title); // NOI18N
+ }
+ if (!componentInitialized) {
+ componentInitialized = true;
+ entities = (Map<String, String>) settings.getProperty(MicronautRepository.PROP_ENTITIES);
+ getComponent().initialize(entities.keySet());
+ }
+ }
+
+ @Override
+ public boolean isValid() {
+ if (entities.isEmpty()) {
+ setErrorMessage(NbBundle.getMessage(EntityClassesPanel.class, "ERR_NoEntities", ProjectUtils.getInformation(Templates.getProject(wizardDescriptor)).getDisplayName()));
+ return false;
+ }
+ if (getComponent().getSelectedEntities().isEmpty()) {
+ setErrorMessage(NbBundle.getMessage(EntityClassesPanel.class, "ERR_SelectEntities"));
+ return false;
+ }
+ setErrorMessage(" "); // NOI18N
+ return true;
+ }
+
+ @Override
+ public void storeSettings(WizardDescriptor settings) {
+ Set<String> selected = getComponent().getSelectedEntities();
+ Map<String, String> selEntities = entities.entrySet().stream().filter(entry -> selected.contains(entry.getKey())).collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));
+ wizardDescriptor.putProperty(MicronautRepository.PROP_SELECTED_ENTITIES, selEntities);
+ }
+
+ @Override
+ public void stateChanged(ChangeEvent event) {
+ changeSupport.fireChange();
+ }
+
+ private void setErrorMessage(String errorMessage) {
+ wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, errorMessage);
+ }
+ }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautEntity.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautEntity.java
new file mode 100644
index 0000000..95c224b
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautEntity.java
@@ -0,0 +1,831 @@
+/*
+ * 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.micronaut.db;
+
+import com.sun.source.tree.AnnotationTree;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import org.netbeans.api.db.explorer.ConnectionManager;
+import org.netbeans.api.db.explorer.DatabaseConnection;
+import org.netbeans.api.db.explorer.DatabaseException;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.classpath.JavaClassPathConstants;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.api.java.source.WorkingCopy;
+import org.netbeans.api.progress.aggregate.BasicAggregateProgressFactory;
+import org.netbeans.api.progress.aggregate.ProgressContributor;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.api.templates.CreateDescriptor;
+import org.netbeans.api.templates.CreateFromTemplateHandler;
+import org.netbeans.modules.j2ee.core.api.support.SourceGroups;
+import org.netbeans.modules.j2ee.core.api.support.java.GenerationUtils;
+import org.netbeans.modules.j2ee.core.api.support.java.SourceUtils;
+import org.netbeans.modules.j2ee.persistence.api.entity.generator.EntitiesFromDBGenerator;
+import org.netbeans.modules.j2ee.persistence.dd.PersistenceUtils;
+import org.netbeans.modules.j2ee.persistence.entitygenerator.CMPMappingModel;
+import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityClass;
+import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityMember;
+import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation;
+import org.netbeans.modules.j2ee.persistence.entitygenerator.RelationshipRole;
+import org.netbeans.modules.j2ee.persistence.util.JPAClassPathHelper;
+import org.netbeans.modules.j2ee.persistence.wizard.fromdb.JavaPersistenceGenerator;
+import org.netbeans.modules.j2ee.persistence.wizard.fromdb.PersistenceGenerator;
+import org.netbeans.modules.j2ee.persistence.wizard.fromdb.PersistenceGeneratorProvider;
+import org.netbeans.modules.j2ee.persistence.wizard.fromdb.ProgressPanel;
+import org.netbeans.modules.j2ee.persistence.wizard.fromdb.RelatedCMPHelper;
+import org.netbeans.modules.j2ee.persistence.wizard.fromdb.RelatedCMPWizard;
+import org.netbeans.modules.j2ee.persistence.wizard.fromdb.UpdateType;
+import org.openide.DialogDescriptor;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.TemplateWizard;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class MicronautEntity extends RelatedCMPWizard {
+
+ private static final String TYPE_MICRONAUT = "micronaut"; // NOI18N
+
+ public static MicronautEntity create() {
+ return new MicronautEntity(TYPE_MICRONAUT);
+ }
+
+ @NbBundle.Messages({
+ "MSG_NoDbConn=No database connection found",
+ "MSG_NoProject=No project found for {0}",
+ "MSG_NoSourceGroup=No source group found for {0}",
+ "MSG_SelectTables=Select Database Tables",
+ "MSG_NoDbTables=No database table found for {0}"
+ })
+ public static CreateFromTemplateHandler handler() {
+ return new CreateFromTemplateHandler() {
+ @Override
+ protected boolean accept(CreateDescriptor desc) {
+ return true;
+ }
+
+ @Override
+ protected List<FileObject> createFromTemplate(CreateDescriptor desc) throws IOException {
+ try {
+ FileObject folder = desc.getTarget();
+ Project project = FileOwnerQuery.getOwner(folder);
+ if (project == null) {
+ DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(Bundle.MSG_NoProject(folder.getPath()), NotifyDescriptor.ERROR_MESSAGE));
+ return Collections.emptyList();
+ }
+ SourceGroup sourceGroup = SourceGroups.getFolderSourceGroup(ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA), folder);
+ if (sourceGroup == null) {
+ DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(Bundle.MSG_NoSourceGroup(folder.getPath()), NotifyDescriptor.ERROR_MESSAGE));
+ return Collections.emptyList();
+ }
+ DatabaseConnection connection = ConnectionManager.getDefault().getPreferredConnection(true);
+ if (connection == null) {
+ DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(Bundle.MSG_NoDbConn(), NotifyDescriptor.ERROR_MESSAGE));
+ return Collections.emptyList();
+ }
+ ConnectionManager.getDefault().connect(connection);
+ Connection conn = connection.getJDBCConnection();
+ ResultSet rs = conn.getMetaData().getTables(conn.getCatalog(), conn.getSchema(), "%", new String[]{"TABLE", "VIEW"}); //NOI18N
+ List<NotifyDescriptor.QuickPick.Item> dbItems = new ArrayList<>();
+ while (rs.next()) {
+ dbItems.add(new NotifyDescriptor.QuickPick.Item(rs.getString("TABLE_NAME"), null)); //NOI18N
+ }
+ if (dbItems.isEmpty()) {
+ DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(Bundle.MSG_NoDbTables(connection.getDisplayName()), NotifyDescriptor.ERROR_MESSAGE));
+ return Collections.emptyList();
+ }
+ NotifyDescriptor.QuickPick qp = new NotifyDescriptor.QuickPick(Bundle.MSG_SelectTables(), Bundle.MSG_SelectTables(), dbItems, true);
+ if (DialogDescriptor.OK_OPTION == DialogDisplayer.getDefault().notify(qp)) {
+ List<String> selectedItems = qp.getItems().stream().filter(item -> item.isSelected()).map(item -> item.getLabel()).collect(Collectors.toList());
+ EntitiesFromDBGenerator generator = new EntitiesFromDBGenerator(selectedItems, false, false, false,
+ EntityRelation.FetchType.DEFAULT, EntityRelation.CollectionType.COLLECTION,
+ SourceGroups.getPackageForFolder(sourceGroup, folder), sourceGroup, connection, project, null, new Generator());
+ ProgressContributor pc = BasicAggregateProgressFactory.createProgressContributor("entity"); //NOI18N\
+ List<FileObject> generated = new ArrayList<>();
+ for (FileObject fo : generator.generate(pc)) {
+ if (fo != null) {
+ generated.add(fo);
+ }
+ }
+ return generated;
+ }
+ } catch (IOException | SQLException | DatabaseException ex) {
+ DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(ex.getMessage(), NotifyDescriptor.ERROR_MESSAGE));
+ }
+ return Collections.emptyList();
+ }
+ };
+ }
+
+ private MicronautEntity(String type) {
+ super(type);
+ }
+
+ @Override
+ public Set<DataObject> instantiate(TemplateWizard wiz) throws IOException {
+ String wizardTitle = NbBundle.getMessage(MicronautEntity.class, "Templates/Micronaut/Entity");
+ wiz.putProperty("NewFileWizard_Title", wizardTitle); // NOI18N
+ return super.instantiate(wiz);
+ }
+
+ @org.openide.util.lookup.ServiceProvider(service=org.netbeans.modules.j2ee.persistence.wizard.fromdb.PersistenceGeneratorProvider.class)
+ public static class GeneratorProvider implements PersistenceGeneratorProvider {
+
+ @Override
+ public String getGeneratorType() {
+ return TYPE_MICRONAUT;
+ }
+
+ @Override
+ public PersistenceGenerator createGenerator() {
+ return new Generator();
+ }
+ }
+
+ private static class Generator extends JavaPersistenceGenerator {
+
+ private final Set<FileObject> generatedEntityFOs = new HashSet<>();
+ private final Map<String, String> replacedNames = new HashMap<>();
+ private final Map<String, String> replacedTypeNames = new HashMap<>();
+ private final Map<String, EntityClass> beanMap = new HashMap<>();
+
+ @Override
+ public Set<FileObject> createdObjects() {
+ return generatedEntityFOs;
+ }
+
+ @Override
+ public void generateBeans(ProgressPanel progressPanel, RelatedCMPHelper helper, FileObject dbschemaFile, ProgressContributor progressContributor) throws IOException {
+ try {
+ doGenerateBeans(progressPanel, helper, progressContributor);
+ } catch (IOException e) {
+ Logger.getLogger(Generator.class.getName()).log(Level.INFO, "IOException, remove generated."); //NOI18N
+ for (FileObject generatedFO : generatedEntityFOs) {
+ try {
+ generatedFO.delete();
+ } catch (IOException ioe) {}
+ }
+ throw e;
+ }
+ }
+
+ private void doGenerateBeans(ProgressPanel progressPanel, RelatedCMPHelper helper, ProgressContributor progressContributor) throws IOException {
+ if (helper.getLocation() != null && helper.getPackageName() != null) {
+ SourceGroups.getFolderForPackage(helper.getLocation(), helper.getPackageName());
+ }
+
+ final boolean jpaSupported = Utils.isJPASupported(helper.getLocation());
+ final boolean beanValidationSupported = isBeanValidationSupported(helper.getLocation());
+
+ EntityClass[] entityClasses = helper.getBeans();
+ int progressMax = entityClasses.length * 2;
+ progressContributor.start(progressMax);
+
+ beanMap.clear();
+ Set<FileObject> generationPackageFOs = new HashSet<>();
+ Set<String> generatedEntityClasses = new HashSet<>();
+
+ for (int i = 0; i < entityClasses.length; i++) {
+ final EntityClass entityClass = entityClasses[i];
+ String entityClassName = entityClass.getClassName();
+ FileObject packageFileObject = entityClass.getPackageFileObject();
+ beanMap.put(entityClassName, entityClass);
+
+ String progressMsg = NbBundle.getMessage(Generator.class, "TXT_GeneratingClass", entityClassName);
+ progressContributor.progress(progressMsg, i);
+ if (progressPanel != null) {
+ progressPanel.setText(progressMsg);
+ }
+
+ FileObject entity = packageFileObject.getFileObject(entityClassName, "java"); //NOI18N
+ switch (entityClass.getUpdateType()) {
+ case RECREATE:
+ case UPDATE:
+ if (entity == null) {//we hit case when old entity position is different from target package
+ String fqn = this.getFQClassName(entityClass.getTableName());
+ int ind = fqn.lastIndexOf(".");
+ String pkg = ind > -1 ? fqn.substring(0, ind) : "";
+ String rel = pkg.replaceAll("\\.", "/");
+ FileObject oldPackage = entityClass.getRootFolder().getFileObject(rel);
+ entity = oldPackage.getFileObject(entityClassName, "java");
+ }
+ entity.delete();
+ entity = null;
+ //fall through is expected
+ case NEW:
+ generatedEntityClasses.add(entityClassName);
+ try {
+ String newName = entityClassName;
+ int count = 1;
+ while (packageFileObject.getFileObject(newName, "java") != null && count < 1000) {
+ newName = entityClassName + "_" + count;
+ count++;
+ }
+ entity = GenerationUtils.createClass(packageFileObject, newName, NbBundle.getMessage(Generator.class, "MSG_Entity_Class", newName));
+ if (!newName.equals(entityClassName)) {
+ replacedNames.put(entityClassName, newName);
+ String pkg = entityClass.getPackage();
+ String entityClassFQN = pkg == null || pkg.isEmpty() ? entityClassName : pkg + "." + entityClassName;
+ String newFQN = pkg == null || pkg.isEmpty() ? newName : pkg + "." + newName;
+ replacedTypeNames.put(entityClassFQN, newFQN);
+ generatedEntityClasses.remove(entityClassName);
+ generatedEntityClasses.add(newName);
+ }
+ } catch (RuntimeException ex) {
+ Logger.getLogger(Generator.class.getName()).log(Level.WARNING, "Can't create class {0} from template in package {1} with package fileobject validity {2}.", new Object[]{entityClassName, packageFileObject.getPath(), packageFileObject.isValid()});//NOI18N
+ throw ex;
+ }
+ generatedEntityFOs.add(entity);
+ generationPackageFOs.add(packageFileObject);
+ }
+ }
+
+ Set<ClassPath> bootCPs = getAllClassPaths(generationPackageFOs, ClassPath.BOOT);
+ Set<ClassPath> compileCPs = getAllClassPaths(generationPackageFOs, ClassPath.COMPILE);
+ Set<ClassPath> sourceCPs = getAllClassPaths(generationPackageFOs, ClassPath.SOURCE);
+ JPAClassPathHelper cpHelper = new JPAClassPathHelper(bootCPs, compileCPs, sourceCPs)
+ .setModuleBootPaths(getAllClassPaths(generationPackageFOs, JavaClassPathConstants.MODULE_BOOT_PATH))
+ .setModuleCompilePaths(getAllClassPaths(generationPackageFOs, JavaClassPathConstants.MODULE_COMPILE_PATH))
+ .setModuleClassPaths(getAllClassPaths(generationPackageFOs, JavaClassPathConstants.MODULE_CLASS_PATH))
+ .setModuleSourcePaths(getAllClassPaths(generationPackageFOs, JavaClassPathConstants.MODULE_SOURCE_PATH));
+
+ for (int i = 0; i < entityClasses.length; i++) {
+ final EntityClass entityClass = entityClasses[i];
+ String entityClassName = getClassName(entityClass);
+
+ if (!generatedEntityClasses.contains(entityClassName) && !UpdateType.UPDATE.equals(entityClass.getUpdateType())) {
+ // this entity class already existed, we didn't create it, so we don't want to touch it except Update type
+ progressContributor.progress(entityClasses.length + i);
+ continue;
+ }
+ String progressMsg = NbBundle.getMessage(Generator.class, "TXT_GeneratingClass", entityClassName);
+ progressContributor.progress(progressMsg, entityClasses.length + i);
+ if (progressPanel != null) {
+ progressPanel.setText(progressMsg);
+ }
+ FileObject entityClassPackageFO = entityClass.getPackageFileObject();
+ FileObject entityClassFO = entityClassPackageFO.getFileObject( entityClassName, "java"); // NOI18N
+ try {
+ JavaSource javaSource = JavaSource.create(cpHelper.createClasspathInfo(), entityClassFO);
+ javaSource.runModificationTask(copy -> {
+ new EntityClassGenerator(copy, entityClass, jpaSupported, beanValidationSupported).run();
+ }).commit();
+ } catch (IOException e) {
+ String message = e.getMessage();
+ String newMessage = ((message == null)
+ ? NbBundle.getMessage(Generator.class, "ERR_GeneratingClass_NoExceptionMessage", entityClassName)
+ : NbBundle.getMessage(Generator.class, "ERR_GeneratingClass", entityClassName, message));
+ throw new IOException(newMessage, e);
+ }
+ }
+
+ progressContributor.progress(progressMax);
+ PersistenceUtils.logUsage(Generator.class, "USG_PERSISTENCE_ENTITY_DB_CREATED", new Integer[]{entityClasses.length});
+ }
+
+ private String getClassName(EntityClass entityClass) {
+ return replacedNames.containsKey(entityClass.getClassName()) ? replacedNames.get(entityClass.getClassName()) : entityClass.getClassName();
+ }
+
+ private static Set<ClassPath> getAllClassPaths(Set<FileObject> fileObjects, String id) {
+ Set<ClassPath> classPaths = new HashSet<>();
+ for (FileObject fileObject : fileObjects) {
+ ClassPath cp = ClassPath.getClassPath(fileObject, id);
+ if (cp != null) {
+ classPaths.add(cp);
+ }
+ }
+ return classPaths;
+ }
+
+ private static boolean isBeanValidationSupported(SourceGroup sg) {
+ if (sg == null) {
+ return false;
+ }
+ ClassPath compile = ClassPath.getClassPath(sg.getRootFolder(), ClassPath.COMPILE);
+ if (compile == null) {
+ return false;
+ }
+ final String notNullAnnotation = "javax.validation.constraints.NotNull"; //NOI18N
+ return compile.findResource(notNullAnnotation.replace('.', '/') + ".class") != null; //NOI18N
+ }
+
+ private abstract class ClassGenerator {
+
+ protected final WorkingCopy copy;
+ protected final GenerationUtils genUtils;
+ // the entity class we are generating
+ protected final EntityClass entityClass;
+ // the mapping of the entity class to the database
+ protected final CMPMappingModel dbMappings;
+ // generated properties
+ protected final List<Property> properties = new ArrayList<>();
+ // generated methods
+ protected final List<MethodTree> methods = new ArrayList<>();
+ // generated constructors
+ protected final List<MethodTree> constructors = new ArrayList<>();
+ // generated fields. does not include fields of properties, just plain fields
+ protected final List<VariableTree> fields = new ArrayList<>();
+ // the original class tree of the class we are generating
+ protected ClassTree originalClassTree;
+ // the modified class tree of the class we are generating
+ protected ClassTree newClassTree;
+ // the TypeElement corresponding to classTree
+ protected TypeElement typeElement;
+ // classTree's module
+ protected ModuleElement moduleElement;
+ // the generating type like New, Update etc
+ protected UpdateType updateType;
+
+ protected final boolean generateJPA;
+ protected final boolean generateValidationConstraints;
+
+ private ClassGenerator(WorkingCopy copy, EntityClass entityClass, boolean jpaSupported, boolean beanValidationSupported) throws IOException {
+ copy.toPhase(JavaSource.Phase.RESOLVED);
+ this.copy = copy;
+ this.entityClass = entityClass;
+ this.updateType = entityClass.getUpdateType();
+ dbMappings = entityClass.getCMPMapping();
+ typeElement = SourceUtils.getPublicTopLevelElement(copy);
+ if (typeElement == null) {
+ throw new IllegalStateException("Cannot find a public top-level class named " + entityClass.getClassName() + // NOI18N
+ " in " + FileUtil.getFileDisplayName(copy.getFileObject())); // NOI18N
+ }
+ moduleElement = copy.getElements().getModuleOf(typeElement);
+ originalClassTree = copy.getTrees().getTree(typeElement);
+ assert originalClassTree != null;
+ newClassTree = originalClassTree;
+ genUtils = GenerationUtils.newInstance(copy);
+ generateJPA = jpaSupported;
+ generateValidationConstraints = beanValidationSupported;
+ }
+
+ protected String createFieldName(String capitalizedFieldName) {
+ return createFieldNameImpl(capitalizedFieldName, false);
+ }
+
+ protected String createCapitalizedFieldName(String fieldName) {
+ return createFieldNameImpl(fieldName, true);
+ }
+
+ private String createFieldNameImpl(String fieldName, boolean capitalized) {
+ StringBuilder sb = new StringBuilder(fieldName);
+ char firstChar = sb.charAt(0);
+ sb.setCharAt(0, capitalized ? Character.toUpperCase(firstChar) : Character.toLowerCase(firstChar));
+ return sb.toString();
+ }
+
+ /**
+ * Creates a property for an entity member, that is, is creates
+ * a field, a getter and a setter method.
+ */
+ protected Property createProperty(EntityMember m) throws IOException {
+ boolean isPKMember = m.isPrimaryKey();
+ List<AnnotationTree> annotations = new ArrayList<>();
+
+ //add @Id() only if not in an embeddable PK class
+ if (isPKMember) {
+ annotations.add(genUtils.createAnnotation(generateJPA ? "javax.persistence.Id" : "io.micronaut.data.annotation.Id")); // NOI18N
+ if (m.isAutoIncrement()) {
+ annotations.add(genUtils.createAnnotation(generateJPA ? "javax.persistence.GeneratedValue" : "io.micronaut.data.annotation.GeneratedValue")); //NOI18N
+ }
+ }
+
+ if (!m.isNullable()) {
+ //Add @NotNull constraint
+ if (generateValidationConstraints && !m.isAutoIncrement()) { //NOI18N
+ annotations.add(genUtils.createAnnotation("javax.validation.constraints.NotNull")); //NOI18N
+ }
+ }
+
+ boolean isLobType = m.isLobType();
+ if (isLobType && generateJPA) {
+ annotations.add(genUtils.createAnnotation("javax.persistence.Lob")); // NOI18N
+ }
+
+ List<ExpressionTree> columnAnnArguments = new ArrayList<>();
+ String memberName = m.getMemberName();
+ String memberType = getMemberType(m);
+
+ String columnName = dbMappings.getCMPFieldMapping().get(memberName);
+ if (!memberName.equalsIgnoreCase(columnName)){
+ columnAnnArguments.add(genUtils.createAnnotationArgument("name", columnName)); //NOI18N
+ }
+
+ Integer length = m.getLength();
+ if (length != null && isCharacterType(memberType)) {
+ if (generateValidationConstraints) {
+ List <ExpressionTree> sizeAnnArguments = new ArrayList<>();
+ if (!m.isNullable()) {
+ sizeAnnArguments.add(genUtils.createAnnotationArgument("min", 1)); //NOI18N
+ }
+ sizeAnnArguments.add(genUtils.createAnnotationArgument("max", length)); //NOI18N
+ annotations.add(genUtils.createAnnotation("javax.validation.constraints.Size", sizeAnnArguments)); //NOI18N
+ }
+ }
+
+ if (!columnAnnArguments.isEmpty() && generateJPA) {
+ annotations.add(genUtils.createAnnotation("javax.persistence.Column", columnAnnArguments)); //NOI18N
+ }
+
+ String temporalType = getMemberTemporalType(m);
+ if (temporalType != null && generateJPA) {
+ ExpressionTree temporalAnnValueArgument = genUtils.createAnnotationArgument(null, "javax.persistence.TemporalType", temporalType); //NOI18N
+ annotations.add(genUtils.createAnnotation("javax.persistence.Temporal", Collections.singletonList(temporalAnnValueArgument)));
+ }
+
+ return new Property(Modifier.PRIVATE, annotations, memberType, memberName);
+ }
+
+ 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";
+ }
+ return memberType;
+ }
+
+ private boolean isCharacterType(String type) {
+ return "java.lang.String".equals(type); //NOI18N
+ }
+
+ private String getMemberTemporalType(EntityMember m) {
+ String memberType = m.getMemberType();
+ String temporalType = null;
+ if ("java.sql.Date".equals(memberType)) { //NOI18N
+ temporalType = "DATE";
+ } else if ("java.sql.Time".equals(memberType)) { //NOI18N
+ temporalType = "TIME";
+ } else if ("java.sql.Timestamp".equals(memberType)) { //NOI18N
+ temporalType = "TIMESTAMP";
+ }
+ return temporalType;
+ }
+
+ public void run() throws IOException {
+ initialize();
+ for (Object object : entityClass.getFields()) {
+ generateMember((EntityMember) object);
+ }
+ for (RelationshipRole roleObject : entityClass.getRoles()) {
+ generateRelationship(roleObject);
+ }
+ finish();
+
+ // add the generated members
+ TreeMaker make = copy.getTreeMaker();
+ int position = 0;
+ for (VariableTree field : fields) {
+ newClassTree = make.insertClassMember(newClassTree, position, field);
+ position++;
+ }
+ for (Property property : properties) {
+ newClassTree = make.insertClassMember(newClassTree, position, property.getField());
+ position++;
+ }
+ for (MethodTree constructor : constructors) {
+ newClassTree = make.addClassMember(newClassTree, constructor);
+ }
+ for (Property property : properties) {
+ newClassTree = make.addClassMember(newClassTree, property.getGetter());
+ newClassTree = make.addClassMember(newClassTree, property.getSetter());
+ }
+ for (MethodTree method : methods) {
+ newClassTree = make.addClassMember(newClassTree, method);
+ }
+ Logger.getLogger(Generator.class.getName()).log(Level.FINE, "Rewrite entity tree with name: {0}", entityClass.getTableName()); //NOI18N
+ Logger.getLogger(Generator.class.getName()).log(Level.FINE, "Rewrite entity tree with annotations: length = {0}, annotations = {1}", new Object[]{newClassTree.getModifiers().getAnnotations().size(), newClassTree.getModifiers().getAnnotations()}); //NOI18N
+ copy.rewrite(originalClassTree, newClassTree);
+ }
+
+ /**
+ * Called at the beginning of the generation process.
+ */
+ protected abstract void initialize() throws IOException;
+
+ /**
+ * Called for each entity class member.
+ */
+ protected abstract void generateMember(EntityMember m) throws IOException;
+
+ /**
+ * Called for each relationship.
+ */
+ protected abstract void generateRelationship(RelationshipRole role) throws IOException;
+
+ /**
+ * Called at the end of the generation process.
+ */
+ protected abstract void finish() throws IOException;
+
+ /**
+ * Encapsulates a generated property, that is, its field, getter
+ * and setter method.
+ */
+ protected final class Property {
+
+ private final VariableTree field;
+ private final MethodTree getter;
+ private final MethodTree setter;
+
+ public Property(Modifier modifier, List<AnnotationTree> annotations, String type, String name) throws IOException {
+ this(modifier, annotations, genUtils.createType(type, typeElement), name);
+ }
+
+ public Property(Modifier modifier, List<AnnotationTree> annotations, TypeMirror type, String name) throws IOException {
+ this(modifier, annotations, copy.getTreeMaker().Type(type), name);
+ }
+
+ private Property(Modifier modifier, List<AnnotationTree> annotations, Tree typeTree, String name) throws IOException {
+ TreeMaker make = copy.getTreeMaker();
+ field = make.Variable(
+ make.Modifiers(EnumSet.of(modifier), annotations),
+ name,
+ typeTree,
+ null);
+ getter = genUtils.createPropertyGetterMethod(
+ make.Modifiers(EnumSet.of(Modifier.PUBLIC), Collections.<AnnotationTree>emptyList()),
+ name,
+ typeTree);
+ setter = genUtils.createPropertySetterMethod(
+ genUtils.createModifiers(Modifier.PUBLIC),
+ name,
+ typeTree);
+ }
+
+ public VariableTree getField() {
+ return field;
+ }
+
+ public MethodTree getGetter() {
+ return getter;
+ }
+
+ public MethodTree getSetter() {
+ return setter;
+ }
+ }
+ }
+
+ private class EntityClassGenerator extends ClassGenerator {
+
+ // the simple name of the entity class
+ private final String entityClassName;
+ // the non-nullable properties (not including the primary key ones)
+ private final List<Property> nonNullableProps = new ArrayList<>();
+ // the names of the primary key columns
+ private final List<String> pkColumnNames = new ArrayList<>();
+ private Property pkProperty;
+ private boolean pkGenerated;
+
+ public EntityClassGenerator(WorkingCopy copy, EntityClass entityClass, boolean jpaSupported, boolean beanValidationSupported) throws IOException {
+ super(copy, entityClass, jpaSupported, beanValidationSupported);
+ entityClassName = getClassName(entityClass);
+ assert typeElement.getSimpleName().contentEquals(entityClassName);
+ }
+
+ @Override
+ protected void initialize() throws IOException {
+ if (generateJPA) {
+ newClassTree = genUtils.addAnnotation(newClassTree, genUtils.createAnnotation("javax.persistence.Entity")); //NOI18N
+ if (dbMappings.getTableName() != null && !entityClassName.equalsIgnoreCase(dbMappings.getTableName())) {
+ List<ExpressionTree> tableAnnArgs = Collections.singletonList(genUtils.createAnnotationArgument("name", dbMappings.getTableName())); //NOI18N
+ newClassTree = genUtils.addAnnotation(newClassTree, genUtils.createAnnotation("javax.persistence.Table", tableAnnArgs)); //NOI18N
+ }
+ } else if (dbMappings.getTableName() != null && !entityClassName.equalsIgnoreCase(dbMappings.getTableName())) {
+ List<ExpressionTree> tableAnnArgs = Collections.singletonList(genUtils.createAnnotationArgument(null, dbMappings.getTableName())); //NOI18N
+ newClassTree = genUtils.addAnnotation(newClassTree, genUtils.createAnnotation("io.micronaut.data.annotation.MappedEntity", tableAnnArgs)); //NOI18N
+ } else {
+ newClassTree = genUtils.addAnnotation(newClassTree, genUtils.createAnnotation("io.micronaut.data.annotation.MappedEntity")); //NOI18N
+ }
+ }
+
+ @Override
+ protected void generateMember(EntityMember m) throws IOException {
+ //skip generating already exist members for UPDATE type
+ String memberName = m.getMemberName();
+ boolean isPKMember = m.isPrimaryKey();
+ Property property;
+ if (isPKMember) {
+ pkProperty = property = createProperty(m);
+ String pkColumnName = dbMappings.getCMPFieldMapping().get(memberName);
+ pkColumnNames.add(pkColumnName);
+ pkGenerated = m.isAutoIncrement();
+ } else {
+ property = createProperty(m);
+ if (!m.isNullable()) {
+ nonNullableProps.add(property);
+ }
+ }
+ properties.add(property);
+ }
+
+ @Override
+ protected void generateRelationship(RelationshipRole role) throws IOException {
+ String memberName = role.getFieldName();
+ if (memberName.endsWith("Collection")) { // NOI18N
+ memberName = memberName.substring(0, memberName.length() - 10);
+ memberName += memberName.endsWith("s") ? "es" : "s"; // NOI18N
+ }
+ String typeName = getRelationshipFieldType(role, entityClass.getPackage());
+ if(replacedTypeNames.containsKey(typeName)) {
+ typeName = replacedTypeNames.get(typeName);
+ }
+ TypeElement typeEl = moduleElement != null
+ ? copy.getElements().getTypeElement(moduleElement, typeName)
+ : copy.getElements().getTypeElement(typeName);
+ assert typeEl != null : "null TypeElement for \"" + typeName + "\"";
+ String collectionType = "java.util.Set"; //NOI18N
+ TypeMirror fieldType = typeEl.asType();
+ if (role.isToMany()) {
+ TypeElement collectionTypeElem = moduleElement != null
+ ? copy.getElements().getTypeElement(moduleElement, collectionType)
+ : copy.getElements().getTypeElement(collectionType);
+ fieldType = copy.getTypes().getDeclaredType(collectionTypeElem, fieldType);
+ }
+ List<AnnotationTree> annotations = new ArrayList<>();
+ List<ExpressionTree> annArguments = new ArrayList<>();
+ if (role.isCascade()) {
+ annArguments.add(genUtils.createAnnotationArgument("cascade", generateJPA ? "javax.persistence.CascadeType" : "io.micronaut.data.annotation.Relation.Cascade", "ALL")); // NOI18N
+ }
+ if (role.equals(role.getParent().getRoleB())) { // Role B
+ String fName = role.getParent().getRoleA().getFieldName();
+ annArguments.add(genUtils.createAnnotationArgument("mappedBy", fName)); // NOI18N
+ } else if (generateJPA) { // Role A
+ if (role.isMany() && role.isToMany()) { // ManyToMany
+ List<ExpressionTree> joinTableAnnArguments = new ArrayList<>();
+ String jTN = dbMappings.getJoinTableMapping().get(role.getFieldName());
+ joinTableAnnArguments.add(genUtils.createAnnotationArgument("name", jTN)); //NOI18N
+ CMPMappingModel.JoinTableColumnMapping joinColumnMap = dbMappings.getJoinTableColumnMppings().get(role.getFieldName());
+ CMPMappingModel.ColumnData[] columns = joinColumnMap.getColumns();
+ CMPMappingModel.ColumnData[] refColumns = joinColumnMap.getReferencedColumns();
+ joinTableAnnArguments.add(genUtils.createAnnotationArgument("joinColumns", createJoinColumnAnnotations(columns, refColumns, null))); // NOI18N
+ CMPMappingModel.ColumnData[] invColumns = joinColumnMap.getInverseColumns();
+ CMPMappingModel.ColumnData[] refInvColumns = joinColumnMap.getReferencedInverseColumns();
+ joinTableAnnArguments.add(genUtils.createAnnotationArgument("inverseJoinColumns", createJoinColumnAnnotations(invColumns, refInvColumns, null))); // NOI18N
+ annotations.add(genUtils.createAnnotation("javax.persistence.JoinTable", joinTableAnnArguments)); // NOI18N
+ } else { // ManyToOne, OneToMany, OneToOne
+ CMPMappingModel.ColumnData[] columns = dbMappings.getCmrFieldMapping().get(role.getFieldName());
+ CMPMappingModel relatedMappings = beanMap.get(role.getParent().getRoleB().getEntityName()).getCMPMapping();
+ CMPMappingModel.ColumnData[] invColumns = relatedMappings.getCmrFieldMapping().get(role.getParent().getRoleB().getFieldName());
+ if (columns.length == 1) {
+ List<ExpressionTree> attrs = new ArrayList<>();
+ attrs.add(genUtils.createAnnotationArgument("name", columns[0].getColumnName())); //NOI18N
+ attrs.add(genUtils.createAnnotationArgument("referencedColumnName", invColumns[0].getColumnName())); //NOI18N
+ makeReadOnlyIfNecessary(pkColumnNames, columns[0].getColumnName(), attrs);
+ annotations.add(genUtils.createAnnotation("javax.persistence.JoinColumn", attrs)); //NOI18N
+ } else {
+ ExpressionTree joinColumnsNameAttrValue = genUtils.createAnnotationArgument(null, createJoinColumnAnnotations(columns, invColumns, pkColumnNames));
+ AnnotationTree joinColumnsAnnotation = genUtils.createAnnotation("javax.persistence.JoinColumns", Collections.singletonList(joinColumnsNameAttrValue)); //NOI18N
+ annotations.add(joinColumnsAnnotation);
+ }
+ }
+ }
+
+ if (generateJPA && !role.isToMany()) { // meaning ManyToOne or OneToOne
+ // Add optional=false on @ManyToOne or the owning side of @OneToOne
+ // if the relationship is non-optional (or non-nuallable in other words)
+ if (!role.isOptional() && (role.isMany() || role.equals(role.getParent().getRoleA()))) {
+ annArguments.add(genUtils.createAnnotationArgument("optional", false)); // NOI18N
+ }
+ }
+
+ // Create the relationship annotation
+ if (generateJPA) {
+ String relationAnn;
+ if (role.isMany() && role.isToMany()) {
+ relationAnn = "ManyToMany"; //NOI18N
+ } else if (role.isMany()) {
+ relationAnn = "ManyToOne"; //NOI18N
+ } else if (role.isToMany()) {
+ relationAnn = "OneToMany"; //NOI18N
+ } else {
+ relationAnn = "OneToOne"; //NOI18N
+ }
+ annotations.add(genUtils.createAnnotation("javax.persistence." + relationAnn, annArguments)); // NOI18N
+ } else {
+ String relationAnn;
+ if (role.isMany() && role.isToMany()) {
+ relationAnn = "MANY_TO_MANY"; //NOI18N
+ } else if (role.isMany()) {
+ relationAnn = "MANY_TO_ONE"; //NOI18N
+ } else if (role.isToMany()) {
+ relationAnn = "ONE_TO_MANY"; //NOI18N
+ } else {
+ relationAnn = "ONE_TO_ONE"; //NOI18N
+ }
+ annArguments.add(0, genUtils.createAnnotationArgument("value", "io.micronaut.data.annotation.Relation.Kind", relationAnn)); // NOI18N
+ annotations.add(genUtils.createAnnotation("io.micronaut.data.annotation.Relation", annArguments)); // NOI18N
+ }
+
+ properties.add(new Property(Modifier.PRIVATE, annotations, fieldType, memberName));
+ }
+
+ @Override
+ protected void finish() {
+ // create a constructor which takes all non-nullable non-relationship fields as args
+ if (nonNullableProps.size() > 0) {
+ List<VariableTree> nonNullableParams = new ArrayList<>(nonNullableProps.size() + 1);
+ if (pkProperty != null && !pkGenerated) {
+ VariableTree pkFieldParam = genUtils.removeModifiers(pkProperty.getField());
+ nonNullableParams.add(pkFieldParam);
+ }
+ for (Property property : nonNullableProps) {
+ nonNullableParams.add(genUtils.removeModifiers(property.getField()));
+ }
+ constructors.add(genUtils.createAssignmentConstructor(genUtils.createModifiers(Modifier.PUBLIC), entityClassName, nonNullableParams));
+ }
+ }
+
+ private List<AnnotationTree> createJoinColumnAnnotations(CMPMappingModel.ColumnData[] columns, CMPMappingModel.ColumnData[] refColumns, List<String> pkcNames) {
+ List<AnnotationTree> joinCols = new ArrayList<>();
+ for (int colIndex = 0; colIndex < columns.length; colIndex++) {
+ List<ExpressionTree> attrs = new ArrayList<>();
+ attrs.add(genUtils.createAnnotationArgument("name", columns[colIndex].getColumnName())); //NOI18N
+ attrs.add(genUtils.createAnnotationArgument("referencedColumnName", refColumns[colIndex].getColumnName())); //NOI18N
+ if (pkcNames != null) {
+ makeReadOnlyIfNecessary(pkcNames, columns[colIndex].getColumnName(), attrs);
+ }
+ joinCols.add(genUtils.createAnnotation("javax.persistence.JoinColumn", attrs)); //NOI18N
+ }
+ return joinCols;
+ }
+
+ private String getRelationshipFieldType(RelationshipRole role, String pkg) {
+ RelationshipRole rA = role.getParent().getRoleA();
+ RelationshipRole rB = role.getParent().getRoleB();
+ RelationshipRole otherRole = role.equals(rA) ? rB : rA;
+
+ // First, check if the entity package name is set in the role.
+ // If yes, then that's the package
+ // If no, then default to the passed in pkg
+ if (role.getEntityPkgName() != null) {
+ return otherRole.getEntityPkgName() + "." + otherRole.getEntityName(); // NOI18N
+ } else {
+ return pkg.length() == 0 ? otherRole.getEntityName() : pkg + "." + otherRole.getEntityName(); // NOI18N
+ }
+ }
+
+ private void makeReadOnlyIfNecessary(List<String> pkColumnNames, String testColumnName, List<ExpressionTree> attrs) {
+ // if the join column is a pk column, add insertable = false, updatable = false
+ if (pkColumnNames.contains(testColumnName)) {
+ attrs.add(genUtils.createAnnotationArgument("insertable", false)); //NOI18N
+ attrs.add(genUtils.createAnnotationArgument("updatable", false)); //NOI18N
+ }
+ }
+ }
+ }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautRepository.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautRepository.java
new file mode 100644
index 0000000..3bb9c8c
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/MicronautRepository.java
@@ -0,0 +1,357 @@
+/*
+ * 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.micronaut.db;
+
+import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.ModifiersTree;
+import com.sun.source.tree.ParameterizedTypeTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.TypeParameterTree;
+import com.sun.source.tree.VariableTree;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.ElementFilter;
+import javax.swing.event.ChangeListener;
+import org.netbeans.api.db.explorer.ConnectionManager;
+import org.netbeans.api.db.explorer.DatabaseConnection;
+import org.netbeans.api.db.explorer.DatabaseException;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.java.source.ClassIndex;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.api.java.source.TypeUtilities;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.api.templates.CreateDescriptor;
+import org.netbeans.api.templates.CreateFromTemplateHandler;
+import org.netbeans.modules.j2ee.core.api.support.SourceGroups;
+import org.netbeans.modules.j2ee.core.api.support.java.GenerationUtils;
+import org.netbeans.modules.j2ee.core.api.support.wizard.Wizards;
+import org.netbeans.spi.project.ui.templates.support.Templates;
+import org.openide.DialogDescriptor;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.WizardDescriptor;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.TemplateWizard;
+import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class MicronautRepository implements TemplateWizard.Iterator {
+
+ public static TemplateWizard.Iterator create() {
+ return new MicronautRepository();
+ }
+
+ @NbBundle.Messages({
+ "MSG_SelectEntities=Select Entity Classes",
+ "MSG_NoEntities=No entity class found in {0}"
+ })
+ public static CreateFromTemplateHandler handler() {
+ return new CreateFromTemplateHandler() {
+ @Override
+ protected boolean accept(CreateDescriptor desc) {
+ return true;
+ }
+
+ @Override
+ protected List<FileObject> createFromTemplate(CreateDescriptor desc) throws IOException {
+ try {
+ final FileObject folder = desc.getTarget();
+ final Project project = FileOwnerQuery.getOwner(folder);
+ if (project == null) {
+ DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(Bundle.MSG_NoProject(folder.getPath()), NotifyDescriptor.ERROR_MESSAGE));
+ return Collections.emptyList();
+ }
+ final SourceGroup sourceGroup = SourceGroups.getFolderSourceGroup(ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA), folder);
+ if (sourceGroup == null) {
+ DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(Bundle.MSG_NoSourceGroup(folder.getPath()), NotifyDescriptor.ERROR_MESSAGE));
+ return Collections.emptyList();
+ }
+ final boolean jpaSupported = Utils.isJPASupported(sourceGroup);
+ final Map<String, String> entity2idTypes = getEntityClasses(sourceGroup, jpaSupported);
+ final List<NotifyDescriptor.QuickPick.Item> entities = new ArrayList<>();
+ for (String entityFQN : entity2idTypes.keySet()) {
+ int idx = entityFQN.lastIndexOf('.');
+ if (idx < 0) {
+ entities.add(new NotifyDescriptor.QuickPick.Item(entityFQN, null));
+ } else {
+ entities.add(new NotifyDescriptor.QuickPick.Item(entityFQN.substring(idx + 1), entityFQN.substring(0, idx)));
+ }
+ }
+ if (entities.isEmpty()) {
+ DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(Bundle.MSG_NoEntities(sourceGroup.getRootFolder().getPath()), NotifyDescriptor.ERROR_MESSAGE));
+ return Collections.emptyList();
+ }
+ NotifyDescriptor.QuickPick qp = new NotifyDescriptor.QuickPick(Bundle.MSG_SelectEntities(), Bundle.MSG_SelectEntities(), entities, true);
+ if (DialogDescriptor.OK_OPTION == DialogDisplayer.getDefault().notify(qp)) {
+ String dialect = getDialect(jpaSupported);
+ List<FileObject> generated = new ArrayList<>();
+ for (NotifyDescriptor.QuickPick.Item item : qp.getItems()) {
+ if (item.isSelected()) {
+ String fqn = item.getDescription() != null ? item.getDescription() + '.' + item.getLabel() : item.getLabel();
+ String entityIdType = entity2idTypes.get(fqn);
+ FileObject fo = generate(folder, item.getLabel(), fqn, entityIdType, dialect);
+ if (fo != null) {
+ generated.add(fo);
+ }
+ }
+ }
+ return generated;
+ }
+ } catch (Exception ex) {
+ DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(ex.getMessage(), NotifyDescriptor.ERROR_MESSAGE));
+ }
+ return Collections.emptyList();
+ }
+ };
+ }
+
+ static final String PROP_ENTITIES = "wizard-entities"; //NOI18N
+ static final String PROP_SELECTED_ENTITIES = "wizard-selected-entities"; //NOI18N
+ private WizardDescriptor.Panel panel;
+ private WizardDescriptor wizardDescriptor;
+ private FileObject targetFolder;
+ private boolean jpaSupported;
+
+ @Override
+ public Set<DataObject> instantiate(TemplateWizard wiz) throws IOException {
+ String dialect = getDialect(jpaSupported);
+ Set<DataObject> generated = new HashSet<>();
+ Map<String, String> selectedEntities = (Map<String, String>) wiz.getProperty(PROP_SELECTED_ENTITIES);
+ for (Map.Entry<String, String> entry : selectedEntities.entrySet()) {
+ String fqn = entry.getKey();
+ int idx = fqn.lastIndexOf('.');
+ String label = idx < 0 ? fqn : fqn.substring(idx + 1);
+ FileObject fo = generate(targetFolder, label, fqn, entry.getValue(), dialect);
+ if (fo != null) {
+ generated.add(DataObject.find(fo));
+ }
+ }
+ return generated;
+ }
+
+ @Override
+ public void initialize(TemplateWizard wiz) {
+ wizardDescriptor = wiz;
+
+ panel = new EntityClassesPanel.WizardPanel(NbBundle.getMessage(MicronautRepository.class, "Templates/Micronaut/Repository"));
+ Wizards.mergeSteps(wizardDescriptor, new WizardDescriptor.Panel[] {
+ panel
+ }, new String[] {
+ NbBundle.getMessage(MicronautRepository.class, "LBL_EntityClasses")
+ });
+
+ targetFolder = Templates.getTargetFolder(wizardDescriptor);
+ Project project = Templates.getProject(wiz);
+ SourceGroup sourceGroup = SourceGroups.getFolderSourceGroup(ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA), targetFolder);
+ if (sourceGroup != null) {
+ jpaSupported = Utils.isJPASupported(sourceGroup);
+ Map<String, String> entities = MicronautRepository.getEntityClasses(sourceGroup, jpaSupported);
+ wiz.putProperty(PROP_ENTITIES, entities);
+ }
+ }
+
+ @Override
+ public void uninitialize(TemplateWizard wiz) {
+ }
+
+ @Override
+ public WizardDescriptor.Panel<WizardDescriptor> current() {
+ return panel;
+ }
+
+ @Override
+ public String name() {
+ return null;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return false;
+ }
+
+ @Override
+ public void nextPanel() {
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void previousPanel() {
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void addChangeListener(ChangeListener l) {
+ }
+
+ @Override
+ public void removeChangeListener(ChangeListener l) {
+ }
+
+ static Map<String, String> getEntityClasses(SourceGroup sg, boolean jpaSupported) {
+ final Map<String, String> entities = new HashMap<>();
+ JavaSource js = JavaSource.create(ClasspathInfo.create(sg.getRootFolder()));
+ if (js != null) {
+ try {
+ js.runWhenScanFinished(cc -> {
+ TypeElement typeElement = cc.getElements().getTypeElement(jpaSupported ? "javax.persistence.Entity" : "io.micronaut.data.annotation.MappedEntity"); //NOI18N
+ if (typeElement != null) {
+ TypeElement idTypeElement = cc.getElements().getTypeElement(jpaSupported ? "javax.persistence.Id" : "io.micronaut.data.annotation.Id"); //NOI18N
+ Set<ElementHandle<TypeElement>> elementHandles = cc.getClasspathInfo().getClassIndex().getElements(ElementHandle.create(typeElement), EnumSet.of(ClassIndex.SearchKind.TYPE_REFERENCES), EnumSet.of(ClassIndex.SearchScope.SOURCE));
+ for (ElementHandle<TypeElement> elementHandle : elementHandles) {
+ TypeElement type = elementHandle.resolve(cc);
+ if (type != null) {
+ String fqn = null;
+ String idType = null;
+ for (AnnotationMirror annotationMirror : type.getAnnotationMirrors()) {
+ if (fqn == null && typeElement == annotationMirror.getAnnotationType().asElement()) {
+ fqn = type.getQualifiedName().toString();
+ }
+ }
+ if (fqn != null) {
+ if (idTypeElement != null) {
+ for (VariableElement field : ElementFilter.fieldsIn(type.getEnclosedElements())) {
+ if (idType == null) {
+ for (AnnotationMirror annotationMirror : field.getAnnotationMirrors()) {
+ if (idType == null && idTypeElement == annotationMirror.getAnnotationType().asElement()) {
+ idType = cc.getTypeUtilities().getTypeName(field.asType(), TypeUtilities.TypeNameOptions.PRINT_FQN).toString();
+ }
+ }
+ }
+ }
+ }
+ if (idType == null) {
+ idType = "java.lang.Object"; //NOI18N
+ }
+ entities.put(fqn, idType);
+ }
+ }
+ }
+ }
+ }, true);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return entities;
+ }
+
+ private static String getDialect(boolean jpaSupported) {
+ if (!jpaSupported) {
+ DatabaseConnection connection = ConnectionManager.getDefault().getPreferredConnection(true);
+ if (connection != null) {
+ try {
+ ConnectionManager.getDefault().connect(connection);
+ Connection conn = connection.getJDBCConnection();
+ String name = conn.getMetaData().getDatabaseProductName();
+ if (name.matches("(?i).*h2.*")) { //NOI18N
+ return "H2"; //NOI18N
+ } else if (name.matches("(?i).*mysql.*")) { //NOI18N
+ return "MYSQL"; //NOI18N
+ } else if (name.matches("(?i).*oracle.*")) { //NOI18N
+ return "ORACLE"; //NOI18N
+ } else if (name.matches("(?i).*postgresql.*")) { //NOI18N
+ return "POSTGRES"; //NOI18N
+ } else if (name.matches("(?i).*microsoft.*")) { //NOI18N
+ return "SQL_SERVER"; //NOI18N
+ }
+ } catch (SQLException | DatabaseException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return ""; //NOI18N
+ }
+ return null;
+ }
+
+ @NbBundle.Messages({
+ "MSG_Repository_Interface=Repository interface {0}\n"
+ })
+ private static FileObject generate(FileObject folder, String entityName, String entityFQN, String entityIdType, String dialect) {
+ try {
+ String name = entityName + "Repository"; // NOI18N
+ FileObject fo = GenerationUtils.createInterface(folder, name, Bundle.MSG_Repository_Interface(name));
+ if (fo != null) {
+ JavaSource js = JavaSource.forFileObject(fo);
+ if (js != null) {
+ js.runModificationTask(copy -> {
+ copy.toPhase(JavaSource.Phase.RESOLVED);
+ Tree origTree = copy.getCompilationUnit().getTypeDecls().get(0);
+ if (origTree.getKind() == Tree.Kind.INTERFACE) {
+ GenerationUtils gu = GenerationUtils.newInstance(copy);
+ TreeMaker tm = copy.getTreeMaker();
+ List<ExpressionTree> args = Arrays.asList(tm.QualIdent(entityFQN), tm.QualIdent(entityIdType));
+ ParameterizedTypeTree type = tm.ParameterizedType(tm.QualIdent("io.micronaut.data.repository.CrudRepository"), args); //NOI18N
+ ClassTree cls = tm.addClassImplementsClause((ClassTree) origTree, type);
+ if (dialect == null) {
+ cls = gu.addAnnotation(cls, gu.createAnnotation("io.micronaut.data.annotation.Repository")); //NOI18N
+ } else if (dialect.isEmpty()) {
+ cls = gu.addAnnotation(cls, gu.createAnnotation("io.micronaut.data.jdbc.annotation.JdbcRepository")); //NOI18N
+ } else {
+ List<ExpressionTree> annArgs = Collections.singletonList(gu.createAnnotationArgument("dialect", "io.micronaut.data.model.query.builder.sql.Dialect", dialect)); //NOI18N
+ cls = gu.addAnnotation(cls, gu.createAnnotation("io.micronaut.data.jdbc.annotation.JdbcRepository", annArgs)); //NOI18N
+ }
+ ModifiersTree mods = tm.Modifiers(Collections.emptySet(), Arrays.asList(gu.createAnnotation("java.lang.Override"), gu.createAnnotation("io.micronaut.core.annotation.NonNull"))); //NOI18N
+ ParameterizedTypeTree retType = tm.ParameterizedType(tm.QualIdent("java.util.List"), Collections.singletonList(tm.QualIdent(entityFQN))); //NOI18N
+ MethodTree findAllMethod = tm.Method(mods, "findAll", retType, Collections.<TypeParameterTree>emptyList(), Collections.<VariableTree>emptyList(), Collections.<ExpressionTree>emptyList(), (BlockTree)null, null); //NOI18N
+ cls = tm.addClassMember(cls, findAllMethod);
+ copy.rewrite(origTree, cls);
+ }
+ }).commit();
+ }
+ }
+ return fo;
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ return null;
+ }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/Utils.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/Utils.java
new file mode 100644
index 0000000..4e3e08f
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/db/Utils.java
@@ -0,0 +1,41 @@
+/*
+ * 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.micronaut.db;
+
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.project.SourceGroup;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class Utils {
+
+ public static boolean isJPASupported(SourceGroup sg) {
+ if (sg == null) {
+ return false;
+ }
+ ClassPath compile = ClassPath.getClassPath(sg.getRootFolder(), ClassPath.COMPILE);
+ if (compile == null) {
+ return false;
+ }
+ final String notNullAnnotation = "io.micronaut.data.jpa.repository.JpaRepository"; //NOI18N
+ return compile.findResource(notNullAnnotation.replace('.', '/') + ".class") != null; //NOI18N
+ }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/EntityDatabase.html b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/EntityDatabase.html
new file mode 100644
index 0000000..58e631a
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/EntityDatabase.html
@@ -0,0 +1,29 @@
+<!--
+
+ 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.
+
+-->
+
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+</head>
+<BODY>
+Creates Micronaut Data entity classes based on an existing relational database.
+This template creates an entity class for each selected table.
+</BODY></HTML>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/Micronaut.html b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/Micronaut.html
new file mode 100644
index 0000000..a9a1093
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/Micronaut.html
@@ -0,0 +1,28 @@
+<!--
+
+ 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.
+
+-->
+
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+</head>
+<BODY>
+Templates for creating various types of files for Micronaut framework.
+</BODY></HTML>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/Repository.html b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/Repository.html
new file mode 100644
index 0000000..a209d08
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/Repository.html
@@ -0,0 +1,29 @@
+<!--
+
+ 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.
+
+-->
+
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+</head>
+<BODY>
+Creates Micronaut Data repository interfaces based on existing entity classes.
+This template creates an repository interface for each selected entity.
+</BODY></HTML>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml
index 31f5f46..b103120 100644
--- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml
@@ -43,4 +43,32 @@
</folder>
</folder>
</folder>
+ <folder name="Templates">
+ <folder name="Micronaut">
+ <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.micronaut.db.Bundle"/>
+ <attr name="templateWizardURL" urlvalue="nbresloc:/org/netbeans/modules/micronaut/resources/Micronaut.html"/>
+ <attr name="position" intvalue="1280"/>
+
+ <file name="Entity">
+ <attr name="position" intvalue="220"/>
+ <attr name="template" boolvalue="true"/>
+ <attr name="instantiatingIterator" methodvalue="org.netbeans.modules.micronaut.db.MicronautEntity.create"/>
+ <attr name="template.createTemplateHandler" methodvalue="org.netbeans.modules.micronaut.db.MicronautEntity.handler"/>
+ <attr name="templateCategory" stringvalue="persistence"/>
+ <attr name="templateWizardURL" urlvalue="nbresloc:/org/netbeans/modules/micronaut/resources/EntityDatabase.html"/>
+ <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.micronaut.db.Bundle"/>
+ <attr name="SystemFileSystem.icon" urlvalue="nbresloc:/org/netbeans/modules/java/resources/class.png"/>
+ </file>
+ <file name="Repository">
+ <attr name="position" intvalue="320"/>
+ <attr name="template" boolvalue="true"/>
+ <attr name="instantiatingIterator" methodvalue="org.netbeans.modules.micronaut.db.MicronautRepository.create"/>
+ <attr name="template.createTemplateHandler" methodvalue="org.netbeans.modules.micronaut.db.MicronautRepository.handler"/>
+ <attr name="templateCategory" stringvalue="persistence"/>
+ <attr name="templateWizardURL" urlvalue="nbresloc:/org/netbeans/modules/micronaut/resources/Repository.html"/>
+ <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.micronaut.db.Bundle"/>
+ <attr name="SystemFileSystem.icon" urlvalue="nbresloc:/org/netbeans/modules/java/resources/interface_file.png"/>
+ </file>
+ </folder>
+ </folder>
</filesystem>
diff --git a/java/j2ee.core.utilities/manifest.mf b/java/j2ee.core.utilities/manifest.mf
index ff7c974..9522765 100644
--- a/java/j2ee.core.utilities/manifest.mf
+++ b/java/j2ee.core.utilities/manifest.mf
@@ -1,4 +1,4 @@
Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.modules.j2ee.core.utilities/0
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/j2ee/core/utilities/Bundle.properties
-OpenIDE-Module-Specification-Version: 1.49
+OpenIDE-Module-Specification-Version: 1.50
diff --git a/java/j2ee.core.utilities/nbproject/project.xml b/java/j2ee.core.utilities/nbproject/project.xml
index 4c2dafc..8b7f58a 100644
--- a/java/j2ee.core.utilities/nbproject/project.xml
+++ b/java/j2ee.core.utilities/nbproject/project.xml
@@ -257,6 +257,7 @@
<friend>org.netbeans.modules.javaee.beanvalidation</friend>
<friend>org.netbeans.modules.maven.j2ee</friend>
<friend>org.netbeans.modules.maven.jaxws</friend>
+ <friend>org.netbeans.modules.micronaut</friend>
<friend>org.netbeans.modules.spring.beans</friend>
<friend>org.netbeans.modules.spring.webmvc</friend>
<friend>org.netbeans.modules.web.core</friend>
diff --git a/java/j2ee.persistence/nbproject/project.properties b/java/j2ee.persistence/nbproject/project.properties
index ea94769..c58bb6a 100644
--- a/java/j2ee.persistence/nbproject/project.properties
+++ b/java/j2ee.persistence/nbproject/project.properties
@@ -17,7 +17,7 @@
javac.compilerargs=-Xlint -Xlint:-serial
javac.source=1.8
-spec.version.base=1.70.0
+spec.version.base=1.71.0
test.unit.run.cp.extra=\
${j2ee.persistence.dir}/modules/ext/eclipselink/org.eclipse.persistence.core-2.7.9.jar:\
diff --git a/java/j2ee.persistence/nbproject/project.xml b/java/j2ee.persistence/nbproject/project.xml
index f8ecc68..e1bff99 100644
--- a/java/j2ee.persistence/nbproject/project.xml
+++ b/java/j2ee.persistence/nbproject/project.xml
@@ -629,6 +629,7 @@
<friend>org.netbeans.modules.javaee.project</friend>
<friend>org.netbeans.modules.javaee.specs.support</friend>
<friend>org.netbeans.modules.maven.j2ee</friend>
+ <friend>org.netbeans.modules.micronaut</friend>
<friend>org.netbeans.modules.profiler.j2ee</friend>
<friend>org.netbeans.modules.web.jsf</friend>
<friend>org.netbeans.modules.web.project</friend>
diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/api/entity/generator/EntitiesFromDBGenerator.java b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/api/entity/generator/EntitiesFromDBGenerator.java
index cc39f45..e75a4b6 100644
--- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/api/entity/generator/EntitiesFromDBGenerator.java
+++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/api/entity/generator/EntitiesFromDBGenerator.java
@@ -41,6 +41,7 @@ import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.Coll
import org.netbeans.modules.j2ee.persistence.entitygenerator.EntityRelation.FetchType;
import org.netbeans.modules.j2ee.persistence.wizard.fromdb.JavaPersistenceGenerator;
import org.netbeans.modules.j2ee.persistence.wizard.fromdb.DBSchemaTableProvider;
+import org.netbeans.modules.j2ee.persistence.wizard.fromdb.PersistenceGenerator;
import org.netbeans.modules.j2ee.persistence.wizard.fromdb.RelatedCMPHelper;
import org.netbeans.modules.j2ee.persistence.wizard.fromdb.SelectedTables;
import org.netbeans.modules.j2ee.persistence.wizard.fromdb.Table;
@@ -63,7 +64,7 @@ public final class EntitiesFromDBGenerator {
private final DatabaseConnection connection;
private final Project project;
private final PersistenceUnit persistenceUnit;
- private final JavaPersistenceGenerator generator;
+ private final PersistenceGenerator generator;
// Global mapping options
private boolean fullyQualifiedTableNames;
@@ -104,6 +105,41 @@ public final class EntitiesFromDBGenerator {
FetchType fetchType, CollectionType collectionType,
String packageName, SourceGroup location, DatabaseConnection connection,
Project project, PersistenceUnit persistenceUnit) {
+ this(tableNames, generateNamedQueries, fullyQualifiedTableNames, regenTablesAttrs, fetchType, collectionType, packageName, location, connection, project, persistenceUnit, new JavaPersistenceGenerator(persistenceUnit));
+ }
+
+ /**
+ * Creates a new instance of EntitiesFromDBGenerator.
+ *
+ * @param tableNames the names of the tables for which entities are generated. Must not be null.
+ * @param generateNamedQueries specifies whether named queries should be generated.
+ * @param fullyQualifiedTableNames specifies whether fully qualified database table names should be used.
+ * Attribute catalog and schema are added to the Table annotation if true
+ * @param regenTablesAttrs specified whether attributes used for regenerating tables from entity classes
+ * should be included. If true, unique containtraints are generated on @Table annotation and attributes
+ * nullable (if false), length (for String type), precision and scale(for decimal type) are added to
+ * the Column annotation
+ * @param fetchType specifies the fetch type for the associations. Can be <code>FetchType.DEFAULT</code>,
+ * <code>FetchType.EAGER</code> or <code>FetchType.LAZY</code>. Default to <code>FetchType.DEFAULT</code>,
+ * meaning no fetch attribute is added to the relationship annotation
+ * @param collectionType specifies the collection type for the OneToMany and ManyToMany fields.
+ * Can be <code>CollectionType.COLLECTION</code>, <code>CollectionType.LIST</code> or
+ * <code>CollectionType.SET</code>. Default to <code>CollectionType.COLLECTION</code>.
+ * @param packageName the name of the package for the generated entities. Must not be null.
+ * @param location the location. Must not be null.
+ * @param connection the database connection for the specified tables. Must not be null.
+ * @param project the project to which entities are generated.
+ * @param persistenceUnit the persistenceUnit to which generated entities should be added
+ * as managed classes. May be null, in which case it is up to the client to add
+ * the generated entities to an appropriate persistence unit (if any).
+ * @param persistenceGenerator persistence generator
+ *
+ */
+ public EntitiesFromDBGenerator(List<String> tableNames, boolean generateNamedQueries,
+ boolean fullyQualifiedTableNames, boolean regenTablesAttrs,
+ FetchType fetchType, CollectionType collectionType,
+ String packageName, SourceGroup location, DatabaseConnection connection,
+ Project project, PersistenceUnit persistenceUnit, PersistenceGenerator persistenceGenerator) {
Parameters.notNull("project", project); //NOI18N
Parameters.notNull("tableNames", tableNames); //NOI18N
Parameters.notNull("packageName", packageName); //NOI18N
@@ -121,7 +157,7 @@ public final class EntitiesFromDBGenerator {
this.connection = connection;
this.project = project;
this.persistenceUnit = persistenceUnit;
- this.generator = new JavaPersistenceGenerator(persistenceUnit);
+ this.generator = persistenceGenerator;
}
/**
diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/DatabaseTablesPanel.java b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/DatabaseTablesPanel.java
index a652c31..eda500f 100644
--- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/DatabaseTablesPanel.java
+++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/DatabaseTablesPanel.java
@@ -1099,7 +1099,9 @@ public class DatabaseTablesPanel extends javax.swing.JPanel implements AncestorL
@Override
public void readSettings(WizardDescriptor settings) {
wizardDescriptor = settings;
- wizardDescriptor.putProperty("NewFileWizard_Title", title); // NOI18N
+ if (title != null) {
+ wizardDescriptor.putProperty("NewFileWizard_Title", title); // NOI18N
+ }
if (!componentInitialized) {
componentInitialized = true;
diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/EntityClassesPanel.java b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/EntityClassesPanel.java
index 1d5ead8..4338264 100644
--- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/EntityClassesPanel.java
+++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/EntityClassesPanel.java
@@ -92,7 +92,7 @@ public class EntityClassesPanel extends javax.swing.JPanel {
private final JMenuItem allToRecreateItem;
- private EntityClassesPanel(boolean puRequired, boolean JAXBRequired) {
+ private EntityClassesPanel(boolean puRequired, boolean JAXBRequired, boolean isJPA) {
this.puRequired = puRequired;
initComponents();
@@ -138,6 +138,12 @@ public class EntityClassesPanel extends javax.swing.JPanel {
packageChanged();
}
});
+ if (!isJPA) {
+ createPUCheckbox.setVisible(false);
+ generateFinderMethodsCheckBox.setVisible(false);
+ generateJAXBCheckBox.setVisible(false);
+ mappedSuperclassCheckBox.setVisible(false);
+ }
}
public void addChangeListener(ChangeListener listener) {
@@ -610,6 +616,7 @@ public class EntityClassesPanel extends javax.swing.JPanel {
private boolean puRequired;
private boolean JAXBRequired;
private boolean isFinishable;
+ private boolean isJPA;
private List<Provider> providers;
@@ -618,25 +625,31 @@ public class EntityClassesPanel extends javax.swing.JPanel {
}
public WizardPanel(boolean persistenceUnitRequired, boolean JAXBRequired,
- boolean isFinishable )
+ boolean isFinishable ) {
+ this(persistenceUnitRequired, JAXBRequired, isFinishable, true);
+ }
+
+ WizardPanel(boolean persistenceUnitRequired, boolean JAXBRequired,
+ boolean isFinishable, boolean isJPA )
{
puRequired = persistenceUnitRequired;
this.JAXBRequired = JAXBRequired;
this.isFinishable = isFinishable;
+ this.isJPA = isJPA;
}
public WizardPanel(boolean persistenceUnitRequired, boolean JAXBRequired){
- this( persistenceUnitRequired , JAXBRequired , true );
+ this( persistenceUnitRequired , JAXBRequired , true, true );
}
public WizardPanel(boolean persistenceUnitRequired){
- this( persistenceUnitRequired , false , true );
+ this( persistenceUnitRequired , false , true, true );
}
@Override
public EntityClassesPanel getComponent() {
if (component == null) {
- component = new EntityClassesPanel(puRequired, JAXBRequired);
+ component = new EntityClassesPanel(puRequired, JAXBRequired, isJPA);
component.addChangeListener(this);
}
return component;
diff --git a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/RelatedCMPWizard.java b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/RelatedCMPWizard.java
index cca3f49..6c4cfe4 100644
--- a/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/RelatedCMPWizard.java
+++ b/java/j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/wizard/fromdb/RelatedCMPWizard.java
@@ -165,12 +165,16 @@ public class RelatedCMPWizard implements TemplateWizard.Iterator {
// new PersistenceUnitWizardDescriptor(project),
// };
// } else {
- return new WizardDescriptor.Panel[]{
- new DatabaseTablesPanel.WizardPanel(wizardTitle),
- new EntityClassesPanel.WizardPanel(),
- new MappingOptionsPanel.WizardPanel(),};
-// }
+ return TYPE_JPA.equals(type) ? new WizardDescriptor.Panel[] {
+ new DatabaseTablesPanel.WizardPanel(wizardTitle),
+ new EntityClassesPanel.WizardPanel(),
+ new MappingOptionsPanel.WizardPanel()
+ } : new WizardDescriptor.Panel[]{
+ new DatabaseTablesPanel.WizardPanel(null),
+ new EntityClassesPanel.WizardPanel(false, false, true, false)
+ } ;
}
+// }
}
private String[] createSteps() {
@@ -189,10 +193,14 @@ public class RelatedCMPWizard implements TemplateWizard.Iterator {
// NbBundle.getMessage(PersistenceUnitWizardDescriptor.class,"LBL_Step1")
// };
// } else {
- return new String[]{
- NbBundle.getMessage(RelatedCMPWizard.class, "LBL_DatabaseTables"),
- NbBundle.getMessage(RelatedCMPWizard.class, "LBL_EntityClasses"),
- NbBundle.getMessage(RelatedCMPWizard.class, "LBL_MappingOptions"),};
+ return TYPE_JPA.equals(type) ? new String[] {
+ NbBundle.getMessage(RelatedCMPWizard.class, "LBL_DatabaseTables"),
+ NbBundle.getMessage(RelatedCMPWizard.class, "LBL_EntityClasses"),
+ NbBundle.getMessage(RelatedCMPWizard.class, "LBL_MappingOptions")
+ } : new String[] {
+ NbBundle.getMessage(RelatedCMPWizard.class, "LBL_DatabaseTables"),
+ NbBundle.getMessage(RelatedCMPWizard.class, "LBL_EntityClasses")
+ };
// }
}
}
diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
index 379e4f8..81f18f3 100644
--- a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
+++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
@@ -98,5 +98,6 @@
<folder name="XML">
<file name="XMLCatalog.xml_hidden"/>
</folder>
+ <folder name="Persistence_hidden"/>
</folder>
</filesystem>
diff --git a/java/java.lsp.server/nbproject/project.xml b/java/java.lsp.server/nbproject/project.xml
index 8318c49..5955f01 100644
--- a/java/java.lsp.server/nbproject/project.xml
+++ b/java/java.lsp.server/nbproject/project.xml
@@ -141,6 +141,14 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.api.templates</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>1.24</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.libs.flexmark</code-name-base>
<build-prerequisite/>
<compile-dependency/>
@@ -537,7 +545,7 @@
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>7.59</specification-version>
+ <specification-version>7.60</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java
index a2decdc..134b355 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java
@@ -37,6 +37,7 @@ import java.util.concurrent.CompletionStage;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
import org.eclipse.lsp4j.ExecuteCommandParams;
import org.eclipse.lsp4j.MessageParams;
import org.eclipse.lsp4j.MessageType;
@@ -46,6 +47,8 @@ import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.project.SourceGroupModifier;
+import org.netbeans.api.templates.CreateDescriptor;
+import org.netbeans.api.templates.FileBuilder;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.URLMapper;
@@ -73,57 +76,42 @@ import org.openide.util.Utilities;
"# {0} - path",
"ERR_ExistingPath={0} already exists",
})
-abstract class LspTemplateUI {
+final class LspTemplateUI {
/**
* Creation thread. All requests are serialized; make sure that no creation process can block e.g. waiting
* for the client's response.
*/
private static final RequestProcessor CREATION_RP = new RequestProcessor(LspTemplateUI.class);
-
private static final Logger LOG = Logger.getLogger(LspTemplateUI.class.getName());
private LspTemplateUI() {
}
- abstract CompletionStage<Pair<DataFolder,String>> findTargetAndName(CompletionStage<DataObject> findTemplate, NbCodeLanguageClient client, ExecuteCommandParams params);
-
static CompletableFuture<Object> createFromTemplate(String templates, NbCodeLanguageClient client, ExecuteCommandParams params) {
final FileObject fo = FileUtil.getConfigFile(templates);
final DataFolder folder = DataFolder.findFolder(fo);
- LspTemplateUI ui = new LspTemplateUI() {
- @Override
- CompletionStage<Pair<DataFolder, String>> findTargetAndName(CompletionStage<DataObject> findTemplate, NbCodeLanguageClient client, ExecuteCommandParams params) {
- return findTargetAndNameForTemplate(findTemplate, client, params);
- }
- };
- return ui.templateUI(folder, client, params);
+ return new LspTemplateUI().templateUI(folder, client, params);
}
static CompletableFuture<Object> createProject(String templates, NbCodeLanguageClient client, ExecuteCommandParams params) {
final FileObject fo = FileUtil.getConfigFile(templates);
final DataFolder folder = DataFolder.findFolder(fo);
- LspTemplateUI ui = new LspTemplateUI() {
- @Override
- CompletionStage<Pair<DataFolder, String>> findTargetAndName(CompletionStage<DataObject> findTemplate, NbCodeLanguageClient client, ExecuteCommandParams params) {
- return findTargetAndNameForProject(findTemplate, client, params);
- }
- };
- return ui.projectUI(folder, client, params);
+ return new LspTemplateUI().projectUI(folder, client, params);
}
private CompletableFuture<Object> templateUI(DataFolder templates, NbCodeLanguageClient client, ExecuteCommandParams params) {
CompletionStage<DataObject> findTemplate = findTemplate(templates, client);
- CompletionStage<Pair<DataFolder, String>> findTargetFolderAndName = findTargetAndName(findTemplate, client, params);
- return findTargetFolderAndName.thenCombineAsync(findTemplate, (targetAndName, source) -> {
- final String name = targetAndName.second();
- if (name == null || name.isEmpty()) {
- throw raise(RuntimeException.class, new UserCancelException());
- }
+ CompletionStage<DataFolder> findTargetFolder = findTargetForTemplate(findTemplate, client, params);
+ return findTargetFolder.thenCombine(findTemplate, (target, source) -> {
+ final FileObject templateFileObject = source.getPrimaryFile();
+ return new FileBuilder(templateFileObject, target.getPrimaryFile()).name(templateFileObject.getName());
+ }).thenCompose(builder -> configure(builder, client)).thenApplyAsync(builder -> {
try {
- DataFolder target = targetAndName.first();
- Map<String,String> prjParams = new HashMap<>();
- DataObject newObject = source.createFromTemplate(target, name, prjParams);
- return (Object) newObject.getPrimaryFile().toURI().toString();
+ if (builder != null) {
+ List<FileObject> created = builder.build();
+ return created != null ? (Object) created.stream().map(fo -> fo.toURI().toString()).collect(Collectors.toList()) : null;
+ }
+ return null;
} catch (IOException ex) {
throw raise(RuntimeException.class, ex);
}
@@ -138,7 +126,7 @@ abstract class LspTemplateUI {
private CompletableFuture<Object> projectUI(DataFolder templates, NbCodeLanguageClient client, ExecuteCommandParams params) {
CompletionStage<DataObject> findTemplate = findTemplate(templates, client);
- CompletionStage<Pair<DataFolder, String>> findTargetFolderAndName = findTargetAndName(findTemplate, client, params);
+ CompletionStage<Pair<DataFolder, String>> findTargetFolderAndName = findTargetAndNameForProject(findTemplate, client, params);
CompletionStage<Pair<DataObject, String>> findTemplateAndPackage = findTemplate.thenCombine(findPackage(findTargetFolderAndName, client), Pair::of);
return findTargetFolderAndName.thenCombineAsync(findTemplateAndPackage, (targetAndName, templateAndPackage) -> {
try {
@@ -169,10 +157,10 @@ abstract class LspTemplateUI {
);
}
- private static CompletionStage<Pair<DataFolder, String>> findTargetAndNameForTemplate(CompletionStage<DataObject> findTemplate, NbCodeLanguageClient client, ExecuteCommandParams params) {
+ private static CompletionStage<DataFolder> findTargetForTemplate(CompletionStage<DataObject> findTemplate, NbCodeLanguageClient client, ExecuteCommandParams params) {
final DataObject[] templateObject = new DataObject[1];
- final CompletionStage<DataFolder> findTarget = findTemplate.thenCompose(any -> {
- templateObject[0] = any;
+ return findTemplate.thenCompose(any -> {
+ templateObject[0] = any;
return client.workspaceFolders();
}).thenCompose(folders -> {
boolean[] suggestionIsExact = { true };
@@ -197,15 +185,6 @@ abstract class LspTemplateUI {
}
return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectTarget(), suggestion.getPrimaryFile().getPath())).thenCompose(new VerifyPath());
});
- CompletionStage<String> findTargetName = findTarget.thenCombine(findTemplate, (target, source) -> source).thenCompose((source) -> {
- return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectName(), source.getName()));
- }).thenCombine(findTemplate, (nameWithExtension, source) -> {
- String templateExtension = source.getPrimaryFile().getExt();
- return removeExtensionFromFileName(nameWithExtension, templateExtension);
- });
- return findTarget.thenCombine(findTargetName, (t, u) -> {
- return Pair.of(t, u);
- });
}
private static CompletionStage<Pair<DataFolder, String>> findTargetAndNameForProject(CompletionStage<DataObject> findTemplate, NbCodeLanguageClient client, ExecuteCommandParams params) {
@@ -232,6 +211,18 @@ abstract class LspTemplateUI {
});
}
+ private static CompletionStage<FileBuilder> configure(FileBuilder builder, NbCodeLanguageClient client) {
+ CreateDescriptor desc = builder.createDescriptor(false);
+ FileObject template = desc.getTemplate();
+ Object handler = template.getAttribute(FileBuilder.ATTR_TEMPLATE_HANDLER);
+ if (handler == null) {
+ return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectName(), desc.getProposedName())).thenApply(name -> {
+ return name != null ? builder.name(name) : null;
+ });
+ }
+ return CompletableFuture.completedFuture(builder);
+ }
+
private static String suggestWorkspaceRoot(List<WorkspaceFolder> folders) throws IllegalArgumentException {
String suggestion = System.getProperty("user.dir");
if (folders != null && !folders.isEmpty()) try {
@@ -401,14 +392,6 @@ abstract class LspTemplateUI {
return findWorkspaceRoot(folders);
}
- private static String removeExtensionFromFileName(String nameWithExtension, String templateExtension) {
- if (nameWithExtension != null && nameWithExtension.endsWith('.' + templateExtension)) {
- return nameWithExtension.substring(0, nameWithExtension.length() - templateExtension.length() - 1);
- } else {
- return nameWithExtension;
- }
- }
-
private static List<QuickPickItem> quickPickTemplates(final DataFolder folder) {
Node[] arr = folder.getNodeDelegate().getChildren().getNodes(true);
List<QuickPickItem> categories = new ArrayList<>();
@@ -486,12 +469,4 @@ abstract class LspTemplateUI {
private static <T extends Exception> T raise(Class<T> clazz, Exception ex) throws T {
throw (T)ex;
}
-
- private static String findGroupId(String pkg, String name) {
- if (pkg.endsWith("." + name)) {
- return pkg.substring(0, pkg.length() - 1 - name.length());
- } else {
- return pkg;
- }
- }
}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java
index 1608657..ce29976 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceUIContext.java
@@ -18,6 +18,7 @@
*/
package org.netbeans.modules.java.lsp.server.protocol;
+import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.eclipse.lsp4j.MessageActionItem;
import org.eclipse.lsp4j.MessageParams;
@@ -56,6 +57,10 @@ class WorkspaceUIContext extends UIContext {
return client.showInputBox(params);
}
+ @Override
+ public CompletableFuture<List<QuickPickItem>> showQuickPick(ShowQuickPickParams params) {
+ return client.showQuickPick(params);
+ }
@Override
protected void logMessage(MessageParams msg) {
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/NotifyDescriptorAdapter.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/NotifyDescriptorAdapter.java
index fae190c..8407538 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/NotifyDescriptorAdapter.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/NotifyDescriptorAdapter.java
@@ -42,7 +42,9 @@ import javax.swing.JButton;
import org.eclipse.lsp4j.MessageActionItem;
import org.eclipse.lsp4j.MessageType;
import org.eclipse.lsp4j.ShowMessageRequestParams;
+import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem;
import org.netbeans.modules.java.lsp.server.protocol.ShowInputBoxParams;
+import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams;
import org.openide.NotifyDescriptor;
import org.openide.awt.Actions;
import org.openide.util.NbBundle;
@@ -289,6 +291,22 @@ class NotifyDescriptorAdapter {
inp.setInputText(item);
return NotifyDescriptor.OK_OPTION;
});
+ } else if (descriptor instanceof NotifyDescriptor.QuickPick) {
+ NotifyDescriptor.QuickPick qp = (NotifyDescriptor.QuickPick) descriptor;
+ Map<QuickPickItem, NotifyDescriptor.QuickPick.Item> items = new HashMap<>();
+ for (NotifyDescriptor.QuickPick.Item item : qp.getItems()) {
+ items.put(new QuickPickItem(item.getLabel(), item.getDescription(), null, item.isSelected(), null), item);
+ }
+ ShowQuickPickParams params = new ShowQuickPickParams(qp.getTitle(), qp.isMultipleSelection(), new ArrayList<>(items.keySet()));
+ return client.showQuickPick(params).thenApply(selected -> {
+ if (selected == null) {
+ return NotifyDescriptor.CLOSED_OPTION;
+ }
+ for (Map.Entry<QuickPickItem, NotifyDescriptor.QuickPick.Item> entry : items.entrySet()) {
+ entry.getValue().setSelected(selected.contains(entry.getKey()));
+ }
+ return NotifyDescriptor.OK_OPTION;
+ });
} else {
ShowMessageRequestParams params = createShowMessageRequest();
if (params == null) {
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java
index 8b27bf3..0fa9bd7 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/UIContext.java
@@ -20,6 +20,8 @@ package org.netbeans.modules.java.lsp.server.ui;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.eclipse.lsp4j.MessageActionItem;
import org.eclipse.lsp4j.MessageParams;
@@ -27,7 +29,9 @@ import org.eclipse.lsp4j.MessageType;
import org.eclipse.lsp4j.ShowMessageRequestParams;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams;
+import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem;
import org.netbeans.modules.java.lsp.server.protocol.ShowInputBoxParams;
+import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams;
import org.netbeans.modules.java.lsp.server.protocol.ShowStatusMessageParams;
import org.openide.awt.StatusDisplayer.Message;
import org.openide.util.Lookup;
@@ -98,6 +102,9 @@ public abstract class UIContext {
throw new AbstractMethodError();
}
+ protected CompletableFuture<List<QuickPickItem>> showQuickPick(ShowQuickPickParams params) {
+ throw new AbstractMethodError();
+ }
private static final class LogImpl extends UIContext {
static final LogImpl DEFAULT = new LogImpl();
@@ -145,5 +152,11 @@ public abstract class UIContext {
CompletableFuture<String> ai = CompletableFuture.completedFuture(null);
return ai;
}
+
+ @Override
+ protected CompletableFuture<List<QuickPickItem>> showQuickPick(ShowQuickPickParams params) {
+ System.err.println("quickPick: " + params.getPlaceHolder());
+ return CompletableFuture.completedFuture(Collections.emptyList());
+ }
}
}
diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/AbstractDialogDisplayerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/AbstractDialogDisplayerTest.java
index 017fb80..561978f 100644
--- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/AbstractDialogDisplayerTest.java
+++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/AbstractDialogDisplayerTest.java
@@ -18,7 +18,9 @@
*/
package org.netbeans.modules.java.lsp.server.ui;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import javax.swing.JPanel;
@@ -29,7 +31,9 @@ import org.eclipse.lsp4j.MessageType;
import org.eclipse.lsp4j.ShowMessageRequestParams;
import org.netbeans.junit.NbTestCase;
import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams;
+import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem;
import org.netbeans.modules.java.lsp.server.protocol.ShowInputBoxParams;
+import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams;
import org.netbeans.modules.java.lsp.server.protocol.ShowStatusMessageParams;
import org.openide.NotifyDescriptor;
import org.openide.awt.StatusDisplayer;
@@ -65,6 +69,11 @@ public class AbstractDialogDisplayerTest extends NbTestCase {
}
@Override
+ protected CompletableFuture<List<QuickPickItem>> showQuickPick(ShowQuickPickParams params) {
+ return CompletableFuture.completedFuture(Collections.emptyList());
+ }
+
+ @Override
protected void logMessage(MessageParams msg) {
}
diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts
index 5b6c468..2ea7e43 100644
--- a/java/java.lsp.server/vscode/src/extension.ts
+++ b/java/java.lsp.server/vscode/src/extension.ts
@@ -341,7 +341,14 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {
if (typeof res === 'string') {
let newFile = vscode.Uri.parse(res as string);
- await vscode.window.showTextDocument(newFile);
+ await vscode.window.showTextDocument(newFile, { preview: false });
+ } else if (Array.isArray(res)) {
+ for(let r of res) {
+ if (typeof r === 'string') {
+ let newFile = vscode.Uri.parse(r as string);
+ await vscode.window.showTextDocument(newFile, { preview: false });
+ }
+ }
}
} else {
throw `Client ${c} doesn't support new from template`;
diff --git a/platform/openide.dialogs/apichanges.xml b/platform/openide.dialogs/apichanges.xml
index 1c272f2..9b417be 100644
--- a/platform/openide.dialogs/apichanges.xml
+++ b/platform/openide.dialogs/apichanges.xml
@@ -28,6 +28,20 @@
<changes>
<change>
<api name="dialogs"/>
+ <summary>NotifyDescriptor.QuickPick added</summary>
+ <version major="7" minor="60"/>
+ <date day="15" month="2" year="2022"/>
+ <author login="dbalek"/>
+ <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
+ <description>
+ <p>
+ Added <code>QuickPick</code> providing a selection list allowing multiple selections.
+ </p>
+ </description>
+ <class package="org.openide" name="NotifyDescriptor"/>
+ </change>
+ <change>
+ <api name="dialogs"/>
<summary>Allow vetoable Next/Finish validation in wizard</summary>
<version major="7" minor="59"/>
<date day="31" month="1" year="2022"/>
diff --git a/platform/openide.dialogs/manifest.mf b/platform/openide.dialogs/manifest.mf
index d44e5ed..e2e94c5 100644
--- a/platform/openide.dialogs/manifest.mf
+++ b/platform/openide.dialogs/manifest.mf
@@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.openide.dialogs
-OpenIDE-Module-Specification-Version: 7.59
+OpenIDE-Module-Specification-Version: 7.60
OpenIDE-Module-Localizing-Bundle: org/openide/Bundle.properties
AutoUpdate-Essential-Module: true
diff --git a/platform/openide.dialogs/src/org/openide/NotifyDescriptor.java b/platform/openide.dialogs/src/org/openide/NotifyDescriptor.java
index 9320b5a..d4cedc3 100644
--- a/platform/openide.dialogs/src/org/openide/NotifyDescriptor.java
+++ b/platform/openide.dialogs/src/org/openide/NotifyDescriptor.java
@@ -22,19 +22,29 @@ package org.openide;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Window;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
+import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
+import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
+import javax.swing.JToggleButton;
import javax.swing.LayoutStyle;
import javax.swing.UIManager;
import org.openide.awt.Mnemonics;
@@ -1153,4 +1163,167 @@ public class NotifyDescriptor extends Object {
}
}
// end of InputLine
+
+ /** Notification providing a selection list allowing multiple selections.
+ * @since 7.60
+ */
+ public static final class QuickPick extends NotifyDescriptor {
+
+ private final String text;
+ private final List<Item> items;
+ private final boolean multipleSelection;
+
+ /**
+ * Construct dialog with the specified title and label text.
+ * @param text label text
+ * @param title title of the dialog
+ * @param items a list of items
+ * @param multipleSelection true if multiple selection allowed
+ * @since 7.60
+ */
+ public QuickPick(final String text, final String title, final List<Item> items, final boolean multipleSelection) {
+ super(null, title, OK_CANCEL_OPTION, PLAIN_MESSAGE, null, null);
+ this.text = text;
+ this.items = items;
+ this.multipleSelection = multipleSelection;
+ }
+
+ @Override
+ public Object getMessage() {
+ Object msg = super.getMessage();
+ if (msg != null) {
+ return msg;
+ }
+ JPanel panel = new JPanel();
+ panel.setOpaque (false);
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(panel);
+ panel.setLayout(layout);
+
+ JLabel label = new JLabel();
+ Mnemonics.setLocalizedText(label, text);
+
+ GroupLayout.ParallelGroup hGroup = layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(label);
+ GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(label);
+
+ final Map<JToggleButton, Item> btn2items = new LinkedHashMap<JToggleButton, Item>();
+ ItemListener listener = new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ JToggleButton btn = (JToggleButton) e.getItemSelectable();
+ Item item = btn2items.get(btn);
+ if (item != null) {
+ item.setSelected(btn.isSelected());
+ }
+ }
+ };
+
+ ButtonGroup buttonGroup = this.multipleSelection ? null : new ButtonGroup();
+ for (Item item : items) {
+ JToggleButton btn;
+ if (buttonGroup != null) {
+ btn = new JRadioButton();
+ buttonGroup.add(btn);
+ } else {
+ btn = new JCheckBox();
+ }
+ btn.setText(item.getLabel());
+ btn.setToolTipText(item.getDescription());
+ btn.setSelected(item.isSelected());
+ hGroup.addComponent(btn);
+ vGroup.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(btn);
+ btn.addItemListener(listener);
+ btn2items.put(btn, item);
+ }
+
+ layout.setHorizontalGroup(layout.createParallelGroup(Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(hGroup)
+ .addContainerGap())
+ );
+ layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(vGroup.addContainerGap())
+ );
+
+ this.setMessage(panel);
+ return panel;
+ }
+
+ /**
+ * Get the list of selection items.
+ * @return unmodifiable list of items
+ * @since 7.60
+ */
+ public List<Item> getItems() {
+ return Collections.unmodifiableList(items);
+ }
+
+ /**
+ * Check if the picker accepts multiple selections.
+ * @return true if multiple selection allowed
+ * @since 7.60
+ */
+ public boolean isMultipleSelection() {
+ return multipleSelection;
+ }
+
+ /**
+ * Item that can be selected from a list of items.
+ * @since 7.60
+ */
+ public static final class Item {
+
+ private final String label;
+ private final String description;
+ private boolean selected;
+
+ /**
+ * Creates item that can be selected from a list of items.
+ * @param label item's label
+ * @param description item's description
+ * @since 7.60
+ */
+ public Item(String label, String description) {
+ this.label = label;
+ this.description = description;
+ }
+
+ /**
+ * Item's label.
+ * @since 7.60
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Item's description.
+ * @since 7.60
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Flag indicating if this item is selected.
+ * @since 7.60
+ */
+ public boolean isSelected() {
+ return selected;
+ }
+
+ /**
+ * Marks item as selected.
+ * @since 7.60
+ */
+ public void setSelected(boolean selected) {
+ this.selected = selected;
+ }
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists