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");
+ }
+
+}