001// Copyright 2008 by Basil Vandegriend. All rights reserved. 002 003package com.basilv.examples.jaxb; 004 005import java.io.*; 006import java.net.URL; 007import java.util.*; 008 009import javax.xml.bind.*; 010 011import org.w3c.dom.Node; 012 013/** 014 * Tools for working with the JAXB (XML Binding) library. 015 */ 016public 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}