Problema com @WebParam Mode

Olá,

estou estudando JAX-WS e estou tentando aprender a usar os WebParam.Mode (IN, OUT e INOUT).

Para testes, criei a seguinte interface:

@WebService
public interface InAndOutModeService {

	@WebMethod
	void createPerson( @WebParam(mode=Mode.OUT) Holder<Person> person);
	
	@WebMethod
	void createPlayer( @WebParam(mode=Mode.IN) Holder<Player> player);
}

Abaixo, a implementação do serviço:

@WebService(endpointInterface="ws.InAndOutModeService")
public class InAndOutModeServiceImpl implements InAndOutModeService {

	@Override
	public void createPerson(Holder<Person>  person) {
		person.value.setName("Person's name");
	}

	@Override
	public void createPlayer(Holder<Player>  player) {
		System.out.println(player);
	}
}

Abaixo, as classes utilizadas como parâmetro:
Person:

public class Person {
	
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + "]";
	}
}

Player:

public class Player extends Person {

	private Integer number;

	public Integer getNumber() {
		return number;
	}

	public void setNumber(Integer number) {
		this.number = number;
	}

	@Override
	public String toString() {
		return "Player [number=" + number + ", getName()=" + getName() + "]";
	}
}

Quando tento subir o serviço, esta exceção é lançada:

Exception in thread "main" javax.xml.ws.WebServiceException: class ws.jaxws.CreatePlayerResponse do not have a property of the name arg0
	at com.sun.xml.internal.ws.server.sei.EndpointResponseMessageBuilder$DocLit.<init>(EndpointResponseMessageBuilder.java:195)
	at com.sun.xml.internal.ws.server.sei.EndpointMethodHandler.createResponseMessageBuilder(EndpointMethodHandler.java:191)
	at com.sun.xml.internal.ws.server.sei.EndpointMethodHandler.<init>(EndpointMethodHandler.java:97)
	at com.sun.xml.internal.ws.server.sei.PayloadQNameBasedDispatcher.<init>(PayloadQNameBasedDispatcher.java:95)
	at com.sun.xml.internal.ws.server.sei.EndpointMethodDispatcherGetter.<init>(EndpointMethodDispatcherGetter.java:61)
	at com.sun.xml.internal.ws.server.sei.SEIInvokerTube.<init>(SEIInvokerTube.java:64)
	at com.sun.xml.internal.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:194)
	at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:456)
	at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:475)
	at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.createEndpoint(EndpointImpl.java:213)
	at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(EndpointImpl.java:143)
	at com.sun.xml.internal.ws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:102)
	at javax.xml.ws.Endpoint.publish(Endpoint.java:170)
	at main.Main.main(Main.java:19)
Caused by: javax.xml.bind.JAXBException: arg0 is not a valid property on class ws.jaxws.CreatePlayerResponse
	at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getElementPropertyAccessor(JAXBContextImpl.java:931)
	at com.sun.xml.internal.ws.server.sei.EndpointResponseMessageBuilder$DocLit.<init>(EndpointResponseMessageBuilder.java:192)
	... 13 more

Como estou apenas estudando (não vou publicar meus serviços em ambiente de produção), estou usando a classe Endpoint para publicá-los:

Endpoint.publish(IN_AND_OUT_MODE_TEST_SERVICE_URL, new InAndOutModeServiceImpl());

Alguém sabe o que estou fazendo de errado?

Obrigado,
Abraço!

Essa classe CreatePlayerResponse é um cliente?

Olá,

Não. Eu acredito que o CreatePlayerResponse é o wrapper para a mensagem que é criado automaticamente pelo JAX-WS.

Obrigado,
Abraço

Tem certeza? Procurei no google e não encontrei nada a respeito.

Sim, tenho.

O padrão usado pelo JAX-WS é DOCUMENT/LITERAL e WRAPPED (parameterStyle = ParameterStyle.WRAPPED por default).

A menos que eu especifique o contrário, usando @SOAPBinding(parameterStyle = ParameterStyle.BARE), duas classes (uma para request e outra para response) wrappers serão criadas.

Obrigado,
Abraço!

Olá,

