Duplicate Class Names/Aliases

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Duplicate Class Names/Aliases

Ken Goudey
I am working with Spring 3.2 and xstream to marshall/unmarshall XML and have been running in circles trying to unmarshall annotated classes with the same name/alias. The gist of it is that I want two separate packages to contain similar models, with a spring configuration like this:

<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
    <property name="annotatedClasses">
        <list>
            <value>com.watchwith.Show</value>
            <value>com.watchwith.Content</value>
            <value>com.watchwith.alternate.Show</value>
            <value>com.watchwith.alternate.Content</value>
        </list>
    </property>
</bean>

In either "Show" and "Content" class I have the same aliases annotated:

@XStreamAlias("show")
public class Show {
    @XStreamAlias("content")
    private Content content;
...
}

@XStreamAlias("content")
public class Content {...}

And in my @Controllers I am importing the correct object, however, it seems that xstream chooses one of the packages/aliases (possibly alphabetically?) and always tries to unmarshall to that model. Is there a way (short of distinct aliases) to advise xstream to which class the incoming XML should be unmarshalled, since it does not appear to honor the value of the @RequestBody annotation?

Thank you!

Ken Goudey
Reply | Threaded
Open this post in threaded view
|

Re: Duplicate Class Names/Aliases

Jörg Schaible-2
Hi Ken,

Ken Goudey wrote:

> I am working with Spring 3.2 and xstream to marshall/unmarshall XML and
> have been running in circles trying to unmarshall annotated classes with
> the same name/alias.


First let me say, that I don't know Spring and what Spring actually does
with XStream.

Aliasing can be done for classes and fields (see
http://xstream.codehaus.org/alias-tutorial.html). These two types are
completely separate, they will not interfere each other.

Multiple alias definitions will clobber each other, if they are not unique:

============== %< =============
xstream.alias("text", String.class);
xstream.alias("text", StringBuilder.class);
assertEquals("<text>Hello</text>", xstream.toXML("Hello"));
assertEquals("<text>Hello</text>",
  xstream.toXML(new StringBuilder("Hello")));
assertEquals(new StringBuilder("Hello"),
  xstream.fromXML("<text>Hello</text>"));
============== %< =============

As you can see, the definition sequence is essential.


> The gist of it is that I want two separate packages
> to contain similar models, with a spring configuration like this:
>
> <bean id="xstreamMarshaller"
> class="org.springframework.oxm.xstream.XStreamMarshaller">
>     <property name="annotatedClasses">
>         <list>
>             <value>com.watchwith.Show</value>
>             <value>com.watchwith.Content</value>
>             <value>com.watchwith.alternate.Show</value>
>             <value>com.watchwith.alternate.Content</value>
>         </list>
>     </property>
> </bean>


The definition sequence is not obvious using annotations though. All I can
assume from this XML snippet is, that Spring will call
xstream.processAnnotations(Class[] types) internally. However, let's assume
you have following classes and call then XStream to process those classes'
annotations:

============== %< =============
class A {
 C c;
}
@XStreamAlias("same")
class B {
}
@XStreamAlias("same")
class C {
}
xstream.processAnnotations(A.class, B.class, C.class);
============== %< =============

XStream will process A, B and C in this sequence, i.e. it would normally
register any annotated alias for A, then for B and in the end for C.
However, in this case A contains a member of type C. Therefore XStream will
actually process these classes in the sequence A, C, B. As documented above,
this will have an effect here. While B and C will marshal both to an XML
element with name "same", the unmarshalling will always produce an element
of type B.


> In either "Show" and "Content" class I have the same aliases annotated:
>
> @XStreamAlias("show")
> public class Show {


The following field alias is superfluous, since the field is already named
"content".


>     @XStreamAlias("content")
>     private Content content;
> ...
> }


The following class alias does not interfere with the field alias above.

 
> @XStreamAlias("content")
> public class Content {...}
>
> And in my @Controllers I am importing the correct object, however, it
> seems that xstream chooses one of the packages/aliases (possibly
> alphabetically?) and always tries to unmarshall to that model. Is there a
> way (short of distinct aliases) to advise xstream to which class the
> incoming XML should be unmarshalled, since it does not appear to honor the
> value of the @RequestBody annotation?


Sorry, I don't know about @Controllers or @RequestBody.

Cheers,
Jörg


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Duplicate Class Names/Aliases

Ken Goudey
Thank you for the quick reply and confirmation of the behavior I was seeing. 

In case someone else runs into the issue of needing different models with identical aliases, I chose to work around the behavior by not using the @RequestBody annotation in one controller, and injecting (or creating) a separate XStream instance with only the appropriate package's annotations processed. Since I know the POST will contain an XML body, I add the HttpServletRequest and deserialize to my alternate model directly.