views:

103

answers:

1

Hi guys

I have an abstract class that looks as follows.

public abstract class Entity<PK extends Serializable> implements Serializable {

    private PK id;

    //getters and setters generated here....
}

public class User extends Entity<Long> {

   //all attributes, getters and setters are done here...
}

My Service looks like this

public interface EntityService {

   public void create(Entity<? extends Serializable> entity) throws ServiceException;
   public boolean delete(Entity<? extends Serializable> entity) throws ServiceException;
}

and my implementation is on class EntityServiceImpl.

When I do a Web Service generation with Apache CXF, I get the following exception:

Error: java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.reflect.TypeVariable

java.lang.RuntimeException: java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.reflect.TypeVariable
    at org.apache.cxf.frontend.AbstractServiceFactory.createService(AbstractServiceFactory.java:41)
    at org.apache.cxf.tools.java2wsdl.processor.JavaToWSDLProcessor.process(JavaToWSDLProcessor.java:128)
    at org.apache.cxf.tools.java2ws.JavaToWSContainer.processWSDL(JavaToWSContainer.java:109)
    at org.apache.cxf.tools.java2ws.JavaToWSContainer.execute(JavaToWSContainer.java:75)
    at org.apache.cxf.tools.common.toolspec.ToolRunner.runTool(ToolRunner.java:103)
    at org.apache.cxf.tools.common.toolspec.ToolRunner.runTool(ToolRunner.java:58)
    at org.apache.cxf.tools.common.toolspec.ToolRunner.runTool(ToolRunner.java:40)
    at org.apache.cxf.tools.java2ws.JavaToWS.run(JavaToWS.java:77)
    at org.apache.cxf.tools.java2ws.JavaToWS.main(JavaToWS.java:45)
Caused by: java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.reflect.TypeVariable
    at org.apache.cxf.jaxb.JAXBContextInitializer.addType(JAXBContextInitializer.java:232)
    at org.apache.cxf.jaxb.JAXBContextInitializer.addType(JAXBContextInitializer.java:211)

My question:

How do I generate a Web Service that has Parametrized Types or uses Generics?

A: 

Seeing that nobody answered this question, I'll answer this myself.

With Apache CXF, A WS generated bean, all getters return a not null object, meaning that if a variable is null, this is what happens:

 public List<? extends User> getParents() {
        if (parents == null) {
            parents = new ArrayList<User>();
        }
        return this.parents;
    }

As you can see, this following causes an exception for CXF:

  • A Serializable class is an interface, so if I have a variable of type Serializable, new Serializable() cannot be defined when CXF generates client source-code.
  • All Object must implement a public constructor.

Failure for the 2 principles, causes the exception above.


Solution

For attribute private List<? extends User> parents, we added this.

@XmlElements({ 
    @XmlElement(type=Man.class),
    @XmlElement(type=Female.class),
    @XmlElement(type=Child.class)
})
private List<? extends User> parents;

And for interfaces, we used the XmlJavaTypeAdapter and wrote an adapter for every implemented subclasses of that interface,

e.g.

public class IntegerConstraintBaseAdapter extends XmlAdapter<IntegerConstraint, ConstraintBase<Integer>> {

    /* (non-Javadoc)
     * @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
     */
    @Override
    public IntegerConstraint marshal(ConstraintBase<Integer> v) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    /* (non-Javadoc)
     * @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
     */
    @Override
    public ConstraintBase<Integer> unmarshal(IntegerConstraint v) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }
}

Hope this helps someone.

The Elite Gentleman