Eu acredito que esteja faltando um parâmetro de resposta(Mode.OUT) ou retorno do método createPlayer. arg0 que a mensagem de erro de refere, é parâmetro player, se chama arg0 pois vc não deu um nome a ele em @WebParam, e o erro é porque ele não corresponde a resposta. Acrescente uma resposta.

Victor Benjamin

Olá,

você diz fazer isso:

@WebParam(name="person", mode=Mode.OUT)

?

Eu já tentei desta maneira e o erro persiste. A única diferença é que na exceção, o “arg0” é substituído por “person”.

Tentei executar um código semelhante em outro computador, com outras versões do JDK e JAX-WS e funcionou.
Acredito que seja algum problema de incompatibilidade.

Obrigado,
abraço!

Qual servidor de aplicação, versão e JDK que você está utilizando?

Provavelmente você está usando JDK 6. Que possui o JAXB. E seu servidor de aplicação possui uma outra versão do JAXB. O que está acontecendo é que ClassLoader está carregando primeiro o JDK. E a versão JAXB da JDK é incompatível com o JAX-WS do servidor. Se o servidor rodar em cima do JDK 5, faça o teste. Acredito que funcionará.

Olá,

Na verdade, não estou usando servidor algum. Estou publicando os serviços usando a classe Endpoint do próprio JAX-WS.

Eu concordo contigo: também acho que talvez seja algum problema de incompatibilidade entre a versão do JDK 6 que uso (.17 eu acho) e do JAX-WS.

Em outra máquina (a do meu serviço), um código semelhante funcionou.

O problema é Mode.IN.

Se comentar o método que o usa, deixando somente o método que usa o Mode.OUT, o código funciona perfeitamente.
Se substituir o Mode.IN por Mode.INOUT também funciona.

O problema é somente com o IN mesmo :?

Obrigado,
Abraço!

Foi o que eu te sugeri na minha primeira resposta. Mas talvez tenha me expressado mal. Quando eu disse acrescentar uma resposta, era para adicionar um parâmetro OUT ou um retorno, que geralmente da no mesmo. Talvez eu tenha usado o termo errado. Invés de resposta saida.

victor.benjamin.guj,

só agora fui entender o quê vc quis dizer hehehe
Então, quando eu executo o código acima, no computador de casa, tenho aquele problema (que estamos suspeitando do Mode.IN sem OUT).

Porém, se eu testar o seguinte código na máquina da empresa em que trabalho:

@WebService
@SOAPBinding(parameterStyle = ParameterStyle.WRAPPED)
public interface Test {
	
	@WebMethod
	void createPerson( @WebParam(name = "personParam", mode=Mode.OUT) Holder<Person> person,
			@WebParam(name = "deptoParam", mode=Mode.OUT) Holder<Departament> dpto
	);
	
	@WebMethod
	void createPersonIn( @WebParam(name = "personInParam", mode=Mode.IN) Person personIn);
}

Implementação:

@WebService(endpointInterface = "ws.Test")
public class TestImpl implements Test {


	public void createPerson(Holder<Person> person, Holder<Departament> dpto) {
		person.value = new Person();
		person.value.setPerson("Person's name");
		dpto.value = new Departament();
		dpto.value.setDeptoName("Dpto Name");
		return;
	}

	public void createPersonIn(Person personIn) {
		personIn.setPerson("PersonIn's Name");
		return;
		
	}
}

Publicação:

public class Main {
	
	public static void main(String... args) {
		Endpoint.publish("http://localhost:1010/Test", new TestImpl());
	}
}

Código do Cliente:

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Test service = new TestImplService().getTestImplPort();
		
		Holder<Person> person = new Holder<Person>();
		Holder<Departament> dpto = new Holder<Departament>();
		service.createPerson(person, dpto);

		System.out.println("INFO: Person = " + person.value.getPerson());
		System.out.println("INFO: Dpto = " + dpto.value.getDeptoName());
		
		Person p = new Person();
		service.createPersonIn(p);
		System.out.println("INFO: " + p.getPerson()); //imprime null como era de se esperar...
	}
}

O código acima funciona na máquina da empresa, mesmo tendo um único parâmetro com Mode.IN e sem retorno.

Acredito que o problema deve ser mesmo alguma incompatibilidade no meu ambiente… :frowning:
Se eu descobrir o que está dando pau no meu ambiente, posto a resposta aqui.

Obrigado,
abraço!