views:

466

answers:

2

Let's say i have the following strucutre

public class Mammal
{
    @WebMethod
    public ArrayList<Mammal> getAll(){ return null; }
    @WebMethod
    public String speak(){ return "Unable to speak"; }
    @WebMethod
    public Mammal me(){ return this; } 
}

@WebService
public class Human extends Mammal
{
    @WebMethod
    public ArrayList<Human> getAll(){ /* code to return all humans as ArrayList<Human> */ }
    @WebMethod
    public String speak() { return "Hai!"; }
    @WebMethod(operationName="GetHuman")
    public Human me(){ return this; }
}

Now If you see the Mammal me() and Human me() are overided natuarlly and this works perfectly and the WSDL is generated as it should be because that i add the operationName="".

So far so good, now the method returning an ArrayList does not work. Somehow it says that ArrayList can't override ArrayList which in my opinion should be possible?

Now I found a work-around for this and the result looks as followed

In the Mammal class I have this instead: public ArrayList getAll(){ return null; }

And i leave the Humna-class untouched, now this works.

However! This makes it Impossible to extending a Human and overriding the method from a new sub-class, so I am back at square one again.

How do I solve this?

Let's say I want to access the Webservice from a C# application then i want the method to have a return type of List Human or List Whatever-extended-Mammal, Without having to type-cast on the other side!

A: 

What if you try real array instead of collection? I don't think that web service frameworks work well with generics.

EDIT: Something like that:

public class Mammal
{

    @WebMethod
    public Mammal[] getAll() { return null; }

    ...

}

@WebService
public class Human extends Mammal
{

    @WebMethod
    public Human[] getAll() { return null; }

    ...

}
Superfilin
It works perfectly well with Collections. And if you use "real" arrays instead of collections the result when calling the webservice is the super-class-return-type which would be Mammal[] when calling the Human[] me(). And that is wrong.
Filip Ekberg
As of Java 5, you're allowed to change the return type in the overriding method as long as the new return type is a subtype of the declared return type.
Superfilin
Have you Tried that? Because when exposing it as a Webservice, Human.getAll() still returns Mammal.
Filip Ekberg
What superflin has suggested is correct. That is using arrays over collections. Go to http://ws.apache.org/axis/java/user-guide.html and check under What Axis can send via SOAP with restricted Interoperability
Cshah
The question is not about using Collections over Arrays, please see my previous responses. The method does not work.
Filip Ekberg
I have tried compiling the code above using Axis2's java2wsdl and with collections it produces WSDL with anyType instead of List, but with arrays it realy uses the return type from supertype's method.
Superfilin
Btw. which WS framework do you use? Do you use Axis2? Or something else?
Superfilin
The reason why Axis2's java2wsdl does not work with generics is because it runs against compiled class which has erased generic signature.
Superfilin
I use JAX-RPC and the Built in Web Service tester in JDeveloper from Oracle. Testing the Webservice both with the tester and from i.e. C# or any other type, still results in returning the Base-type.
Filip Ekberg
+2  A: 

Your code example should not compile even without the web service related annotations. List<Human> is NOT a subtype of List<Mammal>. However, if you use List<? extends Mammal> in your base class, then everything should work just fine.

public class Mammal
{
    @WebMethod
    public List<? extends Mammal> getAll() { return null; }
}

public class Human extends Mammal {
    @WebMethod
    public List<Human> getAll() { return null; }
}

If you want to extend Human even further, then you would have to use

public class Human extends Mammal {
    @WebMethod
    public List<? extends Human> getAll() { return null; }
}
janko
Awesome, im gonna try this out.
Filip Ekberg
Works perfectly, thank you very much. Is <? extends .. > some Java-magic? :)
Filip Ekberg
It is called a "bounded wildcard parameterized type". There is a great FAQ on Java generics here: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
janko