diff --git a/.github/project.yml b/.github/project.yml index 61790d9d..b8ef9df5 100644 --- a/.github/project.yml +++ b/.github/project.yml @@ -2,5 +2,5 @@ name: cui-java-tools pages-reference: cui-java-tools sonar-project-key: cuioss_cui-java-tools release: - current-version: 2.6.0 + current-version: 2.6.1 next-version: 2.6-SNAPSHOT diff --git a/doc/commands.md b/doc/commands.md new file mode 100644 index 00000000..178b4ce2 --- /dev/null +++ b/doc/commands.md @@ -0,0 +1,21 @@ +# Command Configuration + +## ./mvnw -Ppre-commit clean install + +### Last Execution Duration +- **Duration**: 57656ms (57.7 seconds) +- **Last Updated**: 2025-10-16 + +### Acceptable Warnings +- OpenRewrite `CuiLogRecordPatternRecipe` warnings about converting logging to LogRecord pattern +- Deprecation warning for `writeProperty` method in test code (intentional test of deprecated API) + +## handle-pull-request + +### CI/Sonar Duration +- **Duration**: 300000ms (5 minutes) +- **Last Updated**: 2025-10-16 + +### Notes +- This duration represents the time to wait for CI and SonarCloud checks to complete +- Includes buffer time for queue delays diff --git a/pom.xml b/pom.xml index e35e498f..94892e43 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ de.cuioss cui-java-parent - 1.2.5 + 1.3.3 diff --git a/src/main/java/de/cuioss/tools/io/ClassPathLoader.java b/src/main/java/de/cuioss/tools/io/ClassPathLoader.java index 75f5b416..41132812 100644 --- a/src/main/java/de/cuioss/tools/io/ClassPathLoader.java +++ b/src/main/java/de/cuioss/tools/io/ClassPathLoader.java @@ -142,6 +142,7 @@ private static URL resolveUrl(String path) { return url; } } + // cui-rewrite:disable CuiLogRecordPatternRecipe - Recipe bug: Cannot detect LogRecord through nested class LOGGER.info(INFO.CLASSPATH_RESOLUTION_FAILED, path); return null; } diff --git a/src/main/java/de/cuioss/tools/io/FileSystemLoader.java b/src/main/java/de/cuioss/tools/io/FileSystemLoader.java index d23ff076..331196f1 100644 --- a/src/main/java/de/cuioss/tools/io/FileSystemLoader.java +++ b/src/main/java/de/cuioss/tools/io/FileSystemLoader.java @@ -126,7 +126,7 @@ public static String checkPathName(final String pathName) { newPathName = new File(".").getCanonicalPath() + FileTypePrefix.EXTERNAL.removePrefix(pathName); LOGGER.debug("Loading config file from external path: %s", newPathName); } catch (final IOException e) { - LOGGER.error(e, ERROR.CURRENT_DIR_RETRIEVAL_FAILED::format); + LOGGER.error(e, ERROR.CURRENT_DIR_RETRIEVAL_FAILED); } } diff --git a/src/main/java/de/cuioss/tools/property/PropertyUtil.java b/src/main/java/de/cuioss/tools/property/PropertyUtil.java index 5380807a..8fbefe44 100644 --- a/src/main/java/de/cuioss/tools/property/PropertyUtil.java +++ b/src/main/java/de/cuioss/tools/property/PropertyUtil.java @@ -146,6 +146,25 @@ public static void setProperty(Object bean, String propertyName, Object property writePropertyWithChaining(bean, propertyName, propertyValue); } + /** + * Writes a value to a property of a bean using reflection and returns the bean for method chaining. + * This method violates Command-Query Separation by both modifying state and returning a value. + * Consider using {@link #setProperty(Object, String, Object)} for pure command operations. + * + * @param bean the bean to write to, must not be null + * @param propertyName the name of the property to write, must not be null or empty + * @param propertyValue the value to write to the property + * @return the bean instance (for method chaining) + * @throws IllegalArgumentException if the property cannot be written or does not exist + * @since 2.0 + * @deprecated Use {@link #setProperty(Object, String, Object)} for pure command operations + */ + @Deprecated(since = "2.4.1", forRemoval = true) + @SuppressWarnings("java:S1133") // Sonar: "Do not forget to remove this deprecated code someday" + // Intentionally deprecated with forRemoval=true. Removal planned for version 3.0. + public static Object writeProperty(Object bean, String propertyName, Object propertyValue) { + return writePropertyWithChaining(bean, propertyName, propertyValue); + } /** * Internal method for property writing with return value support. diff --git a/src/main/java/de/cuioss/tools/reflect/FieldWrapper.java b/src/main/java/de/cuioss/tools/reflect/FieldWrapper.java index 26c752e4..1d63d30a 100644 --- a/src/main/java/de/cuioss/tools/reflect/FieldWrapper.java +++ b/src/main/java/de/cuioss/tools/reflect/FieldWrapper.java @@ -89,6 +89,7 @@ public Optional readValue(Object source) { try { return Optional.ofNullable(field.get(source)); } catch (IllegalArgumentException | IllegalAccessException e) { + // cui-rewrite:disable CuiLogRecordPatternRecipe - Recipe bug: Cannot detect LogRecord through nested class LOGGER.warn(e, WARN.FIELD_READ_FAILED, field, initialAccessible, source); return Optional.empty(); } finally { diff --git a/src/test/java/de/cuioss/tools/io/FileSystemLoaderTest.java b/src/test/java/de/cuioss/tools/io/FileSystemLoaderTest.java index a27a49d8..b92fd48d 100644 --- a/src/test/java/de/cuioss/tools/io/FileSystemLoaderTest.java +++ b/src/test/java/de/cuioss/tools/io/FileSystemLoaderTest.java @@ -164,4 +164,21 @@ void shouldGetUrlForNonExistentFile() throws MalformedURLException { assertNotNull(url); assertEquals(Path.of(NOT_EXISTING_FILE_PATH).toUri().toURL().getPath(), url.getPath()); } + + @Test + void shouldHandleExternalPathWithComplexScenarios() { + // Test external path handling - this exercises the code path with canonical path resolution + // Even though we can't easily trigger IOException in getCanonicalPath(), this test ensures + // the external path resolution logic is executed + var externalPath = "external:/pom.xml"; + var result = FileSystemLoader.checkPathName(externalPath); + assertNotNull(result); + assertTrue(result.contains("pom.xml")); + + // Also test that we can create a loader with this path - file should exist after resolution + var loader = new FileSystemLoader(externalPath); + assertNotNull(loader); + // The file should be readable since external:/pom.xml resolves to ./pom.xml + assertTrue(loader.isReadable(), "External path should resolve to readable pom.xml"); + } } diff --git a/src/test/java/de/cuioss/tools/property/PropertyUtilTest.java b/src/test/java/de/cuioss/tools/property/PropertyUtilTest.java index 41d5d19b..33ec8c20 100644 --- a/src/test/java/de/cuioss/tools/property/PropertyUtilTest.java +++ b/src/test/java/de/cuioss/tools/property/PropertyUtilTest.java @@ -129,4 +129,31 @@ void shouldResolvePropertyType() { assertFalse(resolvePropertyType(BeanForTestingTypeResolving.class, "notThere").isPresent()); } + @Test + @SuppressWarnings("deprecation") + void shouldSupportDeprecatedWriteProperty() { + var underTest = new BeanWithReadWriteProperties(); + Integer number = 4; + + // Test that deprecated writeProperty returns the bean instance + Object result = writeProperty(underTest, ATTRIBUTE_READ_WRITE, number); + assertAll("Testing deprecated writeProperty", + () -> assertSame(underTest, result, "Should return the same bean instance for chaining"), + () -> assertEquals(number, readProperty(underTest, ATTRIBUTE_READ_WRITE), "Property value should be set correctly")); + + // Test with null value + Object nullResult = writeProperty(underTest, ATTRIBUTE_READ_WRITE, null); + assertAll("Testing deprecated writeProperty with null", + () -> assertSame(underTest, nullResult, "Should return the bean instance even with null value"), + () -> assertNull(readProperty(underTest, ATTRIBUTE_READ_WRITE), "Property value should be null")); + + // Test chaining multiple writes + Object chainResult = writeProperty( + writeProperty(underTest, ATTRIBUTE_READ_WRITE, 10), + ATTRIBUTE_READ_WRITE, 20); + assertAll("Testing method chaining", + () -> assertSame(underTest, chainResult, "Should return the bean for chaining"), + () -> assertEquals(20, readProperty(underTest, ATTRIBUTE_READ_WRITE), "Final value should be 20")); + } + }