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 org.apache.log4j.Logger;
030: import org.jdom.Attribute;
031: import org.jdom.Document;
032: import org.jdom.Element;
033: import org.jdom.output.XMLOutputter;
034:
035: import java.io.*;
036: import java.io.File;
037: import java.io.FileWriter;
038: import java.io.StringWriter;
039: import java.io.Writer;
040: import java.lang.reflect.Method;
041: import java.util.ArrayList;
042: import java.util.Collection;
043: import java.util.Iterator;
044: import java.util.List;
045: import java.util.Map;
046:
047: public class Java2XML extends XMLBinder {
048: private static Logger LOG = Logger.getLogger(Java2XML.class);
049:
050: public Java2XML() {
051: }
052:
053: public String write(Object object, String rootTagName)
054: throws Exception {
055: StringWriter writer = new StringWriter();
056: try {
057: write(object, rootTagName, writer);
058: return writer.toString();
059: } finally {
060: writer.close();
061: }
062: }
063:
064: public void write(Object object, String rootTagName, File file)
065: throws Exception {
066: FileWriter fileWriter = new FileWriter(file, false);
067: try {
068: BufferedWriter bufferedWriter = new BufferedWriter(
069: fileWriter);
070: try {
071: new Java2XML().write(object, rootTagName,
072: bufferedWriter);
073: bufferedWriter.flush();
074: fileWriter.flush();
075: } finally {
076: bufferedWriter.close();
077: }
078: } finally {
079: fileWriter.close();
080: }
081: }
082:
083: public void write(Object object, String rootTagName, Writer writer)
084: throws Exception {
085: Document document = new Document(new Element(rootTagName));
086: write(object, document.getRootElement(), specElements(object
087: .getClass()));
088: XMLOutputter xmlOutputter = new XMLOutputter();
089: xmlOutputter.setNewlines(true);
090: xmlOutputter.setIndent(true);
091: xmlOutputter.output(document, writer);
092: }
093:
094: private void write(final Object object, final Element tag,
095: List specElements) throws Exception {
096: try {
097: visit(specElements, new SpecVisitor() {
098: public void tagSpecFound(String xmlName,
099: String javaName, List specChildElements)
100: throws Exception {
101: Collection childTags = new ArrayList();
102: if (javaName != null) {
103: childTags
104: .addAll(writeChildTags(
105: tag,
106: xmlName,
107: getter(object.getClass(),
108: javaName)
109: .invoke(object,
110: new Object[] {}),
111: specifyingTypeExplicitly(fieldClass(setter(
112: object.getClass(),
113: javaName)))));
114: } else {
115: Element childTag = new Element(xmlName);
116: tag.addContent(childTag);
117: childTags.add(childTag);
118: }
119: //The parent may specify additional tags for itself in the
120: // children. [Jon Aquino]
121: for (Iterator i = childTags.iterator(); i.hasNext();) {
122: Element childTag = (Element) i.next();
123: write(object, childTag, specChildElements);
124: }
125: }
126:
127: public void attributeSpecFound(String xmlName,
128: String javaName) throws Exception {
129: writeAttribute(tag, xmlName, getter(
130: object.getClass(), javaName).invoke(object,
131: new Object[] {}));
132: }
133: }, object.getClass());
134: } catch (Exception e) {
135: LOG.error("Java2XML: Exception writing "
136: + object.getClass());
137: throw e;
138: }
139: }
140:
141: private void writeAttribute(Element tag, String name, Object value)
142: throws XMLBinderException {
143: if (value == null) {
144: throw new XMLBinderException("Cannot store null value as "
145: + "attribute. Store as element instead. (" + name
146: + ").");
147: }
148: tag.setAttribute(new Attribute(name, toXML(value)));
149: }
150:
151: private Element writeChildTag(Element tag, String name,
152: Object value, boolean specifyingType) throws Exception {
153: Element childTag = new Element(name);
154: if ((value != null) && specifyingType) {
155: childTag.setAttribute(new Attribute("class", value
156: .getClass().getName()));
157: }
158: if (value == null) {
159: childTag.setAttribute(new Attribute("null", "true"));
160: } else if (hasCustomConverter(value.getClass())) {
161: childTag.setText(toXML(value));
162: } else if (value instanceof Map) {
163: for (Iterator i = ((Map) value).keySet().iterator(); i
164: .hasNext();) {
165: Object key = i.next();
166: Element mappingTag = new Element("mapping");
167: childTag.addContent(mappingTag);
168: writeChildTag(mappingTag, "key", key, true);
169: writeChildTag(mappingTag, "value", ((Map) value)
170: .get(key), true);
171: }
172: } else if (value instanceof Collection) {
173: for (Iterator i = ((Collection) value).iterator(); i
174: .hasNext();) {
175: Object item = i.next();
176: writeChildTag(childTag, "item", item, true);
177: }
178: } else {
179: write(value, childTag, specElements(value.getClass()));
180: }
181: tag.addContent(childTag);
182: return childTag;
183: }
184:
185: private Collection writeChildTags(Element tag, String name,
186: Object value, boolean specifyingType) throws Exception {
187: ArrayList childTags = new ArrayList();
188: if (value instanceof Collection) {
189: //Might or might not need to specify type, depending on how
190: //concrete the setter's parameter is. [Jon Aquino]
191: for (Iterator i = ((Collection) value).iterator(); i
192: .hasNext();) {
193: Object item = i.next();
194: childTags.add(writeChildTag(tag, name, item,
195: specifyingType));
196: }
197: } else {
198: childTags.add(writeChildTag(tag, name, value,
199: specifyingType));
200: }
201: return childTags;
202: }
203:
204: private Method getter(Class fieldClass, String field)
205: throws XMLBinderException {
206: Method[] methods = fieldClass.getMethods();
207: //Exact match first [Jon Aquino]
208: for (int i = 0; i < methods.length; i++) {
209: if (!methods[i].getName().toUpperCase().equals(
210: "GET" + field.toUpperCase())
211: && !methods[i].getName().toUpperCase().equals(
212: "IS" + field.toUpperCase())) {
213: continue;
214: }
215: if (methods[i].getParameterTypes().length != 0) {
216: continue;
217: }
218: return methods[i];
219: }
220: for (int i = 0; i < methods.length; i++) {
221: if (!methods[i].getName().toUpperCase().startsWith(
222: "GET" + field.toUpperCase())
223: && !methods[i].getName().toUpperCase().startsWith(
224: "IS" + field.toUpperCase())) {
225: continue;
226: }
227: if (methods[i].getParameterTypes().length != 0) {
228: continue;
229: }
230: return methods[i];
231: }
232: throw new XMLBinderException(
233: "Could not find getter named like '" + field + "' "
234: + fieldClass);
235: }
236: }
|