问题
I'm using the Simple (http://simple.sourceforge.net/) library to marshall/unmarshall XML data in Java. For some of my more complex data structures, I need to write my own Converters. For instance, say I have a List<List<String>>
that I need to marshall. I've written the following:
class WorldObject {
@Element(name="vector-names")
@Convert(ListListConverter.class)
private List<List<String>> vectorNames;
/** Constructor and other details ... **/
}
Along with the ListListConverter (I've left out the unmarshaller for the moment):
class ListListConverter implements Converter<List<List<String>>> {
@Override
public List<List<String>> read(InputNode node) throws Exception {
// stub
return null;
}
@Override
public void write(OutputNode node, List<List<String>> value)
throws Exception {
node.setName("list-list-string");
for (List<String> list : value) {
OutputNode subList = node.getChild("list-string");
for (String str : list) {
OutputNode stringNode = subList.getChild("string");
stringNode.setValue(str);
}
subList.commit();
}
node.commit();
}
}
This setup works fine, and produces the XML I want. I would, however, like to have access to the @Element
annotation's name
field so that I can give the tags the specified name (in this case, "vector-names"
) rather than the default name ("list-list-string"
). This is how marshalling works for all the types that Simple handles out of the box, so there must be a way to access that data from a custom Converter.
How can I accomplish this?
回答1:
You can't get the annotation that way, because it's not accessible through the field in the field-converter.
The solution is to write a WorldObject
-Converter - even if you only want to write a single field.
WorldObject
class:
@Root
@Convert(WorldObjectConverter.class) // specify converter for this class
public class WorldObject
{
@Element(name = "vector-names")
private List<List<String>> vectorNames;
// only for the example below - write whatever constructor(s) you need
public WorldObject()
{
this.vectorNames = new ArrayList<>();
}
// constructor, getter / setter, etc.
// a getter is required to access the field in the converter.
public List<List<String>> getVectorNames()
{
return vectorNames;
}
}
WorldObjectConverter
class:
public class WorldObjectConverter implements Converter<WorldObject>
{
@Override
public WorldObject read(InputNode node) throws Exception
{
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void write(OutputNode node, WorldObject value) throws Exception
{
final Field f = value.getClass().getDeclaredField("vectorNames"); // get the field 'vectorNames' of the 'WorldObject' class
final Element elementAnnotation = f.getAnnotation(Element.class); // get the 'Element' annotation of the Field
final String name = elementAnnotation.name(); // get the 'name'-value of the annotation
node.setName(name); // set Nodename
for( List<String> list : value.getVectorNames() )
{
OutputNode subList = node.getChild("list-string");
for( String str : list )
{
OutputNode stringNode = subList.getChild("string");
stringNode.setValue(str);
}
subList.commit();
}
node.commit();
}
}
Example:
final File f = new File("test.xml"); // output file
WorldObject wo = new WorldObject(); // the object to serialize
// some testdata ...
List<String> l = new ArrayList<>();
l.add("a");
l.add("b");
wo.getVectorNames().add(l);
l = new ArrayList<>();
l.add("c");
l.add("d");
wo.getVectorNames().add(l);
// create the serializer - dont forget the AnnotationStrategy!
Serializer ser = new Persister(new AnnotationStrategy());
ser.write(wo, f); // serialize it to file
Output:
<vector-names>
<list-string>
<string>a</string>
<string>b</string>
</list-string>
<list-string>
<string>c</string>
<string>d</string>
</list-string>
</vector-names>
Done!
来源:https://stackoverflow.com/questions/9343348/how-do-you-access-field-annotations-from-a-custom-converter-with-simple