You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Rafael Ribeiro <ra...@gmail.com> on 2008/04/20 18:36:27 UTC

problem serializing class hierarchy

Hi all,

 I have an webmethod that returns an arbitrary class. The problem is, on
some of its executions it might return some subclass of the class that is
expressed on the method signature. Instead of getting the actual class that
was serialized from the webservice the client is getting the class that is
expressed on the method. Do I have to specify anything on the classes that I
need to serialize or on the method in order for it to correct serialize the
expected class?
I am sending a sample I did to reproduce the problem described above (it is
deployed on tomcat using CXFNonSpringServlet and service is registered using
an startupservlet):

-------------------------------- IFake.java
-------------------------------------

package fake;

import javax.jws.WebService;

@WebService
public interface IFake {
    public Foo fooOp();
}

-------------------------------- FakeImpl.java
-------------------------------------

package fake;

public class FakeImpl implements IFake {

    public Foo fooOp() {
        return new FooBar();
    }

}


-------------------------------- FakeCli.java
-------------------------------------

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import fake.IFake;

public class FakeCli {
    private static IFake fakeClient;

    public static void main(String[] args) {
        System.out.println(getFakeClient().fooOp());
    }

    public static IFake getFakeClient() {
        if (fakeClient == null) {
            JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
            factory.setServiceClass(IFake.class);
            factory
                    .setAddress("
http://localhost:8080/mywebapp/services/fake");
            fakeClient = (IFake) factory.create();
        }
        return fakeClient;
    }
}

-------------------------------- Foo.java
-------------------------------------

package fake;

public class Foo {
    private String foo;

    public String getFoo() {
        return foo;
    }

    public void setFoo(String foo) {
        this.foo = foo;
    }

}

-------------------------------- FooBar.java
-------------------------------------

package fake;

public class FooBar extends Foo {
    private String fooBar;

    public String getFooBar() {
        return fooBar;
    }

    public void setFooBar(String fooBar) {
        this.fooBar = fooBar;
    }

}

------------------------------------------------------------------------

