This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/main by this push:
     new 3d4d21ea84 CXF-9003: Name clash when two SEIs have a same name method 
in the same (#2237)
3d4d21ea84 is described below

commit 3d4d21ea84fc686b19f1978acc63f10ecb29e089
Author: Peter Palaga <[email protected]>
AuthorDate: Mon Feb 3 15:37:42 2025 +0100

    CXF-9003: Name clash when two SEIs have a same name method in the same 
(#2237)
    
    Java package
---
 .../apache/cxf/jaxws/WrapperClassGenerator.java    |  22 +--
 .../apache/cxf/jaxws/spi/WrapperClassLoader.java   |  14 +-
 .../jaxws/spi/WrapperClassNamingConvention.java    | 148 ++++++++++++++++++++
 .../main/resources/META-INF/cxf/bus-extensions.txt |   3 +-
 .../cxf/jaxws/spi/WrapperClassLoaderTest.java      |  88 ++++++++++--
 .../org/apache/cxf/systest/jaxws/CXF9003Test.java  | 155 +++++++++++++++++++++
 6 files changed, 403 insertions(+), 27 deletions(-)

diff --git 
a/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/WrapperClassGenerator.java
 
b/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/WrapperClassGenerator.java
index c47338e4e5..ec36e6af0d 100644
--- 
a/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/WrapperClassGenerator.java
+++ 
b/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/WrapperClassGenerator.java
@@ -47,10 +47,11 @@ import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.common.spi.ClassGeneratorClassLoader;
 import org.apache.cxf.common.util.ASMHelper;
 import org.apache.cxf.common.util.OpcodesProxy;
-import org.apache.cxf.common.util.PackageUtils;
 import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.helpers.JavaUtils;
 import org.apache.cxf.jaxws.spi.WrapperClassCreator;
+import org.apache.cxf.jaxws.spi.WrapperClassNamingConvention;
+import 
org.apache.cxf.jaxws.spi.WrapperClassNamingConvention.DefaultWrapperClassNamingConvention;
 import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
 import org.apache.cxf.service.model.InterfaceInfo;
 import org.apache.cxf.service.model.MessageInfo;
@@ -60,19 +61,22 @@ import org.apache.cxf.service.model.SchemaInfo;
 import org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean;
 
 public final class WrapperClassGenerator extends ClassGeneratorClassLoader 
implements WrapperClassCreator {
-    public static final String DEFAULT_PACKAGE_NAME = "defaultnamespace";
+    /**
+     * Kept for backwards compatibility only
+     *
+     * @deprecated use {@link 
WrapperClassNamingConvention#DEFAULT_PACKAGE_NAME} instead
+     */
+    @Deprecated
+    public static final String DEFAULT_PACKAGE_NAME = 
DefaultWrapperClassNamingConvention.DEFAULT_PACKAGE_NAME;
 
     private static final Logger LOG = 
LogUtils.getL7dLogger(WrapperClassGenerator.class);
     private final ASMHelper helper;
+    private final WrapperClassNamingConvention wrapperClassNaming;
 
     public WrapperClassGenerator(Bus bus) {
         super(bus);
-        helper = bus.getExtension(ASMHelper.class);
-    }
-
-    private String getPackageName(Method method) {
-        String pkg = PackageUtils.getPackageName(method.getDeclaringClass());
-        return pkg.length() == 0 ? DEFAULT_PACKAGE_NAME : pkg;
+        this.helper = bus.getExtension(ASMHelper.class);
+        this.wrapperClassNaming = 
bus.getExtension(WrapperClassNamingConvention.class);
     }
 
     private Annotation[] getMethodParameterAnnotations(final MessagePartInfo 
mpi) {
@@ -169,7 +173,7 @@ public final class WrapperClassGenerator extends 
ClassGeneratorClassLoader imple
         QName wrapperElement = messageInfo.getName();
         boolean anonymous = factory.getAnonymousWrapperTypes();
 
-        String pkg = getPackageName(method) + ".jaxws_asm" + (anonymous ? 
"_an" : "");
+        String pkg = 
wrapperClassNaming.getWrapperClassPackageName(method.getDeclaringClass(), 
anonymous);
         String className = pkg + "."
             + StringUtils.capitalize(op.getName().getLocalPart());
         if (!isRequest) {
diff --git 
a/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spi/WrapperClassLoader.java
 
b/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spi/WrapperClassLoader.java
index dfaf195996..9a993272ac 100644
--- 
a/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spi/WrapperClassLoader.java
+++ 
b/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spi/WrapperClassLoader.java
@@ -24,9 +24,7 @@ import java.util.Set;
 
 import org.apache.cxf.Bus;
 import org.apache.cxf.common.spi.GeneratedClassClassLoader;
-import org.apache.cxf.common.util.PackageUtils;
 import org.apache.cxf.common.util.StringUtils;
-import org.apache.cxf.jaxws.WrapperClassGenerator;
 import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
 import org.apache.cxf.service.model.InterfaceInfo;
 import org.apache.cxf.service.model.MessageInfo;
@@ -41,8 +39,11 @@ import 
org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean;
  * @author olivier dufour
  */
 public class WrapperClassLoader extends GeneratedClassClassLoader implements 
WrapperClassCreator {
+    private final WrapperClassNamingConvention wrapperClassNaming;
+
     public WrapperClassLoader(Bus bus) {
         super(bus);
+        wrapperClassNaming = 
bus.getExtension(WrapperClassNamingConvention.class);
     }
 
     @Override
@@ -87,9 +88,10 @@ public class WrapperClassLoader extends 
GeneratedClassClassLoader implements Wra
                                     Method method,
                                     boolean isRequest,
                                     JaxWsServiceFactoryBean factory) {
-        boolean anonymous = factory.getAnonymousWrapperTypes();
 
-        String pkg = getPackageName(method) + ".jaxws_asm" + (anonymous ? 
"_an" : "");
+        String pkg = wrapperClassNaming.getWrapperClassPackageName(
+                method.getDeclaringClass(),
+                factory.getAnonymousWrapperTypes());
         String className = pkg + "."
                 + StringUtils.capitalize(op.getName().getLocalPart());
         if (!isRequest) {
@@ -112,8 +114,4 @@ public class WrapperClassLoader extends 
GeneratedClassClassLoader implements Wra
         //throw new ClassNotFoundException(origClassName);
         return null;
     }
-    private String getPackageName(Method method) {
-        String pkg = PackageUtils.getPackageName(method.getDeclaringClass());
-        return pkg.length() == 0 ? WrapperClassGenerator.DEFAULT_PACKAGE_NAME 
: pkg;
-    }
 }
diff --git 
a/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spi/WrapperClassNamingConvention.java
 
b/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spi/WrapperClassNamingConvention.java
new file mode 100644
index 0000000000..ae1b544c54
--- /dev/null
+++ 
b/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spi/WrapperClassNamingConvention.java
@@ -0,0 +1,148 @@
+/**
+ * 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
+ *
+ * http://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.cxf.jaxws.spi;
+
+import java.util.Locale;
+import java.util.regex.Pattern;
+
+import org.apache.cxf.common.util.PackageUtils;
+/**
+ * Provides names for storing generated wrapper classes.
+ *
+ * @since 4.1.1
+ */
+public interface WrapperClassNamingConvention {
+
+    /**
+     * Returns a package name unique for the given {@code sei} and {@code 
anonymous}
+     * parameters suitable for storing generated wrapper classes.
+     *
+     * @param sei the service endpoint interface for which the package name 
should be created
+     * @param anonymous whether the generated wrapper types are anonymous
+     * @return a valid Java package name
+     */
+    String getWrapperClassPackageName(Class<?> sei, boolean anonymous);
+
+    /**
+     * Default naming scheme since CXF 4.2.0.
+     * <p>
+     * The package name returned by {@link #getWrapperClassPackageName(Class, 
boolean)} are unique
+     * per given {@code sei}.
+     * <p>
+     * Examples:
+     * <table>
+     * <tr>
+     * <th>SEI</th><th>anonymous</th>
+     * <th>{@code getWrapperClassPackageName()} return value</th>
+     * </tr>
+     * <tr>
+     * <td>{@code org.example.Service}</td>
+     * <td>{@code false}</td>
+     * <td>{@code org.example.jaxws_asm.service}</td>
+     * </tr>
+     * <tr>
+     * <td>{@code org.example.OuterClass$Service}</td>
+     * <td>{@code false}</td>
+     * <td>{@code org.example.jaxws_asm.outerclass_service}</td>
+     * </tr>
+     * <tr>
+     * <td>{@code org.example.Service}</td>
+     * <td>{@code true}</td>
+     * <td>{@code org.example.jaxws_asm_an.service}</td>
+     * </tr>
+     * </table>
+     *
+     * @since 4.1.1
+     */
+    class DefaultWrapperClassNamingConvention implements 
WrapperClassNamingConvention {
+        public static final String DEFAULT_PACKAGE_NAME = "defaultnamespace";
+        private static final Pattern JAVA_PACKAGE_NAME_SANITIZER_PATTERN = 
Pattern.compile("[^a-zA-Z0-9_]");
+
+        @Override
+        public String getWrapperClassPackageName(Class<?> sei, boolean 
anonymous) {
+            final String className = sei.getName();
+            final int start = className.startsWith("[L") ? 2 : 0;
+            final int end = className.lastIndexOf('.');
+            final String pkg;
+            final String cl;
+            if (end >= 0) {
+                pkg = className.substring(start, end);
+                cl = className.substring(end + 1);
+            } else {
+                pkg = DefaultWrapperClassNamingConvention.DEFAULT_PACKAGE_NAME;
+                cl = className;
+            }
+
+            return pkg
+                    + (anonymous ? ".jaxws_asm_an." : ".jaxws_asm.")
+                    + 
JAVA_PACKAGE_NAME_SANITIZER_PATTERN.matcher(cl).replaceAll("_").toLowerCase(Locale.ROOT);
+        }
+
+    }
+
+    /**
+     * An implementation restoring the behavior of CXF before version 4.2.0.
+     * <p>
+     * Unlike with {@link DefaultWrapperClassNamingConvention}, this 
implementation's
+     * {@link #getWrapperClassPackageName(Class, boolean)} takes only package 
name
+     * of the given {@code sei} into account.
+     * Therefore naming clashes may occur if two SEIs are in the same package
+     * and both of them have a method with the same name but possibly 
different signature.
+     * <p>
+     * Examples:
+     * <table>
+     * <tr>
+     * <th>SEI</th>
+     * <th>anonymous</th>
+     * <th>{@code getWrapperClassPackageName()} return value</th>
+     * </tr>
+     * <tr>
+     * <td>{@code org.example.Service}</td>
+     * <td>{@code false}</td>
+     * <td>{@code org.example.jaxws_asm}</td>
+     * </tr>
+     * <tr>
+     * <td>{@code org.example.OuterClass$Service}</td>
+     * <td>{@code false}</td>
+     * <td>{@code org.example.jaxws_asm}</td>
+     * </tr>
+     * <tr>
+     * <td>{@code org.example.Service}</td>
+     * <td>{@code true}</td>
+     * <td>{@code org.example.jaxws_asm_an}</td>
+     * </tr>
+     * </table>
+     *
+     * @since 4.1.1
+     */
+    class LegacyWrapperClassNamingConvention implements 
WrapperClassNamingConvention {
+
+        @Override
+        public String getWrapperClassPackageName(Class<?> sei, boolean 
anonymous) {
+            return getPackageName(sei) + ".jaxws_asm" + (anonymous ? "_an" : 
"");
+        }
+
+        private String getPackageName(Class<?> sei) {
+            String pkg = PackageUtils.getPackageName(sei);
+            return pkg.length() == 0 ? 
DefaultWrapperClassNamingConvention.DEFAULT_PACKAGE_NAME : pkg;
+        }
+
+    }
+
+}
diff --git 
a/rt/frontend/jaxws/src/main/resources/META-INF/cxf/bus-extensions.txt 
b/rt/frontend/jaxws/src/main/resources/META-INF/cxf/bus-extensions.txt
index ea4dc9d2bc..f91f28cf0f 100644
--- a/rt/frontend/jaxws/src/main/resources/META-INF/cxf/bus-extensions.txt
+++ b/rt/frontend/jaxws/src/main/resources/META-INF/cxf/bus-extensions.txt
@@ -1,2 +1,3 @@
 org.apache.cxf.jaxws.context.WebServiceContextResourceResolver::true
-org.apache.cxf.jaxws.spi.WrapperClassCreatorProxyService:org.apache.cxf.jaxws.spi.WrapperClassCreator:true
\ No newline at end of file
+org.apache.cxf.jaxws.spi.WrapperClassCreatorProxyService:org.apache.cxf.jaxws.spi.WrapperClassCreator:true
+org.apache.cxf.jaxws.spi.WrapperClassNamingConvention$DefaultWrapperClassNamingConvention:org.apache.cxf.jaxws.spi.WrapperClassNamingConvention:true
diff --git 
a/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/spi/WrapperClassLoaderTest.java
 
b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/spi/WrapperClassLoaderTest.java
index 16ba943bf2..c2a2a4083e 100644
--- 
a/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/spi/WrapperClassLoaderTest.java
+++ 
b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/spi/WrapperClassLoaderTest.java
@@ -21,8 +21,12 @@ package org.apache.cxf.jaxws.spi;
 
 import java.lang.reflect.Method;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.xml.namespace.QName;
 
@@ -31,6 +35,8 @@ import org.apache.cxf.binding.soap.SoapBindingConstants;
 import org.apache.cxf.binding.soap.SoapBindingFactory;
 import org.apache.cxf.binding.soap.SoapTransportFactory;
 import org.apache.cxf.common.spi.GeneratedClassClassLoader;
+import org.apache.cxf.common.spi.GeneratedClassClassLoaderCapture;
+import org.apache.cxf.jaxws.WrapperClassGenerator;
 import org.apache.cxf.jaxws.service.SayHi;
 import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
 import org.apache.cxf.service.model.DescriptionInfo;
@@ -59,10 +65,8 @@ public class WrapperClassLoaderTest extends AbstractCXFTest {
     public void setUpBus() throws Exception {
         super.setUpBus();
 
-        GeneratedClassClassLoader.TypeHelperClassLoader mockClassLoader =
-                
Mockito.mock(GeneratedClassClassLoader.TypeHelperClassLoader.class);
-        
doReturn(SayHi.class).when(mockClassLoader).loadClass("org.apache.cxf.jaxws.service.jaxws_asm.SayHi");
-        bus.setExtension(mockClassLoader, 
GeneratedClassClassLoader.TypeHelperClassLoader.class);
+        Capture c = new Capture();
+        bus.setExtension(c, GeneratedClassClassLoaderCapture.class);
 
         SoapBindingFactory bindingFactory = new SoapBindingFactory();
         bindingFactory.setBus(bus);
@@ -115,8 +119,31 @@ public class WrapperClassLoaderTest extends 
AbstractCXFTest {
     }
 
     @org.junit.Test
-    public void testWrapperClassLoaderWithWrappedOperations() throws Exception 
{
-        WrapperClassLoader wrapperClassLoader = new WrapperClassLoader(bus);
+    public void 
testWrapperClassLoaderWithWrappedOperationsAndDefaultConvention() throws 
Exception {
+        final List<String> loadedClassNames = 
testWrapperClassLoaderWithNamingConvention(
+                new 
WrapperClassNamingConvention.DefaultWrapperClassNamingConvention());
+        assertEquals(
+                List.of(
+                        "org.apache.cxf.jaxws.service.jaxws_asm.sayhi.SayHi",
+                        
"org.apache.cxf.jaxws.service.jaxws_asm.sayhi.SayHiResponse"),
+                loadedClassNames);
+    }
+
+    @org.junit.Test
+    public void 
testWrapperClassLoaderWithWrappedOperationsAndLegacyConvention() throws 
Exception {
+        final List<String> loadedClassNames = 
testWrapperClassLoaderWithNamingConvention(
+                new 
WrapperClassNamingConvention.LegacyWrapperClassNamingConvention());
+        assertEquals(
+                List.of(
+                        "org.apache.cxf.jaxws.service.jaxws_asm.SayHi",
+                        
"org.apache.cxf.jaxws.service.jaxws_asm.SayHiResponse"),
+                loadedClassNames);
+    }
+
+    private List<String> 
testWrapperClassLoaderWithNamingConvention(WrapperClassNamingConvention 
convention)
+            throws Exception {
+        bus.setExtension(convention, WrapperClassNamingConvention.class);
+        WrapperClassGenerator wrapperClassGenerator = new 
WrapperClassGenerator(bus);
         JaxWsServiceFactoryBean factory = new JaxWsServiceFactoryBean();
 
         QName serviceName = new QName(
@@ -153,10 +180,53 @@ public class WrapperClassLoaderTest extends 
AbstractCXFTest {
         outputInfo.addMessagePart(sayHi);
         operationInfo.setOutput("sayHi", outputInfo);
 
-        Set<Class<?>> result = wrapperClassLoader.generate(factory, 
interfaceInfo, false);
-
         //Both Input and Output Messages will be found on Classpath
         //org.apache.cxf.jaxws.service.jaxws_asm.SayHi
-        assertEquals(2, result.size());
+        Set<Class<?>> generatedClasses = 
wrapperClassGenerator.generate(factory, interfaceInfo, false);
+        assertEquals(2, generatedClasses.size());
+
+
+        operationInfo.getInput().getFirstMessagePart().setTypeClass(null);
+        operationInfo.getOutput().getFirstMessagePart().setTypeClass(null);
+
+        WrapperClassLoader wrapperClassLoader = new WrapperClassLoader(bus);
+        GeneratedClassClassLoader.TypeHelperClassLoader cl = 
wrapperClassLoader.getClassLoader();
+        Capture c = 
(Capture)bus.getExtension(GeneratedClassClassLoaderCapture.class);
+        c.restore(cl);
+
+        Set<Class<?>> loadedClasses = wrapperClassLoader.generate(factory, 
interfaceInfo, false);
+        assertEquals(2, loadedClasses.size());
+
+        // The class names must match, but the classes themselves are 
different because they were loaded
+        // using different class loaders
+        final List<String> generatedClassNames = generatedClasses.stream()
+                .map(Class::getName)
+                .collect(Collectors.toList());
+        final List<String> loadedClassNames = loadedClasses.stream()
+                .map(Class::getName)
+                .collect(Collectors.toList());
+        assertEquals(
+                generatedClassNames,
+                loadedClassNames);
+        return loadedClassNames;
     }
+
+    static class Capture implements GeneratedClassClassLoaderCapture {
+
+        private final Map<String, byte[]> sources = new HashMap<>();
+
+        public void capture(String className, byte[] bytes) {
+            if (sources.containsKey(className)) {
+                throw new IllegalStateException("Class " + className + " 
defined twice");
+            }
+            sources.put(className, bytes);
+        }
+
+        public void 
restore(org.apache.cxf.common.spi.GeneratedClassClassLoader.TypeHelperClassLoader
 cl) {
+            for  (Map.Entry<String, byte[]> cls : sources.entrySet()) {
+                cl.defineClass(cls.getKey(), cls.getValue());
+            }
+        }
+    }
+
 }
diff --git 
a/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/CXF9003Test.java 
b/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/CXF9003Test.java
new file mode 100644
index 0000000000..907c43ea2c
--- /dev/null
+++ b/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/CXF9003Test.java
@@ -0,0 +1,155 @@
+/**
+ * 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
+ *
+ * http://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.cxf.systest.jaxws;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import jakarta.jws.WebMethod;
+import jakarta.jws.WebService;
+import jakarta.xml.ws.Endpoint;
+import jakarta.xml.ws.Service;
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.common.spi.GeneratedClassClassLoaderCapture;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.apache.cxf.testutil.common.AbstractClientServerTestBase;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class CXF9003Test extends AbstractClientServerTestBase {
+    static final String PORT = allocatePort(Server9003.class);
+
+    @WebService(targetNamespace = "urn:hello")
+    interface Hello1Service {
+        @WebMethod
+        String hello(String name);
+    }
+
+    @WebService(targetNamespace = "urn:hello")
+    public static class Hello1ServiceImpl implements Hello1Service {
+        @Override
+        public String hello(String person) {
+            return "Hello " + person;
+        }
+    }
+
+    @WebService(targetNamespace = "urn:hello")
+    interface Hello2Service {
+        @WebMethod
+        String hello(Name name);
+    }
+
+    @WebService(targetNamespace = "urn:hello")
+    public static class Hello2ServiceImpl implements Hello2Service {
+        @Override
+        public String hello(Name person) {
+            return "Hello " + person.getName();
+        }
+    }
+    public static class Name {
+        private String name;
+
+        public Name() {
+
+        }
+        public Name(String name) {
+            super();
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    static class Capture implements GeneratedClassClassLoaderCapture {
+
+        private final Map<String, byte[]> sources = new HashMap<>();
+
+        public void capture(String className, byte[] bytes) {
+            if (sources.containsKey(className)) {
+                throw new IllegalStateException("Class " + className + " 
defined twice");
+            }
+            sources.put(className, bytes);
+        }
+    }
+
+
+    public static class Server9003 extends AbstractBusTestServerBase {
+        protected void run() {
+            Object implementor = new Hello1ServiceImpl();
+            String address = "http://localhost:"; + PORT + "/hello1/service";
+            Endpoint.publish(address, implementor);
+
+            Object proxyImpl = new Hello2ServiceImpl();
+            String address2 = "http://localhost:"; + PORT + "/hello2/service";
+            Endpoint.publish(address2, proxyImpl);
+        }
+
+        public static void main(String[] args) {
+            try {
+                Server9003 s = new Server9003();
+                s.start();
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                System.exit(-1);
+            } finally {
+                System.out.println("done!");
+            }
+        }
+    }
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        Bus bus = BusFactory.getDefaultBus();
+        Capture c = new Capture();
+        bus.setExtension(c, GeneratedClassClassLoaderCapture.class);
+        assertTrue("server did not launch correctly", 
launchServer(Server9003.class, true));
+    }
+
+    @Test
+    public void generatedNamingClash() throws Exception {
+
+        QName serviceName1 = new QName("urn:hello", 
"Hello1ServiceImplService");
+        URL wsdlURL1 = new URL("http://localhost:"; + PORT + 
"/hello1/service?wsdl");
+        Service service1 = Service.create(wsdlURL1, serviceName1);
+        Hello1Service helloService1 = service1.getPort(Hello1Service.class);
+
+        QName serviceName2 = new QName("urn:hello", 
"Hello2ServiceImplService");
+        URL wsdlURL2 = new URL("http://localhost:"; + PORT + 
"/hello2/service?wsdl");
+        Service service2 = Service.create(wsdlURL2, serviceName2);
+        Hello2Service helloService2 = service2.getPort(Hello2Service.class);
+
+        assertEquals(helloService1.hello("Dolly"), "Hello Dolly");
+        assertEquals(helloService2.hello(new Name("Joe")), "Hello Joe");
+    }
+
+}

Reply via email to