On Wednesday, June 08, 2011 11:22:08 AM Jason Whaley wrote:
> The problem itself manifests where a @WebMethod is actually specifying
> List<SomeJaxbBean> as the return type.  As a simple example:
> 
> @WebMethod(operationName = "getRoles")
> @WebResult(name = "roles")
> List<Role> getRoles( @WebParam(name="roleIds") List<String> roleIds );
> 
> Would we be better off just wrapping that list in a specific class
> used only as a return type (much like how I suspect wsdl2java would
> generate it if you assume your wsdl had an output message that
> returned a complexType containing a sequence)?

Ah.  Right.  For this case, you should likely create a wrapper class for the 
response and use the @ResponseWrapper annotation to point to it.      The 
"java2ws" tool has a flag to generate stubs for those if you need it, but it 
really would just be another JAXB annotated bean with your list as a property.  
   
If you have the @ResponseWrapper pointing to a valid class, CXF will use it so 
you should be able to use all the same JAXB things like the afterUnmarshal and 
such with it.

Dan


> 
> On Tue, Jun 7, 2011 at 1:46 PM, Daniel Kulp <[email protected]> wrote:
> > My gut feeling is that the best option is to construct the JAXB bean like
> > normal:
> > 
> > public class MyFoo {
> >   List<Blah> blahs = new ArrayList<Blah>();
> > 
> >  ...   all the normal things ....
> > 
> > }
> > 
> > 
> > but then add a method like:
> > 
> > publi void afterUnmarshal(Unmarshaller, Object parent) {
> >    blahs = Collections.unmodifiableList(blahs);
> > }
> > 
> > to reset it to an unmodifiable collection after the unmarshalling is
> > done. The call to the afterUnmarshal method is part of the spec:
> > 
> > http://download.oracle.com/javase/6/docs/api/javax/xml/bind/Unmarshaller.
> > html#unmarshalEventCallback
> > 
> > 
> > Dan
> > 
> > On Tuesday, June 07, 2011 12:22:50 PM Jason Whaley wrote:
> >> (bear with me, this is a bit of a long question)
> >> 
> >> I'm working on a project, Kuali Rice (http://www.kuali.org/rice), that
> >> basically acts as a service bus for a series of other systems.  We are
> >> using CXF behind the scenes to publish JAX-WS annotated services that
> >> are written code-first.  These services can either be looked up and
> >> accessed by a client through a JAX-WS service proxy or, if Rice is
> >> running embedded in an app, an actual reference to the implementation
> >> can be given the to client.
> >> 
> >> This works great in the general case.  However we've recently started
> >> trying to enforce immutability on lots of our model objects and
> >> Collections/Maps of those model objects for various reasons.  Our
> >> services are using these immutable model objects as both parameters
> >> and return types.  Where this breaks down with JAX-WS and SOAP is in
> >> the case where a service method returns a Collection of these model
> >> objects back and we want the Collection itself to be immutable (e.g.
> >> the type you would get back from one of the
> >> Collections.unmodifiable*() methods).  If a client makes a service
> >> call through the JAX-WS proxy and the return type is
> >> List<SomeModelObject> then what it gets back is a modifiable List.
> >> This basically means that the two possible implementations that a
> >> client can reference will have different behaviors that break the
> >> documented expectation of what gets returned from method calls that
> >> return a List type (that expectation being an immutable list).
> >> 
> >> Despite the fact that these services are code first, we are striving
> >> to to make sure that the generated WSDL/XSD from our JAXB and JAX-WS
> >> annotated types and services produce somewhat of a sane contract for
> >> possibly non-java clients to use in the future.  As such, doing
> >> something like introducing an actual type for an ImmutableList (or
> >> using something like ImmutableList from guava) would create needless
> >> and java specific types in the generated WSDL/XSD.  We didn't go that
> >> route for that very reason.
> >> 
> >> The first thing I tried was to write a simple XmlAdapter to that would
> >> return an immutable List reference during unmarshalling.  It ended up
> >> looking like this:
> >> 
> >> 
> >> public class ImmutableListAdapter extends XmlAdapter<Object[], List<?>>
> >> {
> >> 
> >>     @Override
> >>     public List<?> unmarshal(Object[] objects) throws Exception {
> >>         return Collections.unmodifiableList(Arrays.asList(objects));
> >>     }
> >> 
> >>     @Override
> >>     public Object[] marshal(List<?> objects) throws Exception {
> >>         return objects.toArray();
> >>     }
> >> 
> >> }
> >> 
> >> 
> >> This works, but now the generated XSD/WSDL has those sequences that
> >> represent Lists as a sequence of <xs:any> types, which again we'd
> >> prefer not to have in order to keep the XSD/WSDL sane in the future
> >> for non java clients to use.   We could write an adapter for every
> >> single List<SomeModelObject> there such that the unbounded wildcard
> >> type isn't used and we are marshing to/from a
> >> SomeJaxbAnnotatedModelObject[] instead of Object[] each time (thus
> >> preventing the sequences of xs:any), but this seems like massive
> >> overkill to do for every single model object that we have.   Is there
> >> another possible way to do this with a XmlAdapter that wouldn't
> >> require such duplication?
> >> 
> >> If a JAXB Adapter is not the way to go with this, would it possible
> >> (and straightforward) to do this in a CXF interceptor that might do
> >> the same thing as this XmlAdapter but in such a way that it does not
> >> alter the generated XSD?  If so, what phase should that interceptor be
> >> bound to?
> > 
> > --
> > Daniel Kulp
> > [email protected]
> > http://dankulp.com/blog
> > Talend - http://www.talend.com

-- 
Daniel Kulp
[email protected]
http://dankulp.com/blog
Talend - http://www.talend.com

Reply via email to