[xstream-user] xstream.setMode(XStream.XPATH_REFERENCES) and non-circular references

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

[xstream-user] xstream.setMode(XStream.XPATH_REFERENCES) and non-circular references

wombat marsupial
Hi,

I have list of objects, each of which has a java.lang.Enum value.  I want that enum value to be printed out using the normal Enum.toString() method.  XStream does this for the first occurrence of each enum value in the list.  However, on subsequent occurrences of the enum, I get an annoying XPath reference instead of a simple string value.

What I get:
<list>
    <myobject>
        <myenum>enumvalue1</myenum>
    </myobject>
     <myobject>
         <myenum>enumvalue2</myenum>
     </myobject>
     <myobject>
         <myenum reference="../../myobject/myenum"/>
     </myobject>
</list>

What I want:
<list>
     <myobject>
         <myenum>enumvalue1</myenum>
     </myobject>
      <myobject>
          <myenum>enumvalue2</myenum>
      </myobject>
      <myobject>
          <myenum>enumvalue1</myenum>
      </myobject>
</list>

I have two questions:
1. Isn't that XPath wrong?  It does not uniquely identify which <myenum> node is actually being referenced, since there exist multiple in the list.  I understand the complexity involved in generating a true unique XPath string, but a node-set doesn't do me much good.

2. More importantly (to me, at least), is it possible to force XStream to use references ONLY when they exist in a circular manner?  The only time I don't want to print out the full serialization of multiple occurrences of the same object is when that object is a descendant of itself ( i.e. in a circular reference).  xstream.setMode(XStream.NO_REFERENCES) does not work for me here, since I happen to have other data which is circular.  Note that the example above uses enums and a simple toString() representation, but I want this for any/every object and its full graph.

I am using version 1.1.2.
Thanks for any help anyone can provide.
-w
Reply | Threaded
Open this post in threaded view
|

Re: [xstream-user] xstream.setMode(XStream.XPATH_REFERENCES) and non-circular references

Joe Walnes-2
> <list>
>     <myobject>
>         <myenum>enumvalue1</myenum>
>     </myobject>
>      <myobject>
>          <myenum>enumvalue2</myenum>
>      </myobject>
>      <myobject>
>          <myenum reference="../../myobject/myenum"/>
>      </myobject>
> </list>

> 1. Isn't that XPath wrong?  It does not uniquely identify which <myenum>
> node is actually being referenced, since there exist multiple in the list.

If you refer to a single node using an XPath expression, the default
behavior for XPath implementations is to refer to the first node that
matches the pattern.

So ../myobject/myenum is the same as ../myobject[1]/myenum[1] (note:
XPath uses one based indexing).

If you were to refer to another item in the list, the XPath would look
something like:
          <myenum reference="../../myobject/myenum[3]"/>


> 2. More importantly (to me, at least), is it possible to force XStream to
> use references ONLY when they exist in a circular manner?  The only time I
> don't want to print out the full serialization of multiple occurrences of
> the same object is when that object is a descendant of itself ( i.e. in a
> circular reference).  xstream.setMode(XStream.NO_REFERENCES) does not work
> for me here, since I happen to have other data which is circular.  Note that
> the example above uses enums and a simple toString() representation, but I
> want this for any/every object and its full graph.

Out of the box, there is not an option for this. However the necessary
extension points exist in the XStream API to allow you to add this
functionality yourself.

Before I go into the details of this, here's a few points:

* Not using references upon serialization is dangerous when these
objects are mutable as the graph will behave inconsitently before and
after serialization when changing the state of one of the objects. I
highly recommend having graphs that behave consistently before and
after serialization.

* If you don't want to maintain references of mutable objects, I
recommend cloning them upon building the graph, for safety.

* You can tell XStream about immutable classes that it shouldn't use
references for (e.g. Strings, etc) using
XStream.addImmutableType(Something.class).

If you're still interested in adding this functionality, let me know
and I shall walk you through it.

thanks
-Joe
Reply | Threaded
Open this post in threaded view
|

Re: [xstream-user] xstream.setMode(XStream.XPATH_REFERENCES) and non-circular references

wombat marsupial
joe,

in this particular use case, i'm not concerned about de-serialization.  the xml is being piped directly into xsl for transformation into xhtml.  it's the readability of my xslt that's nagging me at the moment.  i prefer to keep my xpath usage simple and sparse.  your reference to XStream.addImmutableType() worked like a charm - i'm getting exactly what i need for this particular enum.

that said, it would be great if you can go into detail regarding how to do this in a generic manner - i would rather not have to track a list of hundreds of "immutable" classes when i could just do it right.

thanks for your help!
-w

[hidden email]
> <list>

>     <myobject>
>         <myenum>enumvalue1</myenum>
>     </myobject>
>      <myobject>
>          <myenum>enumvalue2</myenum>
>      </myobject>
>      <myobject>
>          <myenum reference="../../myobject/myenum"/>
>      </myobject>
> </list>

> 1. Isn't that XPath wrong?  It does not uniquely identify which <myenum>
> node is actually being referenced, since there exist multiple in the list.

If you refer to a single node using an XPath expression, the default
behavior for XPath implementations is to refer to the first node that
matches the pattern.

So ../myobject/myenum is the same as ../myobject[1]/myenum[1] (note:
XPath uses one based indexing).

If you were to refer to another item in the list, the XPath would look
something like:
          <myenum reference="../../myobject/myenum[3]"/>


> 2. More importantly (to me, at least), is it possible to force XStream to
> use references ONLY when they exist in a circular manner?  The only time I
> don't want to print out the full serialization of multiple occurrences of
> the same object is when that object is a descendant of itself ( i.e. in a
> circular reference).  xstream.setMode(XStream.NO_REFERENCES ) does not work
> for me here, since I happen to have other data which is circular.  Note that
> the example above uses enums and a simple toString() representation, but I
> want this for any/every object and its full graph.

Out of the box, there is not an option for this. However the necessary
extension points exist in the XStream API to allow you to add this
functionality yourself.

Before I go into the details of this, here's a few points:

* Not using references upon serialization is dangerous when these
objects are mutable as the graph will behave inconsitently before and
after serialization when changing the state of one of the objects. I
highly recommend having graphs that behave consistently before and
after serialization.

* If you don't want to maintain references of mutable objects, I
recommend cloning them upon building the graph, for safety.

* You can tell XStream about immutable classes that it shouldn't use
references for (e.g. Strings, etc) using
XStream.addImmutableType(Something.class).

If you're still interested in adding this functionality, let me know
and I shall walk you through it.

thanks
-Joe