You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2021/05/18 08:36:21 UTC

[cayenne] branch master updated (55e329a -> 8b34b38)

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

ntimofeev pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git.


    from 55e329a  Remove JDK 16 as protostuff fails on it permanently.
     new 847ada1  CAY-2710 Modeler: modeler throws IllegalArgumentsException when root and rel paths have different roots
     new c1b9f38  Merge remote-tracking branch 'parent/pr/455'
     new 8b34b38  CAY-2710 Modeler: modeler throws IllegalArgumentsException when root and rel paths have different root

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 RELEASE-NOTES.txt                                  |   1 +
 .../org/apache/cayenne/gen/CgenConfiguration.java  |  88 ++++----
 .../apache/cayenne/gen/xml/CgenSaverDelegate.java  |   8 +-
 .../apache/cayenne/gen/CgenConfigurationTest.java  | 248 +++++++++++++++++++++
 .../cayenne/gen/xml/CgenSaverDelegateTest.java     |   4 +
 .../editor/cgen/CodeGeneratorController.java       |  54 +++--
 .../modeler/editor/cgen/GeneratorController.java   |   5 +-
 .../editor/cgen/GeneratorControllerPanel.java      |  10 +-
 8 files changed, 350 insertions(+), 68 deletions(-)
 create mode 100644 cayenne-cgen/src/test/java/org/apache/cayenne/gen/CgenConfigurationTest.java

[cayenne] 03/03: CAY-2710 Modeler: modeler throws IllegalArgumentsException when root and rel paths have different root

Posted by nt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8b34b38763926d01aceb9c2a0ff2d7f329004b94
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Tue May 18 11:36:08 2021 +0300

    CAY-2710 Modeler: modeler throws IllegalArgumentsException when root and rel paths have different root
---
 RELEASE-NOTES.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 2f41f56..b14933a 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -23,6 +23,7 @@ CAY-2706 Modeler: object attribute dialog doesn't properly initialized for the e
 CAY-2707 Modeler: code generation is broken in the DataDomain tab
 CAY-2708 Gradle build plugin fails on Java 16
 CAY-2709 Modeler: Cgen fails to generate code for a new unsaved project with all settings set to default
+CAY-2710 Modeler: modeler throws IllegalArgumentsException when root and rel paths have different root
 
 ----------------------------------
 Release: 4.2.M3

[cayenne] 02/03: Merge remote-tracking branch 'parent/pr/455'

Posted by nt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c1b9f38d3a708d08894ad1892bd799d74bfa0896
Merge: 55e329a 847ada1
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Tue May 18 11:26:16 2021 +0300

    Merge remote-tracking branch 'parent/pr/455'

 .../org/apache/cayenne/gen/CgenConfiguration.java  |  88 ++++----
 .../apache/cayenne/gen/xml/CgenSaverDelegate.java  |   8 +-
 .../apache/cayenne/gen/CgenConfigurationTest.java  | 248 +++++++++++++++++++++
 .../cayenne/gen/xml/CgenSaverDelegateTest.java     |   4 +
 .../editor/cgen/CodeGeneratorController.java       |  54 +++--
 .../modeler/editor/cgen/GeneratorController.java   |   5 +-
 .../editor/cgen/GeneratorControllerPanel.java      |  10 +-
 7 files changed, 349 insertions(+), 68 deletions(-)

[cayenne] 01/03: CAY-2710 Modeler: modeler throws IllegalArgumentsException when root and rel paths have different roots

Posted by nt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 847ada1ebe897deddfe54a1ee2c4490d953ce028
Author: keyris <ke...@gmail.com>
AuthorDate: Tue May 18 11:16:04 2021 +0300

    CAY-2710 Modeler: modeler throws IllegalArgumentsException when root and rel paths have different roots
