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
commit 5713180292e1612bd7f9f00482f041ee716ef54b Author: Andrus Adamchik <[email protected]> AuthorDate: Thu Jun 25 18:44:08 2026 -0400 CAY-2965 MCP Cgen should not fail on an absent "<cgen>" tag unifying default config API --- .../org/apache/cayenne/gen/CgenConfiguration.java | 34 +++++++++ .../apache/cayenne/gen/CgenConfigurationTest.java | 81 ++++++++++++++++++++++ .../apache/cayenne/mcp/tools/cgen/CgenRunTool.java | 23 +----- .../editor/datadomain/cgen/DataDomainCgenTab.java | 7 +- .../ui/project/editor/datamap/cgen/CgenPanel.java | 14 +--- 5 files changed, 119 insertions(+), 40 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 2183201a3..6d2fd810e 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 @@ -20,6 +20,7 @@ package org.apache.cayenne.gen; import org.apache.cayenne.configuration.ConfigurationNodeVisitor; +import org.apache.cayenne.gen.internal.Utils; import org.apache.cayenne.gen.xml.CgenExtension; import org.apache.cayenne.map.DataMap; import org.apache.cayenne.map.Embeddable; @@ -127,6 +128,39 @@ public class CgenConfiguration implements Serializable, XMLSerializable { this.embeddableSuperTemplate = TemplateType.EMBEDDABLE_SUPERCLASS.defaultTemplate(); } + /** + * Builds a default configuration for a DataMap that has no stored cgen config, generating every + * non-generic entity and embeddable into the given output directory. + * + * @param outputDir directory to generate classes into; if {@code null}, the output path is left unset + * @since 5.0 + */ + public static CgenConfiguration createDefault(DataMap dataMap, Path outputDir) { + CgenConfiguration config = new CgenConfiguration(); + config.setDataMap(dataMap); + dataMap.getObjEntities().forEach(config::loadEntity); + dataMap.getEmbeddables().forEach(config::loadEmbeddable); + if (dataMap.getConfigurationSource() != null) { + config.setRootPath(Utils.getRootPathForDataMap(dataMap)); + } + if (outputDir != null) { + config.updateOutputPath(outputDir); + } + return config; + } + + /** + * Returns the default output directory for a saved DataMap, derived from the standard Maven + * source layout ({@code src/main/resources} → {@code src/main/java}, likewise for + * {@code test}), falling back to the DataMap's own directory for non-Maven layouts. + * + * @since 5.0 + */ + public static Path defaultOutputDir(DataMap dataMap) { + Path mapDir = Utils.getRootPathForDataMap(dataMap); + return Utils.getMavenSrcPathForPath(mapDir).map(Path::of).orElse(mapDir); + } + public void resetCollections() { embeddableArtifacts.clear(); entityArtifacts.clear(); 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 index b306cb565..18d63718b 100644 --- a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/CgenConfigurationTest.java +++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/CgenConfigurationTest.java @@ -19,22 +19,103 @@ package org.apache.cayenne.gen; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.Embeddable; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.resource.URLResource; import org.apache.cayenne.validation.ValidationException; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Locale; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class CgenConfigurationTest { + @Nested + public class CreateDefaultTest { + + private DataMap savedMap(Path mapFile) throws MalformedURLException { + DataMap map = unsavedMap(); + map.setConfigurationSource(new URLResource(mapFile.toUri().toURL())); + return map; + } + + private DataMap unsavedMap() { + DataMap map = new DataMap("test"); + + ObjEntity person = new ObjEntity("Person"); + person.setClassName("com.example.Person"); + map.addObjEntity(person); + + // generic entity (no class name) — must be excluded from generation + map.addObjEntity(new ObjEntity("Generic")); + + map.addEmbeddable(new Embeddable("com.example.Address")); + return map; + } + + @Test + public void populatesNonGenericArtifacts(@TempDir Path tmp) throws IOException { + Path mapFile = Files.createFile(tmp.resolve("test.map.xml")); + CgenConfiguration config = CgenConfiguration.createDefault(savedMap(mapFile), tmp); + + assertTrue(config.getEntities().contains("Person")); + assertFalse(config.getEntities().contains("Generic"), "Generic entity must be skipped"); + assertTrue(config.getEmbeddables().contains("com.example.Address")); + } + + @Test + public void derivesMavenOutputDir(@TempDir Path tmp) throws IOException { + Path resources = Files.createDirectories(tmp.resolve("src/main/resources")); + Path mapFile = Files.createFile(resources.resolve("test.map.xml")); + DataMap map = savedMap(mapFile); + + // src/main/resources -> src/main/java + Path outputDir = CgenConfiguration.defaultOutputDir(map); + assertEquals(tmp.resolve("src/main/java"), outputDir); + + CgenConfiguration config = CgenConfiguration.createDefault(map, outputDir); + assertEquals(resources, config.getRootPath()); + assertEquals(tmp.resolve("src/main/java"), config.buildOutputPath()); + } + + @Test + public void explicitOutputDir(@TempDir Path tmp) throws IOException { + Path mapFile = Files.createFile(tmp.resolve("test.map.xml")); + Path outputDir = tmp.resolve("custom/output"); + + CgenConfiguration config = CgenConfiguration.createDefault(savedMap(mapFile), outputDir); + + assertEquals(outputDir, config.buildOutputPath()); + } + + @Test + public void unsavedMapSkipsRootPath() { + CgenConfiguration config = CgenConfiguration.createDefault(unsavedMap(), null); + + assertNull(config.getRootPath()); + assertNull(config.buildOutputPath()); + // artifacts still populated even without a saved location + assertTrue(config.getEntities().contains("Person")); + assertTrue(config.getEmbeddables().contains("com.example.Address")); + } + } + @Nested public class CgenWindowsConfigurationTest { diff --git a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/cgen/CgenRunTool.java b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/cgen/CgenRunTool.java index bbf45f51f..56017064f 100644 --- a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/cgen/CgenRunTool.java +++ b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/cgen/CgenRunTool.java @@ -28,7 +28,6 @@ import org.apache.cayenne.gen.CgenConfigList; import org.apache.cayenne.gen.CgenConfiguration; import org.apache.cayenne.gen.MetadataUtils; import org.apache.cayenne.gen.ToolsUtilsFactory; -import org.apache.cayenne.gen.internal.Utils; import org.apache.cayenne.map.DataMap; import org.apache.cayenne.mcp.project.McpProjectLoaderModule; import org.apache.cayenne.mcp.log.McpLoggingHandler; @@ -165,7 +164,7 @@ public class CgenRunTool { CgenConfigList configList = metaData.get(dataMap, CgenConfigList.class); boolean usedDefaultConfig = configList == null || configList.getAll().isEmpty(); CgenConfiguration cgenConfig = usedDefaultConfig - ? defaultConfig(dataMap) + ? CgenConfiguration.createDefault(dataMap, CgenConfiguration.defaultOutputDir(dataMap)) : configList.getAll().getFirst(); // Set the DataMap file's mtime as the timestamp so fileNeedUpdate() can detect DataMap changes correctly. @@ -246,26 +245,6 @@ public class CgenRunTool { ); } - /** - * Builds a default cgen configuration for a DataMap that has no embedded {@code <cgen>} block. - * Mirrors {@code CgenPanel.createDefaultCgenConfiguration} in CayenneModeler: generate every - * entity and embeddable, with the destination derived from the standard Maven source layout - * ({@code src/main/resources} → {@code src/main/java}, likewise for {@code test}). For projects - * that don't follow the Maven layout the destination falls back to the DataMap's own directory. - */ - private static CgenConfiguration defaultConfig(DataMap dataMap) { - Path mapDir = Utils.getRootPathForDataMap(dataMap); - Path outputPath = Utils.getMavenSrcPathForPath(mapDir).map(Path::of).orElse(mapDir); - - CgenConfiguration config = new CgenConfiguration(); - config.setDataMap(dataMap); - dataMap.getObjEntities().forEach(config::loadEntity); - dataMap.getEmbeddables().forEach(config::loadEmbeddable); - config.setRootPath(mapDir); - config.updateOutputPath(outputPath); - return config; - } - private static CgenRunResult validationFailed(CgenErrorCode code, String message, CgenValidation validation) { return new CgenRunResult( "validation_failed", diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/cgen/DataDomainCgenTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/cgen/DataDomainCgenTab.java index b9327c765..01f37b8aa 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/cgen/DataDomainCgenTab.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/cgen/DataDomainCgenTab.java @@ -85,13 +85,8 @@ public class DataDomainCgenTab extends DataDomainGeneratorsTab<CgenConfiguration } public CgenConfiguration createConfiguration(DataMap dataMap) { - CgenConfiguration cgenConfiguration = new CgenConfiguration(); - cgenConfiguration.setDataMap(dataMap); - cgenConfiguration.updateOutputPath(CgenOps.baseDir(session)); + CgenConfiguration cgenConfiguration = CgenConfiguration.createDefault(dataMap, CgenOps.baseDir(session)); cgenConfiguration.setEncoding(new GeneralPrefs(app.getPrefsLocator().appNode(GeneralPrefs.NODE)).getEncoding()); - - cgenConfiguration.resolveExcludedEntities(); - cgenConfiguration.resolveExcludedEmbeddables(); return cgenConfiguration; } diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/cgen/CgenPanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/cgen/CgenPanel.java index b1b147830..3e360faaa 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/cgen/CgenPanel.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/cgen/CgenPanel.java @@ -31,7 +31,6 @@ import org.apache.cayenne.gen.CgenConfigList; import org.apache.cayenne.gen.CgenConfiguration; import org.apache.cayenne.gen.ClassGenerationAction; import org.apache.cayenne.gen.ClassGenerationActionFactory; -import org.apache.cayenne.gen.internal.Utils; import org.apache.cayenne.map.DataMap; import org.apache.cayenne.map.Embeddable; import org.apache.cayenne.map.Entity; @@ -437,18 +436,9 @@ public class CgenPanel extends ProjectPanel implements ObjEntityListener, Embedd } private CgenConfiguration createDefaultCgenConfiguration(DataMap map) { - CgenConfiguration configuration = new CgenConfiguration(); - configuration.setName(CgenConfigList.DEFAULT_CONFIG_NAME); + Path basePath = map.getLocation() != null ? CgenOps.baseDir(session) : null; + CgenConfiguration configuration = CgenConfiguration.createDefault(map, basePath); configuration.setForce(true); - configuration.setDataMap(map); - - map.getObjEntities().forEach(configuration::loadEntity); - map.getEmbeddables().forEach(configuration::loadEmbeddable); - if (map.getLocation() != null) { - Path basePath = CgenOps.baseDir(session); - configuration.setRootPath(Utils.getRootPathForDataMap(map)); - configuration.updateOutputPath(basePath); - } configuration.setEncoding(new GeneralPrefs(app.getPrefsLocator().appNode(GeneralPrefs.NODE)).getEncoding()); return configuration; }
