Andrew wrote: > I have a class > > class Foo { > int id; > String name; > } > > Using the JsonHierarchicalStreamDriver I can turn this into JSON: > > {"id":1, "name":"x"} > > I want to auto-create a secondary node which is link to the Resource in > a REST interface, ie.: > > {"id":1, "link":"http://host/path/foo/1", "name":"x"} > > I have managed to achieve this using a simple converter: > > public class IdAndLinkConverter implements Converter { > > private final UriBuilder baseUriBuilder; > private final String path; > > public IdAndLinkConverter(UriBuilder baseUriBuilder, String path) { > this.baseUriBuilder = baseUriBuilder; > this.path = path; > } > > public boolean canConvert(Class type) { > return Number.class.isAssignableFrom(type); > } > > public void marshal(Object source, HierarchicalStreamWriter writer, > MarshallingContext context) { > Number id = (Number) source; > writer.setValue(id.toString()); > > writer.endNode(); > writer.startNode("link"); > URI uri = baseUriBuilder.path(path).build(id); > writer.setValue(uri.toString()); > } > > public Object unmarshal(HierarchicalStreamReader reader, > UnmarshallingContext context) { > throw new NotImplementedException(); > } > } > > And I configure this to be associated to a specific field like this: > > xstream.registerLocalConverter(Foo.class, "id", new > IdAndLinkConverter(baseUriBuilder, "/foo")); > > (The javax.ws.rs.core.UriBuilder argument handles creation of the link.) > > The "cheat" is the writer.endNode(), writer.startNode(..) which allows > me to inject a second node whilst I serialize the first field. > > Job done. Until I now want to build a more complex REST url, e.g.: > > class Baa { > int id; > int fooId; > String name; > } > > {"id":7, "fooId":1, "link":"http://host/path/foo/1/bar/7", "name":"y"} > > Now my link field requires two source fields to make it. The converter > approach above does not allow access to the parent object so I am stuck. > > OK, so I could write my own Converter for the Baa class; that's easy > enough, but not as elegant and long-term robust as the > IdAndLinkConverter. Writing my own Converter requires this custom > Converter to be maintained as the Bar class is changed - i.e. adding new > fields. > > I was thinking that I might be able to subclass the ReflectionConverter > which I believe handles all general classes. I can see > marshallField(..) but this does not provide access to the original > object which I need to be able to get to both by id fields. > > Another idea I had was to subclass ReflectionConverter and watch every > field go by and save the ones I am interesting in the > MashallingContext's put/get data holder. Then when the second field I > want comes along I am good to go. But I am not clear on the life cycle > of the MashallingContext and whether this is an appropriate usage of the > data holder. > > No doubt someone has thought of this before. What's the best way to > approach my requirement, please? > > By the way, I only need to handle serialization or marhsalling, not > unmarhsalling.
Actually you should have a look at a custom MarshallingStrategy. For JSON you select normally a predefined one with xstream.setMode(NO_REFERENCES), but in your case it makes sense to write an own one. The marshalling strategy recognizes any marshalled object and you may keep there references and ids for those objects and you may even write something additional (normally attributes). For elements you may append own ones easily after the converter is called that handles the object (note, that you cannot rely on the definition sequence of JSON fields anyway). Look at the TreeMarshaller and derived implementations to get an idea what you can do - no need to write a converter though ;-) Cheers, Jörg --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email