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 6f0cafcaff9aa9ad2a8d9df6598d5725dcaa8838 Author: Andrus Adamchik <[email protected]> AuthorDate: Mon Jul 20 18:31:10 2026 +0200 Fixing missed validations --- .../project/validation/DataMapValidator.java | 4 ++ .../cayenne/project/validation/NameValidator.java | 10 ++- .../project/validation/ObjEntityValidator.java | 6 +- .../project/validation/NameValidatorTest.java | 72 ++++++++++++++++++++++ 4 files changed, 87 insertions(+), 5 deletions(-) diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/DataMapValidator.java b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/DataMapValidator.java index c4931a8ae..4b617c777 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/DataMapValidator.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/DataMapValidator.java @@ -103,6 +103,10 @@ class DataMapValidator extends ConfigurationNodeValidator<DataMap> { if (invalidChars != null) { addFailure(validationResult, map, "DataMap '%s' Java package '%s' contains invalid characters: %s", map.getName(), javaPackage, invalidChars); + } else if (NameValidator.invalidJavaClassComponents(javaPackage)) { + addFailure(validationResult, map, + "DataMap '%s' Java package '%s' contains a reserved word or an empty name component", + map.getName(), javaPackage); } } } diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/NameValidator.java b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/NameValidator.java index 581e7c5e1..706ad6c46 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/NameValidator.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/NameValidator.java @@ -128,14 +128,18 @@ public class NameValidator { return !invalidChars.isEmpty() ? invalidChars : null; } + /** + * Returns whether a "."-separated class or package name contains invalid components: reserved Java + * keywords or empty segments ("com.default.Foo", "com..Foo", ".Foo", "Foo."). + */ public static boolean invalidJavaClassComponents(String classFQN) { if (classFQN == null) { return true; } - StringTokenizer toks = new StringTokenizer(classFQN, "."); - while (toks.hasMoreTokens()) { - if (RESERVED_JAVA_KEYWORDS.contains(toks.nextToken())) { + // the -1 limit keeps trailing empty segments that StringTokenizer would silently skip + for (String component : classFQN.split("\\.", -1)) { + if (component.isEmpty() || RESERVED_JAVA_KEYWORDS.contains(component)) { return true; } } diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/ObjEntityValidator.java b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/ObjEntityValidator.java index 2b33de354..b08fa2647 100644 --- a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/ObjEntityValidator.java +++ b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/ObjEntityValidator.java @@ -115,7 +115,8 @@ class ObjEntityValidator extends ConfigurationNodeValidator<ObjEntity> { addFailure(validationResult, entity, "ObjEntity '%s' Java class '%s' contains invalid characters: %s", entity.getName(), className, invalidChars); } else if (NameValidator.invalidJavaClassComponents(className)) { - addFailure(validationResult, entity, "Java class '%s' of ObjEntity '%s' is a reserved word", + addFailure(validationResult, entity, + "Java class '%s' of ObjEntity '%s' contains a reserved word or an empty name component", className, entity.getName()); } else if (className.indexOf('.') < 0) { addFailure(validationResult, entity, "Java class '%s' of ObjEntity '%s' is in a default package", @@ -136,7 +137,8 @@ class ObjEntityValidator extends ConfigurationNodeValidator<ObjEntity> { addFailure(validationResult, entity, "ObjEntity '%s' Java superclass '%s' contains invalid characters: %s", entity.getName(), superClassName, invalidChars); } else if (NameValidator.invalidJavaClassComponents(superClassName)) { - addFailure(validationResult, entity, "ObjEntity '%s' Java superclass '%s' is a reserved word", + addFailure(validationResult, entity, + "ObjEntity '%s' Java superclass '%s' contains a reserved word or an empty name component", entity.getName(), superClassName); } diff --git a/cayenne-project/src/test/java/org/apache/cayenne/project/validation/NameValidatorTest.java b/cayenne-project/src/test/java/org/apache/cayenne/project/validation/NameValidatorTest.java new file mode 100644 index 000000000..e58d0df1a --- /dev/null +++ b/cayenne-project/src/test/java/org/apache/cayenne/project/validation/NameValidatorTest.java @@ -0,0 +1,72 @@ +/***************************************************************** + * 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.project.validation; + +import org.junit.jupiter.api.Test; + +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.assertTrue; + +public class NameValidatorTest { + + @Test + public void invalidJavaClassComponents_Valid() { + assertFalse(NameValidator.invalidJavaClassComponents("Artist")); + assertFalse(NameValidator.invalidJavaClassComponents("org.example.model.Artist")); + assertFalse(NameValidator.invalidJavaClassComponents("org.example.model")); + } + + @Test + public void invalidJavaClassComponents_ReservedWords() { + assertTrue(NameValidator.invalidJavaClassComponents("class")); + assertTrue(NameValidator.invalidJavaClassComponents("com.default.Foo")); + assertTrue(NameValidator.invalidJavaClassComponents("org.example.switch")); + } + + @Test + public void invalidJavaClassComponents_EmptyComponents() { + assertTrue(NameValidator.invalidJavaClassComponents("")); + assertTrue(NameValidator.invalidJavaClassComponents("com..Foo")); + assertTrue(NameValidator.invalidJavaClassComponents(".Foo")); + assertTrue(NameValidator.invalidJavaClassComponents("Foo.")); + assertTrue(NameValidator.invalidJavaClassComponents(null)); + } + + @Test + public void invalidCharsInJavaClassName() { + assertNull(NameValidator.invalidCharsInJavaClassName("org.example.Artist")); + assertEquals("-", NameValidator.invalidCharsInJavaClassName("org.example.My-Class")); + assertEquals(" ", NameValidator.invalidCharsInJavaClassName("My Class")); + } + + @Test + public void invalidPersistentProperty() { + assertTrue(NameValidator.invalidPersistentProperty("class")); + assertTrue(NameValidator.invalidPersistentProperty("objectId")); + assertTrue(NameValidator.invalidPersistentProperty("objectContext")); + assertTrue(NameValidator.invalidPersistentProperty("persistenceState")); + assertTrue(NameValidator.invalidPersistentProperty("snapshotVersion")); + assertTrue(NameValidator.invalidPersistentProperty(null)); + + assertFalse(NameValidator.invalidPersistentProperty("name")); + assertFalse(NameValidator.invalidPersistentProperty("classRoom")); + } +}
