This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/master by this push:
     new 557882272 CAY-3003 Modeler: NPE editing unmapped ObjAttribute
557882272 is described below

commit 55788227221de159a4ea399a39461903b164bf78
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sat Aug 29 19:47:46 2026 -0400

    CAY-3003 Modeler: NPE editing unmapped ObjAttribute
---
 RELEASE-NOTES.txt                                           |  1 +
 .../org/apache/cayenne/modeler/project/ObjEntityOps.java    |  7 +++++--
 .../objentity/properties/DbAttributePathComboBoxEditor.java |  9 +++++++--
 .../editor/objentity/properties/ObjAttributeTableModel.java | 13 +++++++------
 .../objentity/properties/PathChooserComboBoxCellEditor.java |  7 ++++---
 5 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index f99cfb9b3..6e1947196 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -18,6 +18,7 @@ CAY-2999 Modeler: A restricted method in java.lang.System has 
been called
 CAY-3000 Modeler: unifying the main views of all model objects
 CAY-3001 Modeler: Auto-increment attribute is not picked up
 CAY-3002 Modeler: NPE after clicking path chooser
+CAY-3003 Modeler: NPE editing unmapped ObjAttribute
 
 ----------------------------------
 Release: 5.0-M3
diff --git 
a/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/project/ObjEntityOps.java
 
b/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/project/ObjEntityOps.java
index 421af5c48..46cb66f14 100644
--- 
a/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/project/ObjEntityOps.java
+++ 
b/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/project/ObjEntityOps.java
@@ -62,9 +62,12 @@ public class ObjEntityOps {
         // check individual attributes
         for (ObjAttribute oa : oe.getAttributes()) {
 
+            // the path is null for an attribute that was never mapped to a 
DbAttribute
+            CayennePath path = oa.getDbAttributePath();
+            String dbAttributePath = path != null ? path.value() : "";
+
             // If flattened attribute
-            String dbAttributePath = oa.getDbAttributePath().value();
-            if (dbAttributePath != null && dbAttributePath.contains(".")) {
+            if (dbAttributePath.contains(".")) {
                 String[] pathSplit = dbAttributePath.split("\\.");
 
                 // If flattened attribute
diff --git 
a/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/DbAttributePathComboBoxEditor.java
 
b/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/DbAttributePathComboBoxEditor.java
index 186d0e464..be150260e 100644
--- 
a/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/DbAttributePathComboBoxEditor.java
+++ 
b/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/DbAttributePathComboBoxEditor.java
@@ -79,8 +79,13 @@ class DbAttributePathComboBoxEditor extends 
PathChooserComboBoxCellEditor<ObjAtt
     @Override
     protected void initializeCombo(ObjAttributeTableModel model, int row, 
final JTable table) {
         super.initializeCombo(model, row, table);
-        
pathChooser.setSelectedItem(model.getAttribute(row).getDbAttributePath());
-        savePath = this.model.getAttribute(row).getDbAttributePath().value();
+        // the path is null for an attribute that was never mapped to a 
DbAttribute
+        CayennePath path = model.getAttribute(row).getDbAttributePath();
+        if (path == null) {
+            path = CayennePath.EMPTY_PATH;
+        }
+        pathChooser.setSelectedItem(path);
+        savePath = path.value();
     }
 
 
diff --git 
a/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributeTableModel.java
 
b/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributeTableModel.java
index f1bf0bf63..8f651fe53 100644
--- 
a/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributeTableModel.java
+++ 
b/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributeTableModel.java
@@ -35,14 +35,12 @@ import 
org.apache.cayenne.modeler.event.display.ObjEntityDisplayEvent;
 import org.apache.cayenne.modeler.event.model.ObjAttributeEvent;
 import org.apache.cayenne.modeler.event.model.ObjEntityEvent;
 import org.apache.cayenne.modeler.project.DbEntityOps;
-import org.apache.cayenne.modeler.toolkit.valuetype.ValueTypes;
 import org.apache.cayenne.modeler.toolkit.table.CMTableModel;
 import org.apache.cayenne.modeler.project.ProjectSession;
 import org.apache.cayenne.project.extension.info.ObjectInfo;
 import java.util.Objects;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 
@@ -224,17 +222,20 @@ public class ObjAttributeTableModel extends 
CMTableModel<ObjAttribute> {
         String newType = value != null ? value.toString() : null;
         attribute.setType(newType);
 
-        if (Arrays.asList(ValueTypes.getTypes()).contains(newType) || newType 
== null) {
+        boolean embedded = newType != null && 
session.entityResolver().getEmbeddable(newType) != null;
+        if (embedded == attribute instanceof EmbeddedAttribute) {
+            // the attribute is already of the right class, no need to rebuild 
it
             return;
         }
 
         ObjAttribute attributeNew;
-        if (session.entityResolver().getEmbeddable(newType) != null) {
+        if (embedded) {
+            // a fresh EmbeddedAttribute has a null path already, and an 
embedded attribute maps to no column
             attributeNew = new EmbeddedAttribute();
-            attributeNew.setDbAttributePath((String)null);
         } else {
             attributeNew = new ObjAttribute();
-            
attributeNew.setDbAttributePath(attribute.getDbAttributePath().value());
+            // the CayennePath overload, unlike the String one, tolerates a 
null path
+            attributeNew.setDbAttributePath(attribute.getDbAttributePath());
         }
 
         ObjEntity entity = attribute.getEntity();
diff --git 
a/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/PathChooserComboBoxCellEditor.java
 
b/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/PathChooserComboBoxCellEditor.java
index fff9dd023..c50b679a8 100644
--- 
a/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/PathChooserComboBoxCellEditor.java
+++ 
b/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/PathChooserComboBoxCellEditor.java
@@ -245,11 +245,12 @@ abstract class PathChooserComboBoxCellEditor<T extends 
CMTableModel<?>> extends
         public Component getListCellRendererComponent(
                 JList<?> list, Object value, int index, boolean isSelected, 
boolean cellHasFocus) {
 
+            String path = value != null ? value.toString() : "";
+
             JPanel panel = new JPanel(new BorderLayout());
-            JLabel label = new JLabel(value.toString());
-            panel.add(label);
+            panel.add(new JLabel(path));
 
-            Object currentNode = getCurrentNode(value.toString());
+            Object currentNode = getCurrentNode(path);
             if (treeModel.isLeaf(currentNode)) {
                 ListCellRenderer<Object> leafRenderer = 
Renderers.listRenderer();
                 return leafRenderer.getListCellRendererComponent(list, value, 
index, isSelected, cellHasFocus);

Reply via email to