UiBinder now uses the ResourceOracle. Includes changes to
GwtResourceEntityResolver to make sure sax does so too.

Patch contributed by markovuksanovic@gmail.com with gentle guidance
from scottb@google.com.

http://gwt-code-reviews.appspot.com/579801

Review by: scottb@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8254 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml b/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml
index 2c239e7..541306a 100644
--- a/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml
+++ b/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml
@@ -16,6 +16,9 @@
 <module>
   <inherits name="com.google.gwt.resources.Resources" />
   
+  <source path="client"/>
+  <source path="resources"/>
+  
   <generate-with class="com.google.gwt.uibinder.rebind.UiBinderGenerator">
     <when-type-assignable class="com.google.gwt.uibinder.client.UiBinder"/>
   </generate-with>
diff --git a/user/src/com/google/gwt/uibinder/rebind/GwtResourceEntityResolver.java b/user/src/com/google/gwt/uibinder/rebind/GwtResourceEntityResolver.java
index c93bb83..e4765f9 100644
--- a/user/src/com/google/gwt/uibinder/rebind/GwtResourceEntityResolver.java
+++ b/user/src/com/google/gwt/uibinder/rebind/GwtResourceEntityResolver.java
@@ -15,85 +15,70 @@
  */
 package com.google.gwt.uibinder.rebind;
 
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.ResourceOracle;
+import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.collect.Sets;
 
 import org.xml.sax.EntityResolver;
 import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
 
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.StringReader;
 import java.util.Collections;
+import java.util.Map;
 import java.util.Set;
 
 /**
- * Does special handling of external entities encountered by sax xml parser,
- * e.g. the uri in
- * 
- * <pre>
- * &lt;!DOCTYPE gwt:UiBinder
-  SYSTEM "http://google-web-toolkit.googlecode.com/files/xhtml.ent"></pre>
+ * Makes the sax xml parser use the {@link ResourceOracle}.
  * <p>
- * Specifically, if the requested uri starts with
- * <code>http://google-web-toolkit.googlecode.com/files</code>, provide the
- * contents from a built in resource rather than allowing sax to make a network
- * request.
+ * Does special case handling of GWT specific DTDs to be fetched from our
+ * download site. If the requested uri starts with
+ * <code>http://dl.google.com/gwt/DTD/</code> (or one or two others), provides
+ * the contents from a built in resource rather than allowing sax to make a
+ * network request.
  */
 class GwtResourceEntityResolver implements EntityResolver {
-  interface ResourceLoader {
-    InputStream fetch(String name);
-  }
-
   private static final Set<String> EXTERNAL_PREFIXES = Collections.unmodifiableSet(Sets.create(new String[] {
       "http://google-web-toolkit.googlecode.com/files/",
-      "http://dl.google.com/gwt/DTD/",
-      "https://dl-ssl.google.com/gwt/DTD/"
-      }));
+      "http://dl.google.com/gwt/DTD/", "https://dl-ssl.google.com/gwt/DTD/"}));
 
   private static final String RESOURCES = "com/google/gwt/uibinder/resources/";
 
-  private final ResourceLoader resourceLoader;
+  private String pathBase;
 
