An operation with name '' already exists in this service

Here is a tip on how to avoid this type of exception with JAXWS but before let’s try to understand why your Service construciton fails…

This exception occurs when your service definition (the Java interface in our case) have some duplicates methods without the same number of parameters (ie method overloading). This exception is totally normal since it is quite logic that the resulting Web Service can only have unique operation names :

  • Check a WSDL file. Did you ever see the same operation X times?
  • The Web Service Engine generally tries to get the operation context from the operation name. Then it will unmarshall the parameters (it will not have a look to the operation parameters to choose the operation like it should be done in the Java Runtime).

Here is a service definition sample which will be used in this article :

package com.googlecode.chamerling.blog.jaxws.duplicate;

/**
 * @author Christophe HAMERLING
 *
 */
public interface Service {

	void foo();

	void foo(String bar);
}

So let’s implement this interface :

package com.googlecode.chamerling.blog.jaxws.duplicate;

import javax.jws.WebService;

/**
 * @author Christophe HAMERLING
 *
 */
@WebService
public class ServiceKo implements Service {

	public void foo() {
	}

	public void foo(String bar) {
	}
}

Let’s use the JaxWsServerFactoryBean CXF factory (other WS stacks should throw the same exception…) to expose this service :

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

/**
 * @author Christophe HAMERLING
 */
public class App {

	private static final String URL = "http://localhost:9999/chamerling/services/";

	public static void main(String[] args) {
		JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
		Service space = new ServiceKo();
		svrFactory.setAddress(URL + "ServiceKO");
		svrFactory.setServiceBean(space);

		org.apache.cxf.endpoint.Server service = svrFactory.create();

		System.out.println("Service is available at "
				+ service.getEndpoint().getEndpointInfo().getAddress());

	}
}

You should have a beautiful stack trace :

java.lang.IllegalArgumentException: An operation with name [{http://duplicate.jaxws.blog.chamerling.googlecode.com/}foo] already exists in this service
	at org.apache.cxf.service.model.InterfaceInfo.addOperation(InterfaceInfo.java:71)
	at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.createOperation(ReflectionServiceFactoryBean.java:774)
	at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.createOperation(JaxWsServiceFactoryBean.java:484)
	at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.createInterface(ReflectionServiceFactoryBean.java:766)
	at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.buildServiceFromClass(ReflectionServiceFactoryBean.java:361)
	at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.buildServiceFromClass(JaxWsServiceFactoryBean.java:525)
	at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.initializeServiceModel(ReflectionServiceFactoryBean.java:422)
	at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.create(ReflectionServiceFactoryBean.java:190)
	at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.create(JaxWsServiceFactoryBean.java:164)
	at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:100)
	at org.apache.cxf.frontend.ServerFactoryBean.create(ServerFactoryBean.java:117)
	at org.apache.cxf.jaxws.JaxWsServerFactoryBean.create(JaxWsServerFactoryBean.java:168)
	at com.googlecode.chamerling.blog.jaxws.duplicate.AppTest.testKoService(AppTest.java:37)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:585)
	at junit.framework.TestCase.runTest(TestCase.java:154)
	at junit.framework.TestCase.runBare(TestCase.java:127)
	at junit.framework.TestResult$1.protect(TestResult.java:106)
	at junit.framework.TestResult.runProtected(TestResult.java:124)
	at junit.framework.TestResult.run(TestResult.java:109)
	at junit.framework.TestCase.run(TestCase.java:118)
	at junit.framework.TestSuite.runTest(TestSuite.java:208)
	at junit.framework.TestSuite.run(TestSuite.java:203)
	at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

So the solution is to use the @WebParam @WebMethod annotation. Simply use this annotation to specify unique operation names in your service implementation :

package com.googlecode.chamerling.blog.jaxws.duplicate;

import javax.jws.WebMethod;
import javax.jws.WebService;

/**
 * @author Christophe HAMERLING
 *
 */
@WebService
public class ServiceOk implements Service {

	@WebMethod(operationName = "foo1")
	public void foo() {
	}

	@WebMethod(operationName = "foo2")
	public void foo(String bar) {
	}
}

Sources for this example are availble on my google code project (http://code.google.com/p/chamerling/) under http://code.google.com/p/chamerling/source/browse/#svn/trunk/blog/jaxws-duplicate

4 réflexions sur “An operation with name '' already exists in this service

  1. I have tried what you said, but still continue to get the same exception.

    Need some clarification. In your message text you say use @WebParam, but your code sample uses @WebMethod. I think @WebParam is a typo, but thought I would ask.

    Second, are you sure we can get away with this by simply using the annotation on the method implementations? Doesn’t the WSDL generator look at the service interface? I’m thinking we need to put this on the service interface and not implementation.

    Thoughts?

  2. @SD
    Strange that you have the exception again. Are you using CXF?
    Sorry it is a typo you are right, I am going to fix it right now.
    You are also right on the second point but the reason, we always have to put annotation on the interface when we can. In that case imagine that you can not, solutions are :
    1. Put annotations on the implementation
    2. Create sort of a facade and do not care about annotations.
    For point number one, CXF really takes the right operation name when generating WSDL at runtime. A tool such as java2WSDL may also take the right operation name if you define to use the implementation and not the interface

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s