Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using polymorphic JAX-WS webservice parameters

I have this simple JAX-WS WebService:

@WebService
public class AnimalFeedingService {
    @WebMethod
    public void feed(@WebParam(name = "animal") Animal animal) {
        // Whatever
    }
}

@XmlSeeAlso({ Dog.class, Cat.class })
public abstract class Animal {
    private double weight;
    private String name;
    // Also getters and setters
}

public class Dog extends Animal {}

public class Cat extends Animal {}

I create a client and call feed with an instance of Dog.

Animal myDog = new Dog();
myDog .setName("Rambo");
myDog .setWeight(15);
feedingServicePort.feed(myDog);

The animal in the body of the SOAP call looks like this:

<animal>
    <name>Rambo</name>
    <weight>15</weight>
</animal>

and I get an UnmarshallException because Animal is abstract.

Is there a way to have Rambo unmarshalled as an instance of class Dog? What are my alternatives?

like image 338
adrianboimvaser Avatar asked Feb 09 '11 15:02

adrianboimvaser


1 Answers

As you might have guessed, XML parser is not able to determine the exact subtype of animal you used when requesting because anything it sees is generic <animal> and a set of tags that are common to all types, hence the error. What JAX-WS implementation do you use? It is the responsibility of the client to properly wrap polymorphic types when sending request. In Apache CXF (I checked your code against newest 2.3.2 version) the SOAP request body looks like this:

<animal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:dog">
    <name>Rambo</name>
    <weight>15.0</weight>
</animal>

The xsi:type="ns2:dog" is crucial here. It seems like your JAX-WS client is sending incorrect request that confuses the server. Try sending this request with some other client, like SoapUI, to see whether your server reacts properly.

As I said, it works just fine with Spring/Apache CXF and exactly the same code you've provided, I only extracted Java interface to make CXF happy:

public interface AnimalFeedingService {

    @WebMethod
    void feed(@WebParam(name = "animal") Animal animal);

}

@WebService
@Service
public class AnimalFeedingServiceImpl implements AnimalFeedingService {
    @Override
    @WebMethod
    public void feed(@WebParam(name = "animal") Animal animal) {
        // Whatever
    }
}

...and the server/client glue code:

<jaxws:endpoint implementor="#animalFeedingService" address="/animal"/>

<jaxws:client id="animalFeedingServiceClient"
              serviceClass="com.blogspot.nurkiewicz.test.jaxws.AnimalFeedingService"
              address="http://localhost:8080/test/animal">
</jaxws:client>
like image 181
Tomasz Nurkiewicz Avatar answered Nov 10 '22 06:11

Tomasz Nurkiewicz