From b52216a91d13382cc496432f7aca55b4c778bac4 Mon Sep 17 00:00:00 2001 From: mdb Date: Sat, 17 Nov 2001 03:45:52 +0000 Subject: [PATCH] Created SetFieldRule which allows the XML Digester to set public fields on objects with automatic conversion from a string to the appropriate field type (currently supports int, Integer, String, int[] and String[]). git-svn-id: https://samskivert.googlecode.com/svn/trunk@454 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../java/com/samskivert/xml/SetFieldRule.java | 139 ++++++++++++++++++ .../tests/rsrc/xml/setfieldtest.xml | 7 + .../com/samskivert/xml/SetFieldRuleTest.java | 107 ++++++++++++++ 3 files changed, 253 insertions(+) create mode 100644 projects/samskivert/src/java/com/samskivert/xml/SetFieldRule.java create mode 100644 projects/samskivert/tests/rsrc/xml/setfieldtest.xml create mode 100644 projects/samskivert/tests/src/java/com/samskivert/xml/SetFieldRuleTest.java diff --git a/projects/samskivert/src/java/com/samskivert/xml/SetFieldRule.java b/projects/samskivert/src/java/com/samskivert/xml/SetFieldRule.java new file mode 100644 index 00000000..a6103364 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/xml/SetFieldRule.java @@ -0,0 +1,139 @@ +// +// $Id: SetFieldRule.java,v 1.1 2001/11/17 03:45:52 mdb Exp $ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2001 Walter Korman +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.xml; + +import java.lang.reflect.Field; +import java.util.HashMap; + +import org.xml.sax.Attributes; +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.Rule; + +import com.samskivert.util.StringUtil; + +/** + * Sets a field in the object on the top of the stack with a value parsed + * from the body of an element. + */ +public class SetFieldRule extends Rule +{ + /** + * Constructs a set field rule for the specified field. + */ + public SetFieldRule (Digester digester, String fieldName) + { + super(digester); + + // keep this for later + _fieldName = fieldName; + } + + public void body (String bodyText) + throws Exception + { + _bodyText = bodyText.trim(); + } + + public void end () + throws Exception + { + // make sure we've got something to set + if (StringUtil.blank(_bodyText)) { + if (digester.getDebug() >= 3) { + digester.log(" Skipping set field for lack of " + + "body text [field=" + _fieldName + "]."); + } + return; + } + + Object top = digester.peek(); + if (digester.getDebug() >= 1) { + digester.log(" Setting '" + _fieldName + "' to '" + + _bodyText + "' on '" + top + "'."); + } + + Field field = top.getClass().getField(_fieldName); + + // look up an argument parser for the field type + Parser parser = (Parser)_parsers.get(field.getType()); + if (parser == null) { + String errmsg = "Don't know how to convert strings into " + + "fields of type '" + field.getType() + + "' [field=" + _fieldName + ", target=" + top + "]."; + throw new Exception(errmsg); + } + + // parse the text and set the field + field.set(top, parser.parse(_bodyText)); + } + + protected static interface Parser + { + public Object parse (String source) throws Exception; + } + + protected String _fieldName; + protected String _bodyText; + + protected static HashMap _parsers; + + protected static final int[] INT_ARRAY_PROTOTYPE = new int[0]; + protected static final String[] STRING_ARRAY_PROTOTYPE = new String[0]; + + static { + _parsers = new HashMap(); + + // we can parse strings + _parsers.put(String.class, new Parser() { + public Object parse (String source) throws Exception { + return source; + } + }); + + // and ints + _parsers.put(Integer.TYPE, new Parser() { + public Object parse (String source) throws Exception { + return Integer.valueOf(source); + } + }); + + // and integers + _parsers.put(Integer.class, new Parser() { + public Object parse (String source) throws Exception { + return Integer.valueOf(source); + } + }); + + // and int arrays + _parsers.put(INT_ARRAY_PROTOTYPE.getClass(), new Parser() { + public Object parse (String source) throws Exception { + return StringUtil.parseIntArray(source); + } + }); + + // and string arrays, oh my! + _parsers.put(STRING_ARRAY_PROTOTYPE.getClass(), new Parser() { + public Object parse (String source) throws Exception { + return StringUtil.parseStringArray(source); + } + }); + } +} diff --git a/projects/samskivert/tests/rsrc/xml/setfieldtest.xml b/projects/samskivert/tests/rsrc/xml/setfieldtest.xml new file mode 100644 index 00000000..59309b24 --- /dev/null +++ b/projects/samskivert/tests/rsrc/xml/setfieldtest.xml @@ -0,0 +1,7 @@ + + 5 + howdy partner! + 15 + 1, 2, 3, 4, 5 + one, two, three, four, five + diff --git a/projects/samskivert/tests/src/java/com/samskivert/xml/SetFieldRuleTest.java b/projects/samskivert/tests/src/java/com/samskivert/xml/SetFieldRuleTest.java new file mode 100644 index 00000000..177b7b40 --- /dev/null +++ b/projects/samskivert/tests/src/java/com/samskivert/xml/SetFieldRuleTest.java @@ -0,0 +1,107 @@ +// +// $Id: SetFieldRuleTest.java,v 1.1 2001/11/17 03:45:52 mdb Exp $ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2001 Michael Bayne +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.xml; + +import java.io.InputStream; +import java.io.FileInputStream; + +import junit.framework.Test; +import junit.framework.TestCase; + +import org.apache.commons.digester.Digester; + +import com.samskivert.Log; +import com.samskivert.test.TestUtil; +import com.samskivert.util.StringUtil; + +public class SetFieldRuleTest extends TestCase +{ + public SetFieldRuleTest () + { + super(SetFieldRuleTest.class.getName()); + } + + public static class TestObject + { + public int intField; + public String stringField; + public Integer integerField; + public int[] intArrayField; + public String[] stringArrayField; + + public String toString () + { + return "[intField=" + intField + ", stringField=" + stringField + + ", integerField=" + integerField + + ", intArrayField=" + StringUtil.toString(intArrayField) + + ", stringArrayField=" + StringUtil.toString(stringArrayField) + + "]"; + } + } + + public void runTest () + { + Digester digester = new Digester(); + + // create our object and push it onto the digester + TestObject object = new TestObject(); + digester.push(object); + + // set up some rules + digester.addRule("object/intField", + new SetFieldRule(digester, "intField")); + digester.addRule("object/stringField", + new SetFieldRule(digester, "stringField")); + digester.addRule("object/integerField", + new SetFieldRule(digester, "integerField")); + digester.addRule("object/intArrayField", + new SetFieldRule(digester, "intArrayField")); + digester.addRule("object/stringArrayField", + new SetFieldRule(digester, "stringArrayField")); + + try { + String xmlpath = TestUtil.getResourcePath("xml/setfieldtest.xml"); + InputStream input = new FileInputStream(xmlpath); + digester.parse(input); + input.close(); + } catch (Exception e) { + fail("Parsing failed: " + e); + } + + assert(EXPECTED.equals(object.toString())); + } + + public static Test suite () + { + return new SetFieldRuleTest(); + } + + public static void main (String[] args) + { + SetFieldRuleTest test = new SetFieldRuleTest(); + test.runTest(); + } + + protected static final String EXPECTED = + "[intField=5, stringField=howdy partner!, integerField=15, " + + "intArrayField=(1, 2, 3, 4, 5), " + + "stringArrayField=(one, two, three, four, five)]"; +}