-  public GwtResourceEntityResolver() {
-    this(new ResourceLoader() {
-      public InputStream fetch(String name) {
-        return UiBinderGenerator.class.getClassLoader().getResourceAsStream(
-            name);
-      }
-    });
+  private final ResourceOracle resourceOracle;
+
+  public GwtResourceEntityResolver(ResourceOracle resourceOracle,
+      String pathBase) {
+    this.resourceOracle = resourceOracle;
+    this.pathBase = pathBase;
   }
 
-  /**
-   * For testing.
-   */
-  GwtResourceEntityResolver(ResourceLoader resourceLoader) {
-    this.resourceLoader = resourceLoader;
-  }
-
-  public InputSource resolveEntity(String publicId, String systemId)
-      throws SAXException, IOException {
+  public InputSource resolveEntity(String publicId, String systemId) {
     String matchingPrefix = findMatchingPrefix(systemId);
-    if (matchingPrefix == null) {
-      // Not our problem, return null and sax will find it
-      return null;
+
+    Resource resource = null;
+    Map<String, Resource> map = resourceOracle.getResourceMap();
+    if (matchingPrefix != null) {
+      resource = map.get(RESOURCES
+          + systemId.substring(matchingPrefix.length()));
     }
 
-    String name = RESOURCES
-        + systemId.substring(matchingPrefix.length());
-    InputStream resourceStream = resourceLoader.fetch(name);
-
-    if (resourceStream == null) {
-      /*
-       * They're asking for another DTD resource that we don't short circuit,
-       * Return null and let Sax find it on the interweb.
-       */
-      return null;
+    if (resource == null) {
+      resource = map.get(pathBase + systemId);
     }
 
-    InputSource inputSource = new InputSource(resourceStream);
-    inputSource.setPublicId(publicId);
-    inputSource.setSystemId(systemId);
-    return inputSource;
+    if (resource != null) {
+      String content = Util.readStreamAsString(resource.openContents());
+      InputSource inputSource = new InputSource(new StringReader(content));
+      inputSource.setPublicId(publicId);
+      inputSource.setSystemId(resource.getPath());
+      return inputSource;
+    }
+    /*
+     * Let Sax find it on the interweb.
+     */
+    return null;
   }
 
   private String findMatchingPrefix(String systemId) {
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java
index b8ff3c3..49658b9 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -22,6 +22,9 @@
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.NotFoundException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.ResourceOracle;
+import com.google.gwt.dev.util.Util;
 import com.google.gwt.uibinder.client.UiTemplate;
 import com.google.gwt.uibinder.rebind.messages.MessagesWriter;
 import com.google.gwt.uibinder.rebind.model.ImplicitClientBundle;
@@ -30,7 +33,6 @@
 import org.xml.sax.SAXParseException;
 
 import java.io.PrintWriter;
-import java.net.URL;
 
 /**
  * Generator for implementations of
@@ -60,8 +62,7 @@
     } else {
       templateName = annotation.value();
       if (!templateName.endsWith(TEMPLATE_SUFFIX)) {
-        logger.die("Template file name must end with "
-            + TEMPLATE_SUFFIX);
+        logger.die("Template file name must end with " + TEMPLATE_SUFFIX);
       }
 
       /*
@@ -88,6 +89,8 @@
   public String generate(TreeLogger logger, GeneratorContext genCtx,
       String fqInterfaceName) throws UnableToCompleteException {
     TypeOracle oracle = genCtx.getTypeOracle();
+    ResourceOracle resourceOracle = genCtx.getResourcesOracle();
+
     JClassType interfaceType;
     try {
       interfaceType = oracle.getType(fqInterfaceName);
@@ -103,15 +106,15 @@
 
     if (printWriter != null) {
       generateOnce(interfaceType, implName, printWriter, logger, oracle,
-          writers);
+          resourceOracle, writers);
     }
     return packageName + "." + implName;
   }
 
   private void generateOnce(JClassType interfaceType, String implName,
       PrintWriter binderPrintWriter, TreeLogger treeLogger, TypeOracle oracle,
-      PrintWriterManager writerManager)
- throws UnableToCompleteException {
+      ResourceOracle resourceOracle, PrintWriterManager writerManager)
+      throws UnableToCompleteException {
 
     MortalLogger logger = new MortalLogger(treeLogger);
     String templatePath = deduceTemplateFile(logger, interfaceType);
@@ -119,9 +122,10 @@
         templatePath, interfaceType.getPackage().getName(), implName);
 
     UiBinderWriter uiBinderWriter = new UiBinderWriter(interfaceType, implName,
-        templatePath, oracle, logger, new FieldManager(oracle, logger), messages);
+        templatePath, oracle, logger, new FieldManager(oracle, logger),
+        messages);
 
-    Document doc = getW3cDoc(logger, templatePath);
+    Document doc = getW3cDoc(logger, resourceOracle, templatePath);
 
     uiBinderWriter.parseDocument(doc, binderPrintWriter);
 
@@ -135,16 +139,21 @@
     writerManager.commit();
   }
 
-  private Document getW3cDoc(MortalLogger logger, String templatePath)
+  private Document getW3cDoc(MortalLogger logger,
+      ResourceOracle resourceOracle, String templatePath)
       throws UnableToCompleteException {
-    URL url = UiBinderGenerator.class.getClassLoader().getResource(templatePath);
-    if (null == url) {
+
+    Resource resource = resourceOracle.getResourceMap().get(templatePath);
+
+    if (null == resource) {
       logger.die("Unable to find resource: " + templatePath);
     }
-    
+
     Document doc = null;
     try {
-      doc = new W3cDomHelper(logger.getTreeLogger()).documentFor(url);
+      String content = Util.readStreamAsString(resource.openContents());
+      doc = new W3cDomHelper(logger.getTreeLogger(), resourceOracle).documentFor(content,
+          resource.getPath());
     } catch (SAXParseException e) {
       logger.die("Error parsing XML (line " + e.getLineNumber() + "): "
           + e.getMessage(), e);
diff --git a/user/src/com/google/gwt/uibinder/rebind/W3cDocumentBuilder.java b/user/src/com/google/gwt/uibinder/rebind/W3cDocumentBuilder.java
index 2a19506..d40bfcc 100644
--- a/user/src/com/google/gwt/uibinder/rebind/W3cDocumentBuilder.java
+++ b/user/src/com/google/gwt/uibinder/rebind/W3cDocumentBuilder.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.dev.resource.ResourceOracle;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -45,13 +46,14 @@
   private final Stack<Node> eltStack = new Stack<Node>();
   private Locator locator;
   private final TreeLogger logger;
-  private final GwtResourceEntityResolver resolver = new GwtResourceEntityResolver();
+  private final GwtResourceEntityResolver resolver;
 
-  public W3cDocumentBuilder(TreeLogger logger)
-      throws ParserConfigurationException {
+  public W3cDocumentBuilder(TreeLogger logger, String pathBase,
+      ResourceOracle resourceOracle) throws ParserConfigurationException {
     this.logger = logger;
     document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
     eltStack.push(document);
+    resolver = new GwtResourceEntityResolver(resourceOracle, pathBase);
   }
 
   /**
diff --git a/user/src/com/google/gwt/uibinder/rebind/W3cDomHelper.java b/user/src/com/google/gwt/uibinder/rebind/W3cDomHelper.java
index c17741f..1d3c20e 100644
--- a/user/src/com/google/gwt/uibinder/rebind/W3cDomHelper.java
+++ b/user/src/com/google/gwt/uibinder/rebind/W3cDomHelper.java
@@ -16,6 +16,7 @@
 package com.google.gwt.uibinder.rebind;
 
 import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.ResourceOracle;
 
 import org.w3c.dom.Document;
 import org.xml.sax.InputSource;
@@ -23,9 +24,7 @@
 import org.xml.sax.SAXParseException;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.StringReader;
-import java.net.URL;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
@@ -38,38 +37,31 @@
 public class W3cDomHelper {
   private final SAXParserFactory factory;
   private final TreeLogger logger;
+  private final ResourceOracle resourceOracle;
 
-  public W3cDomHelper(final TreeLogger logger) {
+  public W3cDomHelper(TreeLogger logger, ResourceOracle resourceOracle) {
     this.logger = logger;
+    this.resourceOracle = resourceOracle;
     factory = SAXParserFactory.newInstance();
     factory.setNamespaceAware(true);
   }
 
   /**
-   * Creates an XML document model with the given contents. Nice for testing.
-   * 
-   * @param string the document contents
+   * Creates an XML document model with the given contents.
    */
-  public Document documentFor(String string) throws SAXException, IOException {
+  public Document documentFor(String string, String resourcePath)
+      throws SAXParseException {
     try {
-      W3cDocumentBuilder handler = new W3cDocumentBuilder(logger);
+      if (resourcePath != null) {
+        int pos = resourcePath.lastIndexOf('/');
+        resourcePath = (pos < 0) ? "" : resourcePath.substring(0, pos + 1);
+      }
+      W3cDocumentBuilder handler = new W3cDocumentBuilder(logger, resourcePath,
+          resourceOracle);
       SAXParser parser = factory.newSAXParser();
-      parser.parse(new InputSource(new StringReader(string)), handler);
-      return handler.getDocument();
-    } catch (ParserConfigurationException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  public Document documentFor(URL url) throws SAXParseException {
-    try {
-      W3cDocumentBuilder handler = new W3cDocumentBuilder(logger);
-      SAXParser parser = factory.newSAXParser();
-      InputStream stream = url.openStream();
-      InputSource input = new InputSource(stream);
-      input.setSystemId(url.toExternalForm());
+      InputSource input = new InputSource(new StringReader(string));
+      input.setSystemId(resourcePath);
       parser.parse(input, handler);
-
       return handler.getDocument();
     } catch (SAXParseException e) {
       // Let SAXParseExceptions through.
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java b/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java
index 1e59209..2631426 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java
@@ -22,6 +22,7 @@
 import com.google.gwt.dev.javac.CompilationState;
 import com.google.gwt.dev.javac.CompilationStateBuilder;
 import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.dev.javac.impl.MockResourceOracle;
 import com.google.gwt.dev.resource.Resource;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
 import com.google.gwt.uibinder.attributeparsers.AttributeParsers;
@@ -39,9 +40,8 @@
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
 
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.Set;
@@ -80,7 +80,7 @@
   final JClassType parsedType;
   final MockMortalLogger logger = new MockMortalLogger();
 
-  final W3cDomHelper docHelper = new W3cDomHelper(createLogger());
+  final W3cDomHelper docHelper = new W3cDomHelper(createLogger(), new MockResourceOracle());
   final TypeOracle types;
   final XMLElementProvider elemProvider;
   final MockUiBinderWriter writer;
@@ -117,9 +117,8 @@
     parsedType = types.findType(parsedTypeName);
   }
 
-  public XMLElement getElem(String string, String tag) throws SAXException,
-      IOException {
-    Document doc = docHelper.documentFor(string);
+  public XMLElement getElem(String string, String tag) throws SAXParseException {
+    Document doc = docHelper.documentFor(string, null);
     Element w3cElem = (Element) doc.getDocumentElement().getElementsByTagName(
         tag).item(0);
     Assert.assertNotNull(String.format(
@@ -129,7 +128,7 @@
   }
 
   public FieldWriter parse(String xml) throws UnableToCompleteException,
-      SAXException, IOException {
+      SAXParseException {
 
     StringBuffer b = new StringBuffer();
     b.append("<ui:UiBinder xmlns:ui='" + BINDER_URI + "'");
diff --git a/user/test/com/google/gwt/uibinder/rebind/GwtResourceEntityResolverTest.java b/user/test/com/google/gwt/uibinder/rebind/GwtResourceEntityResolverTest.java
index e251944..385f5f4 100644
--- a/user/test/com/google/gwt/uibinder/rebind/GwtResourceEntityResolverTest.java
+++ b/user/test/com/google/gwt/uibinder/rebind/GwtResourceEntityResolverTest.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2009 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -15,76 +15,68 @@
  */
 package com.google.gwt.uibinder.rebind;
 
+import com.google.gwt.dev.javac.impl.MockResource;
+import com.google.gwt.dev.javac.impl.MockResourceOracle;
+import com.google.gwt.dev.resource.Resource;
+
 import junit.framework.TestCase;
 
 import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-import java.io.IOException;
-import java.io.InputStream;
 
 /**
- * Text of GwtResourceEntityResolver.
+ * Test of GwtResourceEntityResolver.
  */
 public class GwtResourceEntityResolverTest extends TestCase {
-  private static class MockResourceLoader implements
-      GwtResourceEntityResolver.ResourceLoader {
-    InputStream stream;
 
-    public InputStream fetch(String name) {
-      return stream;
-    }
-  }
   private static final String LEGACY_SYSTEM_ID = "http://google-web-toolkit.googlecode.com/files/xhtml.ent";
   private static final String VERSIONED_SYSTEM_ID = "http://dl.google.com/gwt/DTD/2.0.0/xhtml.ent";
   private static final String REDIRECT_SYSTEM_ID = "http://dl.google.com/gwt/DTD/xhtml.ent";
   private static final String SSL_VERSIONED_SYSTEM_ID = "https://dl-ssl.google.com/gwt/DTD/2.0.0/xhtml.ent";
   private static final String SSL_REDIRECT_SYSTEM_ID = "https://dl-ssl.google.com/gwt/DTD/xhtml.ent";
 
-  private GwtResourceEntityResolver resolver;
-  private MockResourceLoader loader;
+  private static final Resource xhtmlEntResource = new MockResource(
+      "com/google/gwt/uibinder/resources/xhtml.ent") {
+    @Override
+    protected CharSequence getContent() {
+      return "";
+    }
+  };
 
-  @Override
-  public void setUp() throws Exception {
-    super.setUp();
-    loader = new MockResourceLoader();
-    resolver = new GwtResourceEntityResolver(loader);
+  private MockResourceOracle oracle = new MockResourceOracle(xhtmlEntResource);
 
-    loader.stream = new InputStream() {
-      @Override
-      public int read() throws IOException {
-        throw new UnsupportedOperationException();
-      }
-    };
+  private GwtResourceEntityResolver resolver = new GwtResourceEntityResolver(
+      oracle, "");
+
+  public void testAlmostCorrectAndOnceWorked() {
+    doExpectNull(LEGACY_SYSTEM_ID.replace("files", "filesss"));
+    doExpectNull(VERSIONED_SYSTEM_ID.replace("DTD", "DTDdddd"));
+    doExpectNull(REDIRECT_SYSTEM_ID.replace("DTD", "DTDdddd"));
   }
 
-  public void testAlmostCorrectAndOnceWorked() throws SAXException, IOException {
-    doBad(LEGACY_SYSTEM_ID.replace("files", "filesss"));
-    doBad(VERSIONED_SYSTEM_ID.replace("DTD", "DTDdddd"));
-    doBad(REDIRECT_SYSTEM_ID.replace("DTD", "DTDdddd"));
-  }
-  
-  public void testNotOurProblem() throws SAXException, IOException {
-    doBad("http://arbitrary");
+  public void testNotOurProblem() {
+    doExpectNull("http://arbitrary");
   }
 
-  public void testVersionedGood() throws SAXException, IOException {
-    doGood(VERSIONED_SYSTEM_ID);
+  public void testHappy() {
     doGood(REDIRECT_SYSTEM_ID);
-    doGood(SSL_VERSIONED_SYSTEM_ID);
     doGood(SSL_REDIRECT_SYSTEM_ID);
     doGood(LEGACY_SYSTEM_ID);
   }
 
-  private void doBad(String url) throws SAXException, IOException {
+  public void testDrillThrough() {
+    doExpectNull(VERSIONED_SYSTEM_ID);
+    doExpectNull(SSL_VERSIONED_SYSTEM_ID);
+  }
+
+  private void doExpectNull(String url) {
     assertNull(resolver.resolveEntity(null, url));
     assertNull(resolver.resolveEntity("meaningless", url));
   }
 
-  private void doGood(String url) throws SAXException, IOException {
+  private void doGood(String url) {
     String publicId = "some old public thing";
     InputSource s = resolver.resolveEntity(publicId, url);
     assertNotNull(s);
     assertEquals(publicId, s.getPublicId());
   }
- }
+}
diff --git a/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java b/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java
index a0a2c6e..3da3af8 100644
--- a/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java
+++ b/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java
@@ -20,6 +20,7 @@
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.dev.javac.CompilationState;
 import com.google.gwt.dev.javac.CompilationStateBuilder;
+import com.google.gwt.dev.javac.impl.MockResourceOracle;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
 import com.google.gwt.uibinder.attributeparsers.AttributeParsers;
 import com.google.gwt.uibinder.elementparsers.NullInterpreter;
@@ -30,9 +31,8 @@
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Text;
-import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
 
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashSet;
 import java.util.Set;
@@ -44,7 +44,7 @@
   private static final String STRING_WITH_DOUBLEQUOTE = "I have a \" quote in me";
 
   private static final W3cDomHelper docHelper = new W3cDomHelper(
-      TreeLogger.NULL);
+      TreeLogger.NULL, new MockResourceOracle());
 
   private static TreeLogger createCompileLogger() {
     PrintWriterTreeLogger logger = new PrintWriterTreeLogger(new PrintWriter(
@@ -54,9 +54,10 @@
   }
 
   private Document doc;
-  private Element item;
-  private XMLElement elm;
   private XMLElementProvider elemProvider;
+  private XMLElement elm;
+  private Element item;
+
   private TypeOracle types;
 
   private MockMortalLogger logger;
@@ -77,7 +78,7 @@
     init("<doc><elm attr1=\"attr1Value\" attr2=\"attr2Value\"/></doc>");
   }
 
-  public void testAssertNoAttributes() throws SAXException, IOException {
+  public void testAssertNoAttributes() throws SAXParseException {
     init("<doc>\n\n<elm yes='true' no='false'>Blah <blah/> blah</elm></doc>");
     assertNull(logger.died);
     try {
@@ -92,7 +93,7 @@
     }
   }
 
-  public void testAssertNoBody() throws SAXException, IOException {
+  public void testAssertNoBody() throws SAXParseException {
     init("<doc>\n\n<elm yes='true' no='false'>Blah <blah/> blah</elm></doc>");
     assertNull(logger.died);
     try {
@@ -105,7 +106,7 @@
     }
   }
 
-  public void testAssertNoText() throws SAXException, IOException {
+  public void testAssertNoText() throws SAXParseException {
     init("<doc>\n\n<elm yes='true' no='false'>Blah <blah/> blah</elm></doc>");
     assertNull(logger.died);
     try {
@@ -118,7 +119,7 @@
     }
   }
 
-  public void testConsumeBoolean() throws SAXException, IOException,
+  public void testConsumeBoolean() throws SAXParseException,
       UnableToCompleteException {
     init("<doc>\n\n<elm yes='true' no='false' "
         + "fnord='fnord' ref='{foo.bar.baz}'/></doc>");
@@ -143,7 +144,7 @@
     }
   }
 
-  public void testConsumeBooleanConstant() throws SAXException, IOException,
+  public void testConsumeBooleanConstant() throws SAXParseException,
       UnableToCompleteException {
     init("<doc>\n\n<elm yes='true' no='false' "
         + "fnord='fnord' ref='{foo.bar.baz}' empty=''/></doc>");
@@ -183,7 +184,7 @@
     }
   }
 
-  public void testConsumeBooleanDefault() throws SAXException, IOException,
+  public void testConsumeBooleanDefault() throws SAXParseException,
       UnableToCompleteException {
     init("<doc>\n\n<elm yes='true' no='false' "
         + "fnord='fnord' ref='{foo.bar.baz}'/></doc>");
@@ -210,8 +211,7 @@
     }
   }
 
-  public void testConsumeChildrenNoTextAllowed() throws SAXException,
-      IOException {
+  public void testConsumeChildrenNoTextAllowed() throws SAXParseException {
     init("<doc>\n\n<elm><child>Hi.</child> Stray text is bad</elm></doc>");
     assertNull(logger.died);
     try {
@@ -267,7 +267,7 @@
   }
 
   public void testConsumeRequiredDouble() throws UnableToCompleteException,
-      SAXException, IOException {
+      SAXParseException {
     init("<doc>\n\n<elm minus='-123.45' plus='123.45' minus-one='-1' "
         + "plus-one='1' fnord='fnord' ref='{foo.bar.baz}'/></doc>");
     assertEquals("1", elm.consumeRequiredDoubleAttribute("plus-one"));
@@ -305,8 +305,8 @@
     }
   }
 
-  public void testConsumeSingleChildElementEmpty() throws SAXException,
-      IOException, UnableToCompleteException {
+  public void testConsumeSingleChildElementEmpty() throws SAXParseException,
+      UnableToCompleteException {
     assertNull(logger.died);
     try {
       elm.consumeSingleChildElement();
@@ -361,8 +361,8 @@
     assertEquals(2, seen.size());
   }
 
-  public void testNoEndTags() throws SAXException, IOException {
-    doc = docHelper.documentFor("<doc><br/></doc>");
+  public void testNoEndTags() throws SAXParseException {
+    doc = docHelper.documentFor("<doc><br/></doc>", null);
     Element documentElement = doc.getDocumentElement();
     Element item = (Element) documentElement.getElementsByTagName("br").item(0);
     XMLElement elm = elemProvider.get(item);
@@ -375,8 +375,8 @@
     item.appendChild(t);
   }
 
-  private void init(final String domString) throws SAXException, IOException {
-    doc = docHelper.documentFor(domString);
+  private void init(final String domString) throws SAXParseException {
+    doc = docHelper.documentFor(domString, null);
     item = (Element) doc.getDocumentElement().getElementsByTagName("elm").item(
         0);
     elm = elemProvider.get(item);