001 // Copyright 2008 by Basil Vandegriend. All rights reserved.
002
003 package com.basilv.examples.jaxb;
004
005 import java.io.*;
006 import java.net.URL;
007 import java.util.*;
008
009 import javax.xml.bind.*;
010
011 import org.w3c.dom.Node;
012
013 /**
014 * Tools for working with the JAXB (XML Binding) library.
015 */
016 public class XmlBindingTools
017 {
018 /**
019 * Parse the XML supplied by the reader into the
020 * corresponding tree of Java objects.
021 *
022 * @param reader Cannot be null. The source of the XML.
023 * @param rootElementClass Cannot be null. The type of the
024 * root element.
025 * @return the Java object that is the root of the tree,
026 * of type rootElement.
027 * @throws JAXBException if an error occurs parsing the
028 * XML.
029 */
030 @SuppressWarnings("unchecked")
031 public static <E extends Object> E parseXML(
032 Reader reader, Class<E> rootElementClass)
033 throws JAXBException {
034
035 if (rootElementClass == null)
036 throw new IllegalArgumentException("rootElementClass is null");
037 if (reader == null)
038 throw new IllegalArgumentException("reader is null");
039
040 JAXBContext context = JAXBContext.newInstance(rootElementClass);
041 Unmarshaller unmarshaller = context.createUnmarshaller();
042
043 CollectingValidationEventHandler handler =
044 new CollectingValidationEventHandler();
045 unmarshaller.setEventHandler(handler);
046
047 E object = (E) unmarshaller.unmarshal(reader);
048 if (!handler.getMessages().isEmpty()) {
049 String errorMessage = "XML parse errors:";
050 for (String message : handler.getMessages()) {
051 errorMessage += "\n" + message;
052 }
053 throw new JAXBException(errorMessage);
054 }
055
056 return object;
057 }
058
059 /**
060 * Generate XML using the supplied root element as the
061 * root of the object tree and write the resulting XML to
062 * the specified writer
063 *
064 * @param rootElement Cannot be null.
065 * @param writer Cannot be null.
066 * @throws JAXBException
067 */
068 public static void generateXML(Object rootElement,
069 Writer writer) throws JAXBException {
070
071 if (rootElement == null)
072 throw new IllegalArgumentException("rootElement is null");
073 if (writer == null)
074 throw new IllegalArgumentException("writer is null");
075
076 JAXBContext context = JAXBContext.newInstance(rootElement.getClass());
077 Marshaller marshaller = context.createMarshaller();
078 marshaller.setProperty(
079 Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
080 marshaller.marshal(rootElement, writer);
081 }
082
083 private static class CollectingValidationEventHandler
084 implements ValidationEventHandler
085 {
086 private List<String> messages = new ArrayList<String>();
087
088 public List<String> getMessages() {
089 return messages;
090 }
091
092 public boolean handleEvent(ValidationEvent event) {
093 if (event == null)
094 throw new IllegalArgumentException("event is null");
095
096 // calculate the severity prefix and return value
097 String severity = null;
098 boolean continueParsing = false;
099 switch (event.getSeverity()) {
100 case ValidationEvent.WARNING:
101 severity = "Warning";
102 continueParsing = true; // continue after warnings
103 break;
104 case ValidationEvent.ERROR:
105 severity = "Error";
106 continueParsing = true; // terminate after errors
107 break;
108 case ValidationEvent.FATAL_ERROR:
109 severity = "Fatal error";
110 continueParsing = false; // terminate after fatal errors
111 break;
112 default:
113 assert false : "Unknown severity.";
114 }
115
116 String location = getLocationDescription(event);
117 String message = severity + " parsing " + location
118 + " due to " + event.getMessage();
119 messages.add(message);
120
121 return continueParsing;
122 }
123
124 private String getLocationDescription(ValidationEvent event) {
125 ValidationEventLocator locator = event.getLocator();
126 if (locator == null) {
127 return "XML with location unavailable";
128 }
129
130 StringBuffer msg = new StringBuffer();
131 URL url = locator.getURL();
132 Object obj = locator.getObject();
133 Node node = locator.getNode();
134 int line = locator.getLineNumber();
135
136 if (url != null || line != -1) {
137 msg.append("line " + line);
138 if (url != null) msg.append(" of " + url);
139 } else if (obj != null) {
140 msg.append(" obj: " + obj.toString());
141 } else if (node != null) {
142 msg.append(" node: " + node.toString());
143 }
144
145 return msg.toString();
146 }
147 }
148 }