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
