001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI for
003: * visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or modify it under
008: * the terms of the GNU General Public License as published by the Free Software
009: * Foundation; either version 2 of the License, or (at your option) any later
010: * version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
014: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
015: * details.
016: *
017: * You should have received a copy of the GNU General Public License along with
018: * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
019: * Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions Suite #1A 2328 Government Street Victoria BC V8T 5G5 Canada
024: *
025: * (250)385-6040 www.vividsolutions.com
026: */
027: package com.vividsolutions.jump.util.java2xml;
028:
029: import java.io.*;
030: import java.io.File;
031: import java.io.FileReader;
032: import java.io.Reader;
033: import java.io.StringReader;
034: import java.lang.reflect.InvocationTargetException;
035: import java.lang.reflect.Method;
036: import java.util.ArrayList;
037: import java.util.Collection;
038: import java.util.Iterator;
039: import java.util.List;
040: import java.util.Map;
041: import org.jdom.Element;
042: import org.jdom.input.SAXBuilder;
043: import com.vividsolutions.jts.util.Assert;
044: import com.vividsolutions.jump.util.StringUtil;
045:
046: public class XML2Java extends XMLBinder {
047: private ArrayList listeners = new ArrayList();
048: private ClassLoader classLoader = getClass().getClassLoader();
049:
050: public XML2Java() {
051: }
052:
053: public XML2Java(ClassLoader classLoader) {
054: this .classLoader = classLoader;
055: }
056:
057: public Object read(String xml, Class c) throws Exception {
058: StringReader reader = new StringReader(xml);
059: try {
060: return read(reader, c);
061: } finally {
062: reader.close();
063: }
064: }
065:
066: public Object read(Reader reader, Class c) throws Exception {
067: return read(new SAXBuilder().build(reader).getRootElement(), c);
068: }
069:
070: public Object read(File file, Class c) throws Exception {
071: FileReader fileReader = new FileReader(file);
072: try {
073: BufferedReader bufferedReader = new BufferedReader(
074: fileReader);
075: try {
076: return new XML2Java().read(bufferedReader, c);
077: } finally {
078: bufferedReader.close();
079: }
080: } finally {
081: fileReader.close();
082: }
083: }
084:
085: private void read(final Element tag, final Object object,
086: List specElements) throws Exception {
087: Assert.isTrue(tag != null);
088: visit(specElements, new SpecVisitor() {
089: private void fillerTagSpecFound(String xmlName,
090: List specChildElements) throws Exception {
091: if (tag.getChildren(xmlName).size() != 1) {
092: throw new XMLBinderException("Expected 1 <"
093: + xmlName + "> tag but found "
094: + tag.getChildren(xmlName).size());
095: }
096: read(tag.getChild(xmlName), object, specChildElements);
097: }
098:
099: private void normalTagSpecFound(String xmlName,
100: String javaName, List specChildElements)
101: throws Exception {
102: setValuesFromTags(object, setter(object.getClass(),
103: javaName), tag.getChildren(xmlName));
104: //The parent may specify additional tags for itself in the
105: // children. [Jon Aquino]
106: for (Iterator i = tag.getChildren(xmlName).iterator(); i
107: .hasNext();) {
108: Element childTag = (Element) i.next();
109: read(childTag, object, specChildElements);
110: }
111: }
112:
113: public void tagSpecFound(String xmlName, String javaName,
114: List specChildElements) throws Exception {
115: if (javaName == null) {
116: fillerTagSpecFound(xmlName, specChildElements);
117: } else {
118: normalTagSpecFound(xmlName, javaName,
119: specChildElements);
120: }
121: }
122:
123: public void attributeSpecFound(String xmlName,
124: String javaName) throws Exception {
125: if (tag.getAttribute(xmlName) == null) {
126: throw new XMLBinderException("Expected '"
127: + xmlName
128: + "' attribute but found none. Tag = "
129: + tag.getName()
130: + "; Attributes = "
131: + StringUtil.toCommaDelimitedString(tag
132: .getAttributes()));
133: }
134: Method setter = setter(object.getClass(), javaName);
135: setValue(object, setter, toJava(tag.getAttribute(
136: xmlName).getValue(),
137: setter.getParameterTypes()[0]));
138: }
139: }, object.getClass());
140: }
141:
142: private Object read(Element tag, Class c) throws Exception {
143: if (tag.getAttribute("null") != null
144: && tag.getAttributeValue("null").equals("true")) {
145: return null;
146: }
147: if (specifyingTypeExplicitly(c)) {
148: if (tag.getAttribute("class") == null) {
149: throw new XMLBinderException("Expected <"
150: + tag.getName()
151: + "> to have 'class' attribute but found none");
152: }
153: return read(tag, Class.forName(tag
154: .getAttributeValue("class"), true, classLoader));
155: }
156: fireCreatingObject(c);
157: if (hasCustomConverter(c)) {
158: return toJava(tag.getTextTrim(), c);
159: }
160: Object object = c.newInstance();
161: if (object instanceof Map) {
162: for (Iterator i = tag.getChildren().iterator(); i.hasNext();) {
163: Element mappingTag = (Element) i.next();
164: if (!mappingTag.getName().equals("mapping")) {
165: throw new XMLBinderException("Expected <"
166: + tag.getName()
167: + "> to have <mapping> tag but found none");
168: }
169: if (mappingTag.getChildren().size() != 2) {
170: throw new XMLBinderException(
171: "Expected <"
172: + tag.getName()
173: + "> to have 2 tags under <mapping> but found "
174: + mappingTag.getChildren().size());
175: }
176: if (mappingTag.getChildren("key").size() != 1) {
177: throw new XMLBinderException(
178: "Expected <"
179: + tag.getName()
180: + "> to have 1 <key> tag under <mapping> but found "
181: + mappingTag.getChildren("key")
182: .size());
183: }
184: if (mappingTag.getChildren("value").size() != 1) {
185: throw new XMLBinderException(
186: "Expected <"
187: + tag.getName()
188: + "> to have 1 <value> tag under <mapping> but found "
189: + mappingTag.getChildren("key")
190: .size());
191: }
192: ((Map) object).put(read(mappingTag.getChild("key"),
193: Object.class), read(mappingTag
194: .getChild("value"), Object.class));
195: }
196: } else if (object instanceof Collection) {
197: for (Iterator i = tag.getChildren().iterator(); i.hasNext();) {
198: Element itemTag = (Element) i.next();
199: if (!itemTag.getName().equals("item")) {
200: throw new XMLBinderException("Expected <"
201: + tag.getName()
202: + "> to have <item> tag but found none");
203: }
204: ((Collection) object).add(read(itemTag, Object.class));
205: }
206: } else {
207: read(tag, object, specElements(object.getClass()));
208: }
209: return object;
210: }
211:
212: private void fireCreatingObject(Class c) {
213: for (Iterator i = listeners.iterator(); i.hasNext();) {
214: Listener l = (Listener) i.next();
215: l.creatingObject(c);
216: }
217: }
218:
219: public void addListener(Listener listener) {
220: listeners.add(listener);
221: }
222:
223: private void setValuesFromTags(Object object, Method setter,
224: Collection tags) throws Exception {
225: for (Iterator i = tags.iterator(); i.hasNext();) {
226: Element tag = (Element) i.next();
227: setValueFromTag(object, setter, tag);
228: }
229: }
230:
231: private void setValueFromTag(Object object, Method setter,
232: Element tag) throws Exception {
233: setValue(object, setter, read(tag, fieldClass(setter)));
234: }
235:
236: private void setValue(Object object, Method setter, Object value)
237: throws IllegalAccessException, InvocationTargetException {
238: //If you get an InvocationTargetException, check the bottom of the
239: // stack
240: //trace -- you should see the stack trace for the underlying exception.
241: //[Jon Aquino]
242: setter.invoke(object, new Object[] { value });
243: }
244:
245: public static interface Listener {
246: public void creatingObject(Class c);
247: }
248: }
|