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)?




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
>

Reply via email to