diff --git a/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/QuarkusCxfProcessor.java b/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/QuarkusCxfProcessor.java index f57a92ec7..6e7eb92b6 100644 --- a/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/QuarkusCxfProcessor.java +++ b/extensions/core/deployment/src/main/java/io/quarkiverse/cxf/deployment/QuarkusCxfProcessor.java @@ -12,8 +12,10 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.Random; @@ -659,7 +661,7 @@ public InputSource resolveEntity(String publicId, String systemId) { private static class QuarkusCapture implements GeneratedClassClassLoaderCapture { private final ClassOutput classOutput; - private final Set generatedClasses = new LinkedHashSet<>(); + private final Map generatedClasses = new LinkedHashMap<>(); QuarkusCapture(ClassOutput classOutput) { this.classOutput = classOutput; @@ -668,12 +670,16 @@ private static class QuarkusCapture implements GeneratedClassClassLoaderCapture @Override public void capture(String name, byte[] bytes) { final String dotName = name.indexOf('.') >= 0 ? name : name.replace('/', '.'); - if (!generatedClasses.contains(dotName)) { - final String slashName = name.indexOf('/') >= 0 ? name : name.replace('.', '/'); + final String slashName = name.indexOf('/') >= 0 ? name : name.replace('.', '/'); + final byte[] oldVal = generatedClasses.get(dotName); + if (oldVal != null && !Arrays.equals(oldVal, bytes)) { + throw new IllegalStateException("Cannot overwrite an existing generated class file " + slashName + + " with a different content. Is there perhaps a naming clash among the methods of your service interfaces?"); + } else { classOutput.getSourceWriter(slashName); LOGGER.debugf("Generated class %s", dotName); classOutput.write(slashName, bytes); - generatedClasses.add(dotName); + generatedClasses.put(dotName, bytes); } } @@ -682,7 +688,7 @@ public int getGeneratedClassesCount() { } public String[] getGeneratedClasses() { - return generatedClasses.toArray(new String[0]); + return generatedClasses.keySet().toArray(new String[0]); } } diff --git a/extensions/core/deployment/src/test/java/io/quarkiverse/cxf/deployment/test/AsmNamingClashTest.java b/extensions/core/deployment/src/test/java/io/quarkiverse/cxf/deployment/test/AsmNamingClashTest.java new file mode 100644 index 000000000..e9237ac8a --- /dev/null +++ b/extensions/core/deployment/src/test/java/io/quarkiverse/cxf/deployment/test/AsmNamingClashTest.java @@ -0,0 +1,87 @@ +package io.quarkiverse.cxf.deployment.test; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; + +import jakarta.jws.WebMethod; +import jakarta.jws.WebService; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkiverse.cxf.annotation.CXFClient; +import io.quarkus.test.QuarkusUnitTest; + +/** + * A reproducer for https://github.com/quarkiverse/quarkus-cxf/issues/1326 + */ +public class AsmNamingClashTest { + + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest() + .withApplicationRoot(root -> root.addClasses(HelloServiceString.class, HelloServiceStringImpl.class)) + .overrideConfigKey("quarkus.cxf.endpoint.\"/helloString\".implementor", HelloServiceStringImpl.class.getName()) + .overrideConfigKey("quarkus.cxf.client.helloString.service-interface", HelloServiceString.class.getName()) + .overrideConfigKey("quarkus.cxf.client.helloString.client-endpoint-url", + "http://localhost:8081/services/helloString") + .overrideConfigKey("quarkus.cxf.endpoint.\"/helloInt\".implementor", HelloServiceIntImpl.class.getName()) + .overrideConfigKey("quarkus.cxf.client.helloInt.service-interface", HelloServiceInt.class.getName()) + .overrideConfigKey("quarkus.cxf.client.helloInt.client-endpoint-url", "http://localhost:8081/services/helloInt") + .assertException(t -> Assertions.assertThat(t).isInstanceOf(IllegalStateException.class) + .hasMessageContaining( + "Cannot overwrite an existing generated class file io/quarkiverse/cxf/deployment/test/jaxws_asm/Hello with a different content")); + + @CXFClient("helloString") + HelloServiceString helloString; + + @CXFClient("helloInt") + HelloServiceInt helloInt; + + @Test + void payloadLogged() throws IOException { + + Assertions.assertThat(helloString.hello("Joe")).isEqualTo("Hello Joe!"); + Assertions.assertThat(helloInt.hello(42)).isEqualTo("Hello 42!"); + + } + + @WebService(targetNamespace = "http://deployment.logging.features.cxf.quarkiverse.io/") + public interface HelloServiceString { + + @WebMethod + String hello(String text); + + } + + @WebService(targetNamespace = "http://deployment.logging.features.cxf.quarkiverse.io/") + public interface HelloServiceInt { + + @WebMethod + String hello(int i); + + } + + @WebService(serviceName = "HelloService") + public static class HelloServiceStringImpl implements HelloServiceString { + + @WebMethod + @Override + public String hello(String text) { + return "Hello " + text + "!"; + } + + } + + @WebService(serviceName = "HelloService") + public static class HelloServiceIntImpl implements HelloServiceInt { + + @WebMethod + @Override + public String hello(int text) { + return "Hello " + text + "!"; + } + + } +} diff --git a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/MtomAwtResource.java b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/MtomAwtResource.java index 4761c2cee..b11a60a95 100644 --- a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/MtomAwtResource.java +++ b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/MtomAwtResource.java @@ -19,6 +19,7 @@ import jakarta.ws.rs.core.Response; import io.quarkiverse.cxf.annotation.CXFClient; +import io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers.ImageServiceWithWrappers; @Path("/mtom-awt-rest") @ApplicationScoped diff --git a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageData.java b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageData.java similarity index 94% rename from integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageData.java rename to integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageData.java index 7b64ed636..4a385eecc 100644 --- a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageData.java +++ b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageData.java @@ -1,4 +1,4 @@ -package io.quarkiverse.cxf.it.ws.mtom.awt.server; +package io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers; import java.awt.Image; diff --git a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageResponse.java b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageResponse.java similarity index 92% rename from integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageResponse.java rename to integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageResponse.java index e101ebc21..ce9bc5264 100644 --- a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageResponse.java +++ b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageResponse.java @@ -1,4 +1,4 @@ -package io.quarkiverse.cxf.it.ws.mtom.awt.server; +package io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers; import java.awt.Image; @@ -33,4 +33,4 @@ public Image getReturn() { public void setReturn(Image data) { this._return = data; } -} \ No newline at end of file +} diff --git a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageServiceWithWrappers.java b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageServiceWithWrappers.java similarity index 80% rename from integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageServiceWithWrappers.java rename to integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageServiceWithWrappers.java index f9ce5b89e..8c495c232 100644 --- a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageServiceWithWrappers.java +++ b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageServiceWithWrappers.java @@ -1,4 +1,4 @@ -package io.quarkiverse.cxf.it.ws.mtom.awt.server; +package io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers; import java.awt.Image; @@ -16,12 +16,12 @@ public interface ImageServiceWithWrappers { public static final String NS = "https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/test/mtom-awt-with-wrappers"; @WebMethod - @ResponseWrapper(localName = "ImageResponse", targetNamespace = NS, className = "io.quarkiverse.cxf.it.ws.mtom.awt.server.ImageResponse") + @ResponseWrapper(localName = "ImageResponse", targetNamespace = NS, className = "io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers.ImageResponse") Image downloadImage( @WebParam(name = "name", targetNamespace = NS) String name); @WebMethod - @RequestWrapper(localName = "ImageData", targetNamespace = NS, className = "io.quarkiverse.cxf.it.ws.mtom.awt.server.ImageData") + @RequestWrapper(localName = "ImageData", targetNamespace = NS, className = "io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers.ImageData") String uploadImage( @WebParam(name = "data", targetNamespace = NS) Image data, @WebParam(name = "name", targetNamespace = NS) String name); diff --git a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageServiceWithWrappersImpl.java b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageServiceWithWrappersImpl.java similarity index 86% rename from integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageServiceWithWrappersImpl.java rename to integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageServiceWithWrappersImpl.java index c517150be..4e66cbfd6 100644 --- a/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/ImageServiceWithWrappersImpl.java +++ b/integration-tests/mtom-awt/src/main/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/wrappers/ImageServiceWithWrappersImpl.java @@ -1,4 +1,4 @@ -package io.quarkiverse.cxf.it.ws.mtom.awt.server; +package io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers; import java.awt.Image; import java.util.Map; @@ -6,7 +6,7 @@ import jakarta.jws.WebService; -@WebService(name = "ImageServiceWithWrappers", serviceName = "ImageServiceWithWrappers", endpointInterface = "io.quarkiverse.cxf.it.ws.mtom.awt.server.ImageServiceWithWrappers", targetNamespace = ImageServiceWithWrappers.NS) +@WebService(name = "ImageServiceWithWrappers", serviceName = "ImageServiceWithWrappers", endpointInterface = "io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers.ImageServiceWithWrappers", targetNamespace = ImageServiceWithWrappers.NS) public class ImageServiceWithWrappersImpl implements ImageServiceWithWrappers { public static final String MSG_SUCCESS = "Upload Successful"; diff --git a/integration-tests/mtom-awt/src/main/resources/application.properties b/integration-tests/mtom-awt/src/main/resources/application.properties index f6558b0c4..a63030a5e 100644 --- a/integration-tests/mtom-awt/src/main/resources/application.properties +++ b/integration-tests/mtom-awt/src/main/resources/application.properties @@ -9,12 +9,12 @@ quarkus.cxf.client.imageServiceClient.endpoint-namespace = "https://quarkiverse. quarkus.cxf.client.imageServiceClient.endpoint-name = ImageService quarkus.cxf.client.imageServiceClient.native.runtime-initialized = true -quarkus.cxf.endpoint."/mtom-aws-with-wrappers".implementor = io.quarkiverse.cxf.it.ws.mtom.awt.server.ImageServiceWithWrappersImpl +quarkus.cxf.endpoint."/mtom-aws-with-wrappers".implementor = io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers.ImageServiceWithWrappersImpl quarkus.cxf.endpoint."/mtom-aws-with-wrappers".features = org.apache.cxf.ext.logging.LoggingFeature quarkus.cxf.endpoint."/mtom-aws-with-wrappers".handlers = io.quarkiverse.cxf.it.ws.mtom.awt.server.MtomEnforcer quarkus.cxf.client.imageServiceClientWithWrappers.client-endpoint-url = http://localhost:${quarkus.http.test-port}/soap/mtom-aws-with-wrappers/ImageServiceWithWrappers -quarkus.cxf.client.imageServiceClientWithWrappers.service-interface = io.quarkiverse.cxf.it.ws.mtom.awt.server.ImageServiceWithWrappers +quarkus.cxf.client.imageServiceClientWithWrappers.service-interface = io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers.ImageServiceWithWrappers quarkus.cxf.client.imageServiceClientWithWrappers.endpoint-namespace = "https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/test/mtom-awt-with-wrappers" quarkus.cxf.client.imageServiceClientWithWrappers.endpoint-name = ImageServiceWithWrappers quarkus.cxf.client.imageServiceClientWithWrappers.native.runtime-initialized = true \ No newline at end of file diff --git a/integration-tests/mtom-awt/src/test/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/MtomAwtTest.java b/integration-tests/mtom-awt/src/test/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/MtomAwtTest.java index d90ec16bf..731774c59 100644 --- a/integration-tests/mtom-awt/src/test/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/MtomAwtTest.java +++ b/integration-tests/mtom-awt/src/test/java/io/quarkiverse/cxf/it/ws/mtom/awt/server/MtomAwtTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test; import io.quarkiverse.cxf.it.ws.mtom.awt.server.MtomAwtResource.ClientKey; +import io.quarkiverse.cxf.it.ws.mtom.awt.server.wrappers.ImageServiceWithWrappersImpl; import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.restassured.http.ContentType;