DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG· RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://issues.apache.org/bugzilla/show_bug.cgi?id=35714>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND· INSERTED IN THE BUG DATABASE.
http://issues.apache.org/bugzilla/show_bug.cgi?id=35714 Summary: [betwixt] POJO->XML . 'null' reference sin arrays or collection not generated in XML Product: Commons Version: unspecified Platform: Other OS/Version: All Status: NEW Severity: normal Priority: P2 Component: Betwixt AssignedTo: [email protected] ReportedBy: [EMAIL PROTECTED] Hi, I apologise if this is a frequently asked question but I didn't see it answered in the FAQ and 10 minutes of searching didn't show anything. My problem is that I want to be sometimes able to store the fact that for a particular class field there is NO value. Simplified to the extreme: the problem is that I want to present a web user with a list of prompts (descriptions) and the user should type in values or nothing depending on whether or not a value is appropriate or not. I want to store the whole thing as name:value pairs and the order IS important and must be preserved. So I have several options on how to implement this. for example: 1) Using two arrays in parallel - one for the questions and another for the answers. or 2) Using LinkedHashMap or 3) Defining a special place-holder object to represent "Don't know / No comment". I guess I am going to have to use approach 3 unless someone has got an idea of how to make one of the other approaches work. Here is what I tried for 1&2 1) Using two arrays in parallel ------------------------------- I tried declaring an array of Objects (for the moment only holding Strings) for the descriptions and a parallel array of Objects for the values. private Object [] descriptions; private Object [] values; Using this approach Xstream behaves exactly like I want in this respect - it generated a special <null/> tag for array elements containing null values (in this example the first 3 elements of the "values" array contained null references). <descriptions class="string-array"> <string>London-Brussels</string> <string>Brussels-London</string> <string>Air</string> <string>Cost per person</string> <string>Nr. Persons</string> </descriptions> <values> <null/> <null/> <null/> <double>132.11</double> <int>3</int> </values> This conveys the information to my users that a flight London-Brussels return should cost Euro 132.11 per person and that 3 people will be travelling. Trying the same thing with betwixt gave me something like this ... <descriptions class="string-array"> <string>London-Brussels</string> <string>Brussels-London</string> <string>Air</string> <string>Cost per person</string> <string>Nr. Persons</string> </descriptions> <values> <double>132.11</double> <int>3</int> </values> So there is not output for the null values and this destroys the association between the two arrays. 2) Using LinkedHashMap ---------------------- The problem here was that betwixt generated ID references to elements that it never defines. I have listed an abbreviated the code of the class below which contains some test-code in the constructor. The full output is listed below (the output is the result from the test code in the constructor and other test-code in a JUnit testcase which I wrote to test the original parallel array solution). The program serializes a whole tree of objects so the first item that directly illustrates the problem is the element with id="5". Here there seems to be 3 elements for the entries in the LinkedHashMap but the actual data does not seems to be stored anywhere. Other elements reference these elements (which is reasonable since these are constant) but the actual data I wanted to store is not there. public class BudgetLeafItemImpl extends BaseBudgetItemImpl implements BudgetLeafItem { private LinkedHashMap testList = new LinkedHashMap(); private Object [] descriptions; private Object [] values; //... public BudgetLeafItemImpl() { super(); testList.put("Desc1", null); testList.put("Desc2",null); testList.put("Desc3", new Double(123.2)); } // .. get/setters, business logic omitted } <?xml version="1.0"?> <budgetNonLeafItemImpl leaf-item-type="false" mandatory="false" title="A1 Eligible costs" valid="true" id="1"> <children> <child leaf-item-type="false" mandatory="true" title="A1.1 Personnel" valid="true" id="2"> <children/> <setterInterface/> <setterInterfaceNonLeaf/> </child> <child leaf-item-type="false" mandatory="false" title="A1.2 Travel and accomodation" valid="true" id="3"> <children> <child leaf-item-type="false" mandatory="false" title="A1.2.1 Travel" valid="true" id="4"> <children> <child leaf-item-type="true" mandatory="false" title="A1.2.1.1 Travel - London Brussels" valid="true" id="5"> <descriptions> <string>London-Brussels</string> <string>Brussels-London</string> <string>Air</string> <string>Cost per person</string> <string>Nr. Persons</string> </descriptions> <setterInterface/> <testList> <entry id="6"/> <entry id="7"/> <entry id="8"/> </testList> <values> <double>132.11</double> <integer>3</integer> </values> </child> <child leaf-item-type="true" mandatory="false" title="A1.2.1.2 Travel - Amsterdam Brussels" valid="true" id="9"> <descriptions> <string>Brussels-Amsterdam</string> <string>Amsterdam-Brussels</string> <string>Train</string> <string>Cost per person</string> <string>Nr. Persons</string> </descriptions> <setterInterface/> <testList> <entry idref="6"/> <entry idref="7"/> <entry idref="8"/> </testList> <values> <double>100.0</double> <integer>1</integer> </values> </child> </children> <setterInterface/> <setterInterfaceNonLeaf/> </child> </children> <setterInterface/> <setterInterfaceNonLeaf/> </child> <child leaf-item-type="false" mandatory="false" title="A1.3 Implementation costs" valid="true" id="10"> <children> <child leaf-item-type="false" mandatory="false" title="A1.3.1 Implementation costs - Translations" valid="true" id="11"> <children> <child leaf-item-type="true" mandatory="false" title="A1.3.1.1 Translation of questionaire for all member states" valid="true" id="12"> <descriptions> <string>English</string> <string>French</string> <string>Cost per page (Euro)</string> <string>Nr. pages</string> </descriptions> <setterInterface/> <testList> <entry idref="6"/> <entry idref="7"/> <entry idref="8"/> </testList> <values> <double>10.5</double> <integer>10</integer> </values> </child> <child leaf-item-type="true" mandatory="false" title="A1.3.1.1 Translation of questionaire for all member states" valid="true" id="13"> <descriptions> <string>English</string> <string>French</string> <string>Cost per page (Euro)</string> <string>Nr. pages</string> </descriptions> <setterInterface/> <testList> <entry idref="6"/> <entry idref="7"/> <entry idref="8"/> </testList> <values> <double>10.5</double> <integer>10</integer> </values> </child> </children> <setterInterface/> <setterInterfaceNonLeaf/> </child> </children> <setterInterface/> <setterInterfaceNonLeaf/> </child> <child leaf-item-type="false" mandatory="false" title="A1.4 Frais résultant d'exigences de la convention" valid="true" id="14"> <children> <child leaf-item-type="true" mandatory="false" title="A1.4.1 Audit reports" valid="true" id="15"> <descriptions> <string>Audit fees</string> </descriptions> <setterInterface/> <testList> <entry idref="6"/> <entry idref="7"/> <entry idref="8"/> </testList> <values> <double>0.0</double> </values> </child> <child leaf-item-type="true" mandatory="false" title="A1.4.2 Financial guarantee" valid="true" id="16"> <descriptions> <string>Cost of obtaining financial guarantee</string> </descriptions> <setterInterface/> <testList> <entry idref="6"/> <entry idref="7"/> <entry idref="8"/> </testList> <values> <double>0.0</double> </values> </child> </children> <setterInterface/> <setterInterfaceNonLeaf/> </child> <child leaf-item-type="false" mandatory="false" title="A1.7 Indirect and other costs (max 7% of eligible costs)" valid="true" id="17"> <children> <child leaf-item-type="true" mandatory="false" title="A1.7.1 General expenses" valid="true" id="18"> <descriptions> <string>General expenses</string> </descriptions> <setterInterface/> <testList> <entry idref="6"/> <entry idref="7"/> <entry idref="8"/> </testList> <values> <double>0.0</double> </values> </child> </children> <setterInterface/> <setterInterfaceNonLeaf/> </child> </children> <setterInterface/> <setterInterfaceNonLeaf/> </budgetNonLeafItemImpl> The code to generate the XML (a different class) follows: It accepts a budget tree which is a Non-Leaf object (header) which contains a collection of other headers or BudgetLeafItemImpl which represent actual items with costs in the budget. class Lister { ... private String toXML(BudgetNonLeafItem budgTree) { StringWriter xmlOut = new StringWriter(); BeanWriter writer = new BeanWriter(xmlOut); IntrospectionConfiguration cfg = writer.getXMLIntrospector().getConfiguration(); cfg.setAttributesForPrimitives(true); writer.enablePrettyPrint(); writer.getBindingConfiguration().setMapIDs(true); // set a custom name mapper for attributes cfg.setAttributeNameMapper(new HyphenatedNameMapper()); // set a custom name mapper for elements cfg.setElementNameMapper(new DecapitalizeNameMapper()); writer.setWriteEmptyElements(true); // write out the bean String xmlString = null; try { writer.write(budgTree); xmlString = xmlOut.toString(); writer.close(); } catch (Throwable t) { // theoretically possible but unlikely t.printStackTrace(System.err); System.err.println("Error converting budget to xml:" + budgTree); } return xmlString; } } Thanks, Richard Sullivan ps Sorry about the obviously anonymous mail address but I don't want even more spam than I already have thanks ! -- Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug, or are watching the assignee. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