 This webservice is registered by this call on the startupservlet:
        Endpoint.publish("/fake", new FakeImpl());

and the result of the execution of FakeCli is something like:
fake.Foo@6210fb

If I try to cast it to FooBar I get a ClassCastException, as expected since
this class was really instantiated as Foo instead of FooBar

Re: problem serializing class hierarchy

Posted by Freeman Fang <fr...@gmail.com>.
Hi Rafael,

Take a look at  CXF-340-Support adding extra classes to JAXB context,  
which address your issue.
[1] for more details
[1]http://issues.apache.org/jira/browse/CXF-340

Regards

Freeman

Rafael Ribeiro wrote:
> Hi all,
>
>  I have an webmethod that returns an arbitrary class. The problem is, on
> some of its executions it might return some subclass of the class that is
> expressed on the method signature. Instead of getting the actual class that
> was serialized from the webservice the client is getting the class that is
> expressed on the method. Do I have to specify anything on the classes that I
> need to serialize or on the method in order for it to correct serialize the
> expected class?
> I am sending a sample I did to reproduce the problem described above (it is
> deployed on tomcat using CXFNonSpringServlet and service is registered using
> an startupservlet):
>
> -------------------------------- IFake.java
> -------------------------------------
>
> package fake;
>
> import javax.jws.WebService;
>
> @WebService
> public interface IFake {
>     public Foo fooOp();
> }
>
> -------------------------------- FakeImpl.java
> -------------------------------------
>
> package fake;
>
> public class FakeImpl implements IFake {
>
>     public Foo fooOp() {
>         return new FooBar();
>     }
>
> }
>
>
> -------------------------------- FakeCli.java
> -------------------------------------
>
> import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
>
> import fake.IFake;
>
> public class FakeCli {
>     private static IFake fakeClient;
>
>     public static void main(String[] args) {
>         System.out.println(getFakeClient().fooOp());
>     }
>
>     public static IFake getFakeClient() {
>         if (fakeClient == null) {
>             JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
>             factory.setServiceClass(IFake.class);
>             factory
>                     .setAddress("
> http://localhost:8080/mywebapp/services/fake");
>             fakeClient = (IFake) factory.create();
>         }
>         return fakeClient;
>     }
> }
>
> -------------------------------- Foo.java
> -------------------------------------
>
> package fake;
>
> public class Foo {
>     private String foo;
>
>     public String getFoo() {
>         return foo;
>     }
>
>     public void setFoo(String foo) {
>         this.foo = foo;
>     }
>
> }
>
> -------------------------------- FooBar.java
> -------------------------------------
>
> package fake;
>
> public class FooBar extends Foo {
>     private String fooBar;
>
>     public String getFooBar() {
>         return fooBar;
>     }
>
>     public void setFooBar(String fooBar) {
>         this.fooBar = fooBar;
>     }
>
> }
>
> ------------------------------------------------------------------------
>
>  This webservice is registered by this call on the startupservlet:
>         Endpoint.publish("/fake", new FakeImpl());
>
> and the result of the execution of FakeCli is something like:
> fake.Foo@6210fb
>
> If I try to cast it to FooBar I get a ClassCastException, as expected since
> this class was really instantiated as Foo instead of FooBar
>
>   


Re: problem serializing class hierarchy

Posted by Rafael Ribeiro <ra...@gmail.com>.
After some extra googling rounds I found this thread that pointed to the
same problem I faced...
http://www.nabble.com/Migrating-XFire-Aegis-inheritance-to-CXF-td13536859.html
Does anyone knows if there is another method for solving this by using
annotations?

regards,


2008/4/20, Rafael Ribeiro <ra...@gmail.com>:
>
> Hi all,
>
>  I have an webmethod that returns an arbitrary class. The problem is, on
> some of its executions it might return some subclass of the class that is
> expressed on the method signature. Instead of getting the actual class that
> was serialized from the webservice the client is getting the class that is
> expressed on the method. Do I have to specify anything on the classes that I
> need to serialize or on the method in order for it to correct serialize the
> expected class?
> I am sending a sample I did to reproduce the problem described above (it
> is deployed on tomcat using CXFNonSpringServlet and service is registered
> using an startupservlet):
>
> -------------------------------- IFake.java
> -------------------------------------
>
> package fake;
>
> import javax.jws.WebService;
>
> @WebService
> public interface IFake {
>     public Foo fooOp();
> }
>
> -------------------------------- FakeImpl.java
> -------------------------------------
>
> package fake;
>
> public class FakeImpl implements IFake {
>
>     public Foo fooOp() {
>         return new FooBar();
>     }
>
> }
>
>
> -------------------------------- FakeCli.java
> -------------------------------------
>
> import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
>
> import fake.IFake;
>
> public class FakeCli {
>     private static IFake fakeClient;
>
>     public static void main(String[] args) {
>         System.out.println(getFakeClient().fooOp());
>     }
>
>     public static IFake getFakeClient() {
>         if (fakeClient == null) {
>             JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
>             factory.setServiceClass(IFake.class);
>             factory
>                     .setAddress("
> http://localhost:8080/mywebapp/services/fake");
>             fakeClient = (IFake) factory.create();
>         }
>         return fakeClient;
>     }
> }
>
> -------------------------------- Foo.java
> -------------------------------------
>
> package fake;
>
> public class Foo {
>     private String foo;
>
>     public String getFoo() {
>         return foo;
>     }
>
>     public void setFoo(String foo) {
>         this.foo = foo;
>     }
>
> }
>
> -------------------------------- FooBar.java
> -------------------------------------
>
> package fake;
>
> public class FooBar extends Foo {
>     private String fooBar;
>
>     public String getFooBar() {
>         return fooBar;
>     }
>
>     public void setFooBar(String fooBar) {
>         this.fooBar = fooBar;
>     }
>
> }
>
> ------------------------------------------------------------------------
>
>  This webservice is registered by this call on the startupservlet:
>         Endpoint.publish("/fake", new FakeImpl());
>
> and the result of the execution of FakeCli is something like:
> fake.Foo@6210fb
>
> If I try to cast it to FooBar I get a ClassCastException, as expected
> since this class was really instantiated as Foo instead of FooBar
>

Re: problem serializing class hierarchy

Posted by Ian Roberts <i....@dcs.shef.ac.uk>.
Rafael Ribeiro wrote:
> Hi all,
> 
>  I have an webmethod that returns an arbitrary class. The problem is, on
> some of its executions it might return some subclass of the class that is
> expressed on the method signature. Instead of getting the actual class that
> was serialized from the webservice the client is getting the class that is
> expressed on the method. Do I have to specify anything on the classes that I
> need to serialize or on the method in order for it to correct serialize the
> expected class?

To get this working with JAX-WS you need to make sure that the JAXB 
context knows about all the possible concrete classes you could be 
returning.  With a CXF 2.1 snapshot you might be able to do this with an 
@XmlSeeAlso annotation in the appropriate place (but don't ask me where 
that place is...).

I managed this with 2.0.x by creating a data binding object that 
includes the extra classes (in both the server and client sides):

<jaxws:server id="myServiceEndpoint"
     serviceBean="#myServiceImpl"
     serviceClass="fake.FakeImpl"
     address="/service">
   <jaxws:dataBinding>
     <bean class="org.apache.cxf.jaxb.JAXBDataBinding">
       <property name="extraClass">
         <list>
           <value>fake.FooBar</value>
           <value>fake.AnotherSubclassOfFoo</value>
         </list>
       </property>
     </bean>
   </jaxws:dataBinding>
</jaxws:server>

For the client side, you set the data binding on the 
JaxWsProxyFactoryBean before calling factory.create():

JAXBDataBinding db = new JAXBDataBinding();
db.setExtraClass(new Class[] {
    fake.FooBar.class,
    fake.AnotherSubclassOfFoo.class
});
factory.setDataBinding(db);

To do the server side without Spring I guess you could use this same 
code snippet with a JaxWsServerFactoryBean.

Ian

-- 
Ian Roberts               | Department of Computer Science
i.roberts@dcs.shef.ac.uk  | University of Sheffield, UK

Re: problem serializing class hierarchy

Posted by Daniel Kulp <dk...@apache.org>.
As Ian mentioned, this is quite a bit easier with JAXWS/JAXB 2.1.  With 
the 2.1 snapshots, you can add

@XmlSeeAlso(FooBar.class) to the IFake interface or to the Foo object to 
allow the runtime to know that the FooBar class should also be added to 
the JAXBContext.  

Alternatively, for CXF 2.0.5 and 2.1, if Foo.java and FooBar.java are in 
the same package, you can add a file called "jaxb.index" to the package 
that just contains a single line:
FooBar
(don't put a package qualifier there as the jaxb.index only loades 
classes from the same package)  The JAXB databinding will pick that up 
and load those classes as well.

Dan


On Sunday 20 April 2008, Rafael Ribeiro wrote:
> Hi all,
>
>  I have an webmethod that returns an arbitrary class. The problem is,
> on some of its executions it might return some subclass of the class
> that is expressed on the method signature. Instead of getting the
> actual class that was serialized from the webservice the client is
> getting the class that is expressed on the method. Do I have to
> specify anything on the classes that I need to serialize or on the
> method in order for it to correct serialize the expected class?
> I am sending a sample I did to reproduce the problem described above
> (it is deployed on tomcat using CXFNonSpringServlet and service is
> registered using an startupservlet):
>
> -------------------------------- IFake.java
> -------------------------------------
>
> package fake;
>
> import javax.jws.WebService;
>
> @WebService
> public interface IFake {
>     public Foo fooOp();
> }
>
> -------------------------------- FakeImpl.java
> -------------------------------------
>
> package fake;
>
> public class FakeImpl implements IFake {
>
>     public Foo fooOp() {
>         return new FooBar();
>     }
>
> }
>
>
> -------------------------------- FakeCli.java
> -------------------------------------
>
> import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
>
> import fake.IFake;
>
> public class FakeCli {
>     private static IFake fakeClient;
>
>     public static void main(String[] args) {
>         System.out.println(getFakeClient().fooOp());
>     }
>
>     public static IFake getFakeClient() {
>         if (fakeClient == null) {
>             JaxWsProxyFactoryBean factory = new
> JaxWsProxyFactoryBean(); factory.setServiceClass(IFake.class);
>             factory
>                     .setAddress("
> http://localhost:8080/mywebapp/services/fake");
>             fakeClient = (IFake) factory.create();
>         }
>         return fakeClient;
>     }
> }
>
> -------------------------------- Foo.java
> -------------------------------------
>
> package fake;
>
> public class Foo {
>     private String foo;
>
>     public String getFoo() {
>         return foo;
>     }
>
>     public void setFoo(String foo) {
>         this.foo = foo;
>     }
>
> }
>
> -------------------------------- FooBar.java
> -------------------------------------
>
> package fake;
>
> public class FooBar extends Foo {
>     private String fooBar;
>
>     public String getFooBar() {
>         return fooBar;
>     }
>
>     public void setFooBar(String fooBar) {
>         this.fooBar = fooBar;
>     }
>
> }
>
> ----------------------------------------------------------------------
>--
>
>  This webservice is registered by this call on the startupservlet:
>         Endpoint.publish("/fake", new FakeImpl());
>
> and the result of the execution of FakeCli is something like:
> fake.Foo@6210fb
>
> If I try to cast it to FooBar I get a ClassCastException, as expected
> since this class was really instantiated as Foo instead of FooBar



-- 
J. Daniel Kulp
Principal Engineer, IONA
dkulp@apache.org
http://www.dankulp.com/blog