---
 .../org/apache/cayenne/gen/CgenConfiguration.java  |  88 ++++----
 .../apache/cayenne/gen/xml/CgenSaverDelegate.java  |   8 +-
 .../apache/cayenne/gen/CgenConfigurationTest.java  | 248 +++++++++++++++++++++
 .../cayenne/gen/xml/CgenSaverDelegateTest.java     |   4 +
 .../editor/cgen/CodeGeneratorController.java       |  54 +++--
 .../modeler/editor/cgen/GeneratorController.java   |   5 +-
 .../editor/cgen/GeneratorControllerPanel.java      |  10 +-
 7 files changed, 349 insertions(+), 68 deletions(-)

diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/CgenConfiguration.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/CgenConfiguration.java
index 06cd354..02e81cd 100644
--- a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/CgenConfiguration.java
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/CgenConfiguration.java
@@ -22,11 +22,7 @@ package org.apache.cayenne.gen;
 import java.io.Serializable;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
@@ -36,12 +32,14 @@ import org.apache.cayenne.map.Embeddable;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.util.XMLEncoder;
 import org.apache.cayenne.util.XMLSerializable;
+import org.apache.cayenne.validation.ValidationException;
 
 /**
  * Used to keep config of class generation action.
  * Previously was the part of ClassGeneretionAction class.
  * Now CgenConfiguration is saved in dataMap file.
  * You can reuse it in next cgen actions.
+ *
  * @since 4.1
  */
 public class CgenConfiguration implements Serializable, XMLSerializable {
@@ -85,7 +83,7 @@ public class CgenConfiguration implements Serializable, XMLSerializable {
      * @since 4.2
      */
     private String externalToolConfig;
-    
+
     public CgenConfiguration(boolean client) {
         /**
          * {@link #isDefault()} method should be in sync with the following values
@@ -105,7 +103,7 @@ public class CgenConfiguration implements Serializable, XMLSerializable {
 
         this.client = client;
 
-        if(!client) {
+        if (!client) {
             this.template = ClassGenerationAction.SUBCLASS_TEMPLATE;
             this.superTemplate = ClassGenerationAction.SUPERCLASS_TEMPLATE;
             this.queryTemplate = ClassGenerationAction.DATAMAP_SUBCLASS_TEMPLATE;
@@ -120,7 +118,7 @@ public class CgenConfiguration implements Serializable, XMLSerializable {
         this.embeddableSuperTemplate = ClassGenerationAction.EMBEDDABLE_SUPERCLASS_TEMPLATE;
     }
 
-    public void resetCollections(){
+    public void resetCollections() {
         embeddableArtifacts.clear();
         entityArtifacts.clear();
     }
@@ -149,7 +147,7 @@ public class CgenConfiguration implements Serializable, XMLSerializable {
         }
     }
 
-    public String getArtifactsGenerationMode(){
+    public String getArtifactsGenerationMode() {
         return artifactsGenerationMode.getLabel();
     }
 
@@ -176,12 +174,20 @@ public class CgenConfiguration implements Serializable, XMLSerializable {
 
     public void setRelPath(String pathStr) {
         Path path = Paths.get(pathStr);
-        if(path.isAbsolute() && rootPath != null) {
-            this.relPath = rootPath.relativize(path);
-        } else {
-            this.relPath = path;
+
+        if (rootPath != null) {
+
+            if (!rootPath.isAbsolute()) {
+                throw new ValidationException("Root path : " + '"' + rootPath.toString() + '"' + "should be absolute");
+            }
+
+            if (path.isAbsolute() && rootPath.getRoot().equals(path.getRoot())) {
+                this.relPath = rootPath.relativize(path);
+                return;
+            }
         }
-	}
+        this.relPath = path;
+    }
 
     public boolean isOverwrite() {
         return overwrite;
@@ -300,7 +306,7 @@ public class CgenConfiguration implements Serializable, XMLSerializable {
     }
 
     public String buildRelPath() {
-        if(relPath == null || relPath.toString().isEmpty()) {
+        if (relPath == null || relPath.toString().isEmpty()) {
             return ".";
         }
         return relPath.toString();
@@ -327,23 +333,23 @@ public class CgenConfiguration implements Serializable, XMLSerializable {
     }
 
     public String getExternalToolConfig() {
-    	return externalToolConfig;
+        return externalToolConfig;
     }
-    
+
     public void setExternalToolConfig(String config) {
-    	this.externalToolConfig = config;
+        this.externalToolConfig = config;
     }
-    
+
     void addArtifact(Artifact artifact) {
         artifacts.add(artifact);
     }
 
     public Path buildPath() {
-		return rootPath != null ? relPath != null ? rootPath.resolve(relPath).toAbsolutePath().normalize() : rootPath : relPath;
-	}
+        return rootPath != null ? relPath != null ? rootPath.resolve(relPath).toAbsolutePath().normalize() : rootPath : relPath;
+    }
 
     public void loadEntity(ObjEntity entity) {
-        if(!entity.isGeneric()) {
+        if (!entity.isGeneric()) {
             entityArtifacts.add(entity.getName());
         }
     }
@@ -378,23 +384,23 @@ public class CgenConfiguration implements Serializable, XMLSerializable {
         return String.join(",", excludeEmbeddable);
     }
 
-	public void resolveExcludeEntities() {
-		entityArtifacts = dataMap.getObjEntities()
-				.stream()
-				.map(ObjEntity::getName)
-				.filter(name -> !excludeEntityArtifacts.contains(name))
-				.collect(Collectors.toSet());
-	}
+    public void resolveExcludeEntities() {
+        entityArtifacts = dataMap.getObjEntities()
+                .stream()
+                .map(ObjEntity::getName)
+                .filter(name -> !excludeEntityArtifacts.contains(name))
+                .collect(Collectors.toSet());
+    }
 
-	public void resolveExcludeEmbeddables() {
-    	embeddableArtifacts = dataMap.getEmbeddables()
-				.stream()
-				.map(Embeddable::getClassName)
-				.filter(className -> !excludeEmbeddableArtifacts.contains(className))
-				.collect(Collectors.toSet());
-	}
+    public void resolveExcludeEmbeddables() {
+        embeddableArtifacts = dataMap.getEmbeddables()
+                .stream()
+                .map(Embeddable::getClassName)
+                .filter(className -> !excludeEmbeddableArtifacts.contains(className))
+                .collect(Collectors.toSet());
+    }
 
-	public Collection<String> getExcludeEntityArtifacts() {
+    public Collection<String> getExcludeEntityArtifacts() {
         return excludeEntityArtifacts;
     }
 
@@ -442,12 +448,12 @@ public class CgenConfiguration implements Serializable, XMLSerializable {
                 && !createPropertyNames
                 && "*.java".equals(outputPattern)
                 && (template.equals(ClassGenerationAction.SUBCLASS_TEMPLATE)
-                    || template.equals(ClientClassGenerationAction.SUBCLASS_TEMPLATE))
+                || template.equals(ClientClassGenerationAction.SUBCLASS_TEMPLATE))
                 && (superTemplate.equals(ClassGenerationAction.SUPERCLASS_TEMPLATE)
-                    || superTemplate.equals(ClientClassGenerationAction.SUPERCLASS_TEMPLATE))
+                || superTemplate.equals(ClientClassGenerationAction.SUPERCLASS_TEMPLATE))
                 && (superPkg == null
-                    || superPkg.isEmpty())
+                || superPkg.isEmpty())
                 && (externalToolConfig == null
-                    || externalToolConfig.isEmpty());
+                || externalToolConfig.isEmpty());
     }
 }
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
index ea94c72..2724cb8 100644
--- a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
@@ -72,9 +72,15 @@ public class CgenSaverDelegate extends BaseSaverDelegate {
         Path prevPath = cgenConfiguration.buildPath();
         if(prevPath != null) {
             if(prevPath.isAbsolute()) {
-                Path relPath = resourcePath.relativize(prevPath).normalize();
+
+                Path relPath = prevPath;
+
+                if (resourcePath.getRoot().equals(prevPath.getRoot())) {
+                    relPath = resourcePath.relativize(prevPath).normalize();
+                }
                 cgenConfiguration.setRelPath(relPath);
             }
+
             Path templatePath = Paths.get(cgenConfiguration.getTemplate());
             if(templatePath.isAbsolute()) {
                 cgenConfiguration.setTemplate(resourcePath.relativize(templatePath).normalize().toString());
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/CgenConfigurationTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/CgenConfigurationTest.java
new file mode 100644
index 0000000..fd5572c
--- /dev/null
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/CgenConfigurationTest.java
@@ -0,0 +1,248 @@
+/*****************************************************************
+ *   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
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.gen;
+
+import org.apache.cayenne.validation.ValidationException;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Locale;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Enclosed.class)
+public class CgenConfigurationTest {
+
+    public static class СgenWindowsConfigurationTest {
+
+        CgenConfiguration configuration;
+
+        @Before
+        public void setUp() {
+            configuration = new CgenConfiguration(false);
+        }
+
+        @Before
+        public void checkPlatform() {
+            Assume.assumeTrue(System.getProperty("os.name").toLowerCase(Locale.ROOT).startsWith("win"));
+        }
+
+        @Test
+        public void equalRootsEqualDirectories() {
+            configuration.setRootPath(Paths.get("C:\\test1\\test2\\test3"));
+            Path relPath = Paths.get("C:\\test1\\test2\\test3");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get(""), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void equalRootsNotEqualDirectories() {
+            configuration.setRootPath(Paths.get("C:\\test1\\test2\\test3"));
+            Path relPath = Paths.get("C:\\test1\\test2\\testAnother");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get("..\\testAnother"), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void equalRootsEmptyDirectories() {
+            configuration.setRootPath(Paths.get("C:\\"));
+            Path relPath = Paths.get("C:\\");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get(""), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void notEqualRootsEqualDirectories() {
+            configuration.setRootPath(Paths.get("C:\\test1\\test2\\test3"));
+            Path relPath = Paths.get("E:\\test1\\test2\\test3");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get("E:\\test1\\test2\\test3"), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void notEqualRootsNotEqualDirectories() {
+            configuration.setRootPath(Paths.get("C:\\test1\\test2\\test3"));
+            Path relPath = Paths.get("E:\\test1\\test2\\testAnother");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get("E:\\test1\\test2\\testAnother"), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void notEqualRootsEmptyDirectories() {
+            configuration.setRootPath(Paths.get("C:\\"));
+            Path relPath = Paths.get("E:\\");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get("E:\\"), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test(expected = ValidationException.class)
+        public void emptyRootNotEmptyRelPath() {
+            configuration.setRootPath(Paths.get(""));
+            Path relPath = Paths.get("E:\\");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get("E:\\"), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void notEmptyRootEmptyRelPath() {
+            configuration.setRootPath(Paths.get("E:\\"));
+            Path relPath = Paths.get("");
+
+            configuration.setRelPath(relPath);
+
+            assertEquals(relPath, configuration.getRelPath());
+            assertEquals(Paths.get("E:\\"), configuration.buildPath());
+        }
+
+        @Test(expected = InvalidPathException.class)
+        public void invalidRelPath() {
+            configuration.setRootPath(Paths.get("C:\\test1\\test2\\test3"));
+            configuration.setRelPath("invalidRoot:\\test");
+        }
+
+        @Test(expected = InvalidPathException.class)
+        public void invalidRootPath() {
+            configuration.setRootPath(Paths.get("invalidRoot:\\test"));
+            configuration.setRelPath("C:\\test1\\test2\\test3");
+        }
+
+        @Test
+        public void nullRootPath() {
+            configuration.setRelPath("C:\\test1\\test2\\test3");
+            assertEquals(Paths.get("C:\\test1\\test2\\test3"), configuration.getRelPath());
+            assertEquals(Paths.get("C:\\test1\\test2\\test3"), configuration.buildPath());
+        }
+    }
+
+    public static class СgenUnixConfigurationTest {
+
+        CgenConfiguration configuration;
+
+        @Before
+        public void setUp() {
+            configuration = new CgenConfiguration(false);
+        }
+
+        @Before
+        public void checkPlatform() {
+            Assume.assumeFalse(System.getProperty("os.name").toLowerCase(Locale.ROOT).startsWith("win"));
+        }
+
+        @Test
+        public void equalRootsEqualDirectories() {
+            configuration.setRootPath(Paths.get("/test1/test2/test3"));
+            Path relPath = Paths.get("/test1/test2/test3");
+            configuration.setRelPath(relPath.toString());
+
+
+            assertEquals(Paths.get(""), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void equalRootsNotEqualDirectories() {
+            configuration.setRootPath(Paths.get("/test1/test2/test3"));
+            Path relPath = Paths.get("/test1/test2/testAnother");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get("../testAnother"), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void equalRootsEmptyDirectories() {
+            configuration.setRootPath(Paths.get("/"));
+            Path relPath = Paths.get("/");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get(""), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void concatCorrectRootPathAndRelPath() {
+            configuration.setRootPath(Paths.get("/test1/test2/test3"));
+            Path relPath = Paths.get("test1/test2/test3");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get("test1/test2/test3"), configuration.getRelPath());
+            assertEquals(Paths.get("/test1/test2/test3/test1/test2/test3"), configuration.buildPath());
+        }
+
+        @Test(expected = ValidationException.class)
+        public void emptyRootNotEmptyRelPath() {
+            configuration.setRootPath(Paths.get(""));
+            Path relPath = Paths.get("/");
+            configuration.setRelPath(relPath.toString());
+
+            assertEquals(Paths.get("/"), configuration.getRelPath());
+            assertEquals(relPath, configuration.buildPath());
+        }
+
+        @Test
+        public void notEmptyRootEmptyRelPath() {
+            configuration.setRootPath(Paths.get("/"));
+            configuration.setRelPath("");
+
+            assertEquals(Paths.get(""), configuration.getRelPath());
+            assertEquals(Paths.get("/"), configuration.buildPath());
+        }
+
+        @Test(expected = ValidationException.class)
+        public void invalidRootPath() {
+            configuration.setRootPath(Paths.get("invalidRoot:/test"));
+            configuration.setRelPath("/test1/test2/test3");
+        }
+
+        @Test(expected = ValidationException.class)
+        public void concatInvalidRootPathAndRelPath() {
+            configuration.setRootPath(Paths.get("invalidRoot:/test"));
+            configuration.setRelPath("test1/test2/test3");
+        }
+
+        @Test
+        public void nullRootPath() {
+            configuration.setRelPath("/test1/test2/test3");
+            assertEquals(Paths.get("/test1/test2/test3"), configuration.getRelPath());
+            assertEquals(Paths.get("/test1/test2/test3"), configuration.buildPath());
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/xml/CgenSaverDelegateTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/xml/CgenSaverDelegateTest.java
index 37c910b..78be02e 100644
--- a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/xml/CgenSaverDelegateTest.java
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/xml/CgenSaverDelegateTest.java
@@ -73,4 +73,8 @@ public class CgenSaverDelegateTest {
     }
 
 
+
+
+
+
 }
\ No newline at end of file
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorController.java
index d292ac2..8b85e06 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorController.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorController.java
@@ -101,8 +101,8 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
         createConfiguration(dataMap);
 
         GeneratorController modeController = prevGeneratorController.get(dataMap);
-        if(modeController == null) {
-            if(cgenConfiguration.isDefault()) {
+        if (modeController == null) {
+            if (cgenConfiguration.isDefault()) {
                 modeController = cgenConfiguration.isClient()
                         ? generatorSelector.getClientGeneratorController()
                         : generatorSelector.getStandartController();
@@ -118,7 +118,7 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
         classesSelector.validate(classes);
     }
 
-    private void initListeners(){
+    private void initListeners() {
         projectController.addObjEntityListener(this);
         projectController.addEmbeddableListener(this);
         projectController.addDataMapListener(this);
@@ -207,7 +207,7 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
      */
     public void createConfiguration(DataMap map) {
         cgenConfiguration = projectController.getApplication().getMetaData().get(map, CgenConfiguration.class);
-        if(cgenConfiguration != null){
+        if (cgenConfiguration != null) {
             addToSelectedEntities(cgenConfiguration.getEntities());
             addToSelectedEmbeddables(cgenConfiguration.getEmbeddables());
             cgenConfiguration.setForce(true);
@@ -236,7 +236,9 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
             return;
         }
 
-        cgenConfiguration.setRootPath(basePath);
+        if (map.getLocation() != null) {
+            cgenConfiguration.setRootPath(basePath);
+        }
         Preferences preferences = application.getPreferencesNode(GeneralPreferences.class, "");
         if (preferences != null) {
             cgenConfiguration.setEncoding(preferences.get(GeneralPreferences.ENCODING_PREFERENCE, null));
@@ -260,7 +262,7 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
         boolean modified = selectionModel.updateSelection(predicate, classes);
 
         for (Object classObj : classes) {
-            if(classObj instanceof DataMap) {
+            if (classObj instanceof DataMap) {
                 boolean selected = predicate.test(classObj);
                 updateArtifactGenerationMode(selected);
             }
@@ -270,7 +272,7 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
     }
 
     private void updateArtifactGenerationMode(boolean selected) {
-        if(selected) {
+        if (selected) {
             cgenConfiguration.setArtifactsGenerationMode("all");
         } else {
             cgenConfiguration.setArtifactsGenerationMode("entity");
@@ -293,19 +295,19 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
         this.currentClass = currentClass;
     }
 
-    public void updateSelectedEntities(){
+    public void updateSelectedEntities() {
         updateEntities();
         updateEmbeddables();
     }
 
     public void checkCgenConfigDirty() {
-        if(initFromModel || cgenConfiguration == null) {
+        if (initFromModel || cgenConfiguration == null) {
             return;
         }
 
         DataMap map = projectController.getCurrentDataMap();
         CgenConfiguration existingConfig = projectController.getApplication().getMetaData().get(map, CgenConfiguration.class);
-        if(existingConfig == null) {
+        if (existingConfig == null) {
             getApplication().getMetaData().add(map, cgenConfiguration);
         }
 
@@ -313,9 +315,9 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
     }
 
     private void updateEntities() {
-        if(cgenConfiguration != null) {
+        if (cgenConfiguration != null) {
             cgenConfiguration.getEntities().clear();
-            for(ObjEntity entity: selectionModel.getSelectedEntities(classes)) {
+            for (ObjEntity entity : selectionModel.getSelectedEntities(classes)) {
                 cgenConfiguration.loadEntity(entity);
             }
         }
@@ -323,9 +325,9 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
     }
 
     private void updateEmbeddables() {
-        if(cgenConfiguration != null) {
+        if (cgenConfiguration != null) {
             cgenConfiguration.getEmbeddables().clear();
-            for(Embeddable embeddable : selectionModel.getSelectedEmbeddables(classes)) {
+            for (Embeddable embeddable : selectionModel.getSelectedEmbeddables(classes)) {
                 cgenConfiguration.loadEmbeddable(embeddable.getClassName());
             }
         }
@@ -340,7 +342,7 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
     void addEntity(DataMap dataMap, ObjEntity objEntity) {
         prepareClasses(dataMap);
         selectionModel.addSelectedEntity(objEntity.getName());
-        if(cgenConfiguration != null) {
+        if (cgenConfiguration != null) {
             cgenConfiguration.loadEntity(objEntity);
         }
         checkCgenConfigDirty();
@@ -376,7 +378,8 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
     }
 
     @Override
-    public void objEntityChanged(EntityEvent e) {}
+    public void objEntityChanged(EntityEvent e) {
+    }
 
     @Override
     public void objEntityAdded(EntityEvent e) {
@@ -386,21 +389,22 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
     @Override
     public void objEntityRemoved(EntityEvent e) {
         selectionModel.removeFromSelectedEntities((ObjEntity) e.getEntity());
-        if(cgenConfiguration != null) {
+        if (cgenConfiguration != null) {
             cgenConfiguration.getEntities().remove(e.getEntity().getName());
         }
         checkCgenConfigDirty();
     }
 
     @Override
-    public void embeddableChanged(EmbeddableEvent e, DataMap map) {}
+    public void embeddableChanged(EmbeddableEvent e, DataMap map) {
+    }
 
     @Override
     public void embeddableAdded(EmbeddableEvent e, DataMap map) {
         prepareClasses(map);
         String embeddableClassName = e.getEmbeddable().getClassName();
         selectionModel.addSelectedEmbeddable(embeddableClassName);
-        if(cgenConfiguration != null) {
+        if (cgenConfiguration != null) {
             cgenConfiguration.loadEmbeddable(embeddableClassName);
         }
         checkCgenConfigDirty();
@@ -409,7 +413,7 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
     @Override
     public void embeddableRemoved(EmbeddableEvent e, DataMap map) {
         selectionModel.removeFromSelectedEmbeddables(e.getEmbeddable());
-        if(cgenConfiguration != null) {
+        if (cgenConfiguration != null) {
             cgenConfiguration.getEmbeddables().remove(e.getEmbeddable().getClassName());
         }
         checkCgenConfigDirty();
@@ -417,8 +421,8 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
 
     @Override
     public void dataMapChanged(DataMapEvent e) {
-        if(e.getSource() instanceof DbImportController) {
-            if(cgenConfiguration != null) {
+        if (e.getSource() instanceof DbImportController) {
+            if (cgenConfiguration != null) {
                 for (ObjEntity objEntity : e.getDataMap().getObjEntities()) {
                     if (!cgenConfiguration.getExcludeEntityArtifacts().contains(objEntity.getName())) {
                         addEntity(cgenConfiguration.getDataMap(), objEntity);
@@ -430,10 +434,12 @@ public class CodeGeneratorController extends CayenneController implements ObjEnt
     }
 
     @Override
-    public void dataMapAdded(DataMapEvent e) {}
+    public void dataMapAdded(DataMapEvent e) {
+    }
 
     @Override
-    public void dataMapRemoved(DataMapEvent e) {}
+    public void dataMapRemoved(DataMapEvent e) {
+    }
 
     public CgenConfiguration getCgenConfiguration() {
         return cgenConfiguration;
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorController.java
index 545bee0..5346e2a 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorController.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorController.java
@@ -62,7 +62,10 @@ public abstract class GeneratorController extends CayenneController {
 
     protected void initForm(CgenConfiguration cgenConfiguration) {
         this.cgenConfiguration = cgenConfiguration;
-        getView().getOutputFolder().setText(cgenConfiguration.buildPath().toString());
+
+        if (cgenConfiguration.getRootPath() != null) {
+            getView().getOutputFolder().setText(cgenConfiguration.buildPath().toString());
+        }
         if(cgenConfiguration.getArtifactsGenerationMode().equalsIgnoreCase("all")) {
             getParentController().setCurrentClass(cgenConfiguration.getDataMap());
             getParentController().setSelected(true);
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorControllerPanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorControllerPanel.java
index 22e5c37..90f418b 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorControllerPanel.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorControllerPanel.java
@@ -27,6 +27,8 @@ import org.apache.cayenne.validation.ValidationException;
 import javax.swing.JButton;
 import javax.swing.JPanel;
 import javax.swing.JTextField;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 
 /**
  * @since 4.1
@@ -45,8 +47,14 @@ public class GeneratorControllerPanel extends JPanel {
         this.outputFolder = new TextAdapter(new JTextField()) {
             @Override
             protected void updateModel(String text) throws ValidationException {
+
                 CgenConfiguration cgenByDataMap = getCgenConfig();
-                if(cgenByDataMap != null) {
+
+                if (cgenByDataMap != null) {
+
+                    if (cgenByDataMap.getRootPath() == null && !Paths.get(text).isAbsolute()) {
+                        throw new ValidationException("You should save project to use rel path as output directory ");
+                    }
                     cgenByDataMap.setRelPath(text);
                     checkConfigDirty();
                 }