From f6cb9d2eaeaf6b3017f29cb8b1c6f91baa8ee387 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Thu, 26 Jun 2025 11:54:54 +0200 Subject: [PATCH] blindspot on RemoveUnusedImportsStep --- .../java/RemoveUnusedImportsStepTest.java | 14 ++- .../removeunusedimports/Issue2532Post.test | 84 ++++++++++++++++++ .../removeunusedimports/Issue2532Pre.test | 86 +++++++++++++++++++ 3 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 testlib/src/main/resources/java/removeunusedimports/Issue2532Post.test create mode 100644 testlib/src/main/resources/java/removeunusedimports/Issue2532Pre.test diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java index 50853ba914..cb0ebea6f8 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ class RemoveUnusedImportsStepTest extends MavenIntegrationHarness { @Test - void testRemoveUnusedInports() throws Exception { + void testRemoveUnusedImports() throws Exception { writePomWithJavaSteps(""); String path = "src/main/java/test.java"; @@ -30,4 +30,14 @@ void testRemoveUnusedInports() throws Exception { mavenRunner().withArguments("spotless:apply").runNoError(); assertFile(path).sameAsResource("java/removeunusedimports/JavaCodeWithPackageFormatted.test"); } + + @Test + void testIssue2532() throws Exception { + writePomWithJavaSteps(""); + + String path = "src/main/java/test.java"; + setFile(path).toResource("java/removeunusedimports/Issue2532Pre.test"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile(path).sameAsResource("java/removeunusedimports/Issue2532Post.test"); + } } diff --git a/testlib/src/main/resources/java/removeunusedimports/Issue2532Post.test b/testlib/src/main/resources/java/removeunusedimports/Issue2532Post.test new file mode 100644 index 0000000000..5ebb1266c4 --- /dev/null +++ b/testlib/src/main/resources/java/removeunusedimports/Issue2532Post.test @@ -0,0 +1,84 @@ +package io.quarkus.test; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Properties; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.jboss.shrinkwrap.api.Node; +import org.jboss.shrinkwrap.api.asset.Asset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.exporter.ZipExporter; +import org.jboss.shrinkwrap.api.spec.JavaArchive; + +final class ExportUtil { + + static final String APPLICATION_PROPERTIES = "application.properties"; + + private ExportUtil() { + } + + static void exportToQuarkusDeploymentPath(JavaArchive archive) throws IOException { + String exportPath = System.getProperty("quarkus.deploymentExportPath"); + if (exportPath == null) { + return; + } + File exportDir = new File(exportPath); + if (exportDir.exists()) { + if (!exportDir.isDirectory()) { + throw new IllegalStateException("Export path is not a directory: " + exportPath); + } + try (Stream stream = Files.walk(exportDir.toPath())) { + stream.sorted(Comparator.reverseOrder()).map(Path::toFile) + .forEach(File::delete); + } + } else if (!exportDir.mkdirs()) { + throw new IllegalStateException("Export path could not be created: " + exportPath); + } + File exportFile = new File(exportDir, archive.getName()); + archive.as(ZipExporter.class).exportTo(exportFile); + } + + static void mergeCustomApplicationProperties(JavaArchive archive, Properties customApplicationProperties) + throws IOException { + Node applicationProperties = archive.get(APPLICATION_PROPERTIES); + if (applicationProperties != null) { + // Merge the existing "application.properties" asset and overriden config properties + // Overriden properties take precedence + Properties mergedProperties = new Properties(); + Asset asset = applicationProperties.getAsset(); + if (asset instanceof StringAsset strAsset) { + mergedProperties.load(new StringReader(strAsset.getSource())); + } else { + try (InputStream in = asset.openStream()) { + mergedProperties.load(in); + } + } + customApplicationProperties.forEach(mergedProperties::put); + + if (Boolean.parseBoolean(System.getProperty("quarkus.test.log-merged-properties"))) { + System.out.println("Merged config properties:\n" + + mergedProperties.keySet().stream().map(Object::toString).collect(Collectors.joining("\n"))); + } else { + System.out.println( + "NOTE: overrideConfigKey() and application.properties were merged; use quarkus.test.log-merged-properties=true to list the specific values"); + } + deleteApplicationProperties(archive); + archive.add(new PropertiesAsset(mergedProperties), APPLICATION_PROPERTIES); + } else { + archive.add(new PropertiesAsset(customApplicationProperties), APPLICATION_PROPERTIES); + } + } + + static void deleteApplicationProperties(JavaArchive archive) { + // MemoryMapArchiveBase#addAsset(ArchivePath,Asset) does not overwrite the existing node correctly + // https://github.com/shrinkwrap/shrinkwrap/issues/179 + archive.delete(APPLICATION_PROPERTIES); + } +} diff --git a/testlib/src/main/resources/java/removeunusedimports/Issue2532Pre.test b/testlib/src/main/resources/java/removeunusedimports/Issue2532Pre.test new file mode 100644 index 0000000000..4f9f0039a1 --- /dev/null +++ b/testlib/src/main/resources/java/removeunusedimports/Issue2532Pre.test @@ -0,0 +1,86 @@ +package io.quarkus.test; + +import static io.quarkus.test.ExportUtil.APPLICATION_PROPERTIES; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Properties; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.jboss.shrinkwrap.api.Node; +import org.jboss.shrinkwrap.api.asset.Asset; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.exporter.ZipExporter; +import org.jboss.shrinkwrap.api.spec.JavaArchive; + +final class ExportUtil { + + static final String APPLICATION_PROPERTIES = "application.properties"; + + private ExportUtil() { + } + + static void exportToQuarkusDeploymentPath(JavaArchive archive) throws IOException { + String exportPath = System.getProperty("quarkus.deploymentExportPath"); + if (exportPath == null) { + return; + } + File exportDir = new File(exportPath); + if (exportDir.exists()) { + if (!exportDir.isDirectory()) { + throw new IllegalStateException("Export path is not a directory: " + exportPath); + } + try (Stream stream = Files.walk(exportDir.toPath())) { + stream.sorted(Comparator.reverseOrder()).map(Path::toFile) + .forEach(File::delete); + } + } else if (!exportDir.mkdirs()) { + throw new IllegalStateException("Export path could not be created: " + exportPath); + } + File exportFile = new File(exportDir, archive.getName()); + archive.as(ZipExporter.class).exportTo(exportFile); + } + + static void mergeCustomApplicationProperties(JavaArchive archive, Properties customApplicationProperties) + throws IOException { + Node applicationProperties = archive.get(APPLICATION_PROPERTIES); + if (applicationProperties != null) { + // Merge the existing "application.properties" asset and overriden config properties + // Overriden properties take precedence + Properties mergedProperties = new Properties(); + Asset asset = applicationProperties.getAsset(); + if (asset instanceof StringAsset strAsset) { + mergedProperties.load(new StringReader(strAsset.getSource())); + } else { + try (InputStream in = asset.openStream()) { + mergedProperties.load(in); + } + } + customApplicationProperties.forEach(mergedProperties::put); + + if (Boolean.parseBoolean(System.getProperty("quarkus.test.log-merged-properties"))) { + System.out.println("Merged config properties:\n" + + mergedProperties.keySet().stream().map(Object::toString).collect(Collectors.joining("\n"))); + } else { + System.out.println( + "NOTE: overrideConfigKey() and application.properties were merged; use quarkus.test.log-merged-properties=true to list the specific values"); + } + deleteApplicationProperties(archive); + archive.add(new PropertiesAsset(mergedProperties), APPLICATION_PROPERTIES); + } else { + archive.add(new PropertiesAsset(customApplicationProperties), APPLICATION_PROPERTIES); + } + } + + static void deleteApplicationProperties(JavaArchive archive) { + // MemoryMapArchiveBase#addAsset(ArchivePath,Asset) does not overwrite the existing node correctly + // https://github.com/shrinkwrap/shrinkwrap/issues/179 + archive.delete(APPLICATION_PROPERTIES); + } +}