Index: trunk/src/org/openstreetmap/josm/data/imagery/GetCapabilitiesParseHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/imagery/GetCapabilitiesParseHelper.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/data/imagery/GetCapabilitiesParseHelper.java	(revision 13901)
@@ -9,9 +9,9 @@
 
 import javax.xml.namespace.QName;
-import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 
 /**
@@ -82,10 +82,5 @@
      */
     public static XMLStreamReader getReader(InputStream in) throws XMLStreamException {
-        XMLInputFactory factory = XMLInputFactory.newInstance();
-        // do not try to load external entities, nor validate the XML
-        factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
-        factory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
-        factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
-        return factory.createXMLStreamReader(in);
+        return XmlUtils.newSafeXMLInputFactory().createXMLStreamReader(in);
     }
 
Index: trunk/src/org/openstreetmap/josm/data/preferences/PreferencesReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/PreferencesReader.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/data/preferences/PreferencesReader.java	(revision 13901)
@@ -21,5 +21,4 @@
 
 import javax.xml.XMLConstants;
-import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
@@ -37,5 +36,5 @@
 import org.openstreetmap.josm.spi.preferences.StringSetting;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.xml.sax.SAXException;
 
@@ -97,5 +96,5 @@
     public static void validateXML(Reader in) throws IOException, SAXException {
         try (CachedFile cf = new CachedFile("resource://data/preferences.xsd"); InputStream xsdStream = cf.getInputStream()) {
-            Schema schema = Utils.newXmlSchemaFactory().newSchema(new StreamSource(xsdStream));
+            Schema schema = XmlUtils.newXmlSchemaFactory().newSchema(new StreamSource(xsdStream));
             Validator validator = schema.newValidator();
             validator.validate(new StreamSource(in));
@@ -127,9 +126,9 @@
     public void parse() throws XMLStreamException, IOException {
         if (reader != null) {
-            this.parser = XMLInputFactory.newInstance().createXMLStreamReader(reader);
+            this.parser = XmlUtils.newSafeXMLInputFactory().createXMLStreamReader(reader);
             doParse();
         } else {
             try (BufferedReader in = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
-                this.parser = XMLInputFactory.newInstance().createXMLStreamReader(in);
+                this.parser = XmlUtils.newSafeXMLInputFactory().createXMLStreamReader(in);
                 doParse();
             }
Index: trunk/src/org/openstreetmap/josm/gui/io/CustomConfigurator.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/CustomConfigurator.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/gui/io/CustomConfigurator.java	(revision 13901)
@@ -35,5 +35,4 @@
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.TransformerFactoryConfigurationError;
 import javax.xml.transform.dom.DOMSource;
@@ -53,4 +52,5 @@
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.w3c.dom.DOMException;
 import org.w3c.dom.Document;
@@ -228,5 +228,5 @@
         try {
             String toXML = Main.pref.toXML(true);
-            DocumentBuilder builder = Utils.newSafeDOMBuilder();
+            DocumentBuilder builder = XmlUtils.newSafeDOMBuilder();
             document = builder.parse(new ByteArrayInputStream(toXML.getBytes(StandardCharsets.UTF_8)));
             exportDocument = builder.newDocument();
@@ -258,5 +258,5 @@
             }
             File f = new File(filename);
-            Transformer ts = TransformerFactory.newInstance().newTransformer();
+            Transformer ts = XmlUtils.newSafeTransformerFactory().newTransformer();
             ts.setOutputProperty(OutputKeys.INDENT, "yes");
             ts.transform(new DOMSource(exportDocument), new StreamResult(f.toURI().getPath()));
@@ -406,5 +406,5 @@
         public void openAndReadXML(InputStream is) {
             try {
-                Document document = Utils.parseSafeDOM(is);
+                Document document = XmlUtils.parseSafeDOM(is);
                 synchronized (CustomConfigurator.class) {
                     processXML(document);
@@ -681,5 +681,5 @@
             Preferences tmpPref = new Preferences();
             try {
-                Transformer xformer = TransformerFactory.newInstance().newTransformer();
+                Transformer xformer = XmlUtils.newSafeTransformerFactory().newTransformer();
                 CharArrayWriter outputWriter = new CharArrayWriter(8192);
                 StreamResult out = new StreamResult(outputWriter);
Index: trunk/src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java	(revision 13901)
@@ -27,4 +27,5 @@
 import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.XmlParsingException;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.w3c.dom.Document;
 import org.xml.sax.SAXException;
@@ -124,5 +125,5 @@
                 throw new OsmApiException(connection.getResponse().getResponseCode(),
                         connection.getResponse().getHeaderField("Error"), null);
-            Document d = Utils.parseSafeDOM(connection.getResponse().getContent());
+            Document d = XmlUtils.parseSafeDOM(connection.getResponse().getContent());
             return OsmServerUserInfoReader.buildFromXML(d);
         } catch (SAXException | ParserConfigurationException e) {
Index: trunk/src/org/openstreetmap/josm/io/Capabilities.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/Capabilities.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/Capabilities.java	(revision 13901)
@@ -14,5 +14,5 @@
 
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -274,5 +274,5 @@
         public static Capabilities parse(InputSource inputSource) throws SAXException, IOException, ParserConfigurationException {
             CapabilitiesParser parser = new CapabilitiesParser();
-            Utils.parseSafeSAX(inputSource, parser);
+            XmlUtils.parseSafeSAX(inputSource, parser);
             return parser.getCapabilities();
         }
Index: trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java	(revision 13901)
@@ -28,4 +28,5 @@
 import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.XmlParsingException;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -92,5 +93,5 @@
             progressMonitor.beginTask(tr("Parsing response from server..."));
             InputSource inputSource = new InputSource(new StringReader(diffUploadResponse));
-            Utils.parseSafeSAX(inputSource, new Parser());
+            XmlUtils.parseSafeSAX(inputSource, new Parser());
         } catch (XmlParsingException e) {
             throw e;
Index: trunk/src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 13901)
@@ -27,5 +27,5 @@
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -582,5 +582,5 @@
         Parser parser = new Parser();
         try {
-            Utils.parseSafeSAX(inputSource, parser);
+            XmlUtils.parseSafeSAX(inputSource, parser);
             return true;
         } catch (SAXException e) {
Index: trunk/src/org/openstreetmap/josm/io/NameFinder.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/NameFinder.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/NameFinder.java	(revision 13901)
@@ -24,4 +24,5 @@
 import org.openstreetmap.josm.tools.UncheckedParseException;
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -89,5 +90,5 @@
         InputSource inputSource = new InputSource(reader);
         NameFinderResultParser parser = new NameFinderResultParser();
-        Utils.parseSafeSAX(inputSource, parser);
+        XmlUtils.parseSafeSAX(inputSource, parser);
         return parser.getResult();
     }
Index: trunk/src/org/openstreetmap/josm/io/NoteReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/NoteReader.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/NoteReader.java	(revision 13901)
@@ -20,5 +20,5 @@
 import org.openstreetmap.josm.data.osm.User;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.openstreetmap.josm.tools.date.DateUtils;
 import org.xml.sax.Attributes;
@@ -216,5 +216,5 @@
         DefaultHandler parser = new Parser();
         try {
-            Utils.parseSafeSAX(inputSource, parser);
+            XmlUtils.parseSafeSAX(inputSource, parser);
         } catch (ParserConfigurationException e) {
             Logging.error(e); // broken SAXException chaining
Index: trunk/src/org/openstreetmap/josm/io/OsmChangesetContentParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmChangesetContentParser.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/OsmChangesetContentParser.java	(revision 13901)
@@ -18,6 +18,6 @@
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.XmlParsingException;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -153,5 +153,5 @@
             progressMonitor.beginTask("");
             progressMonitor.indeterminateSubTask(tr("Parsing changeset content ..."));
-            Utils.parseSafeSAX(source, new Parser());
+            XmlUtils.parseSafeSAX(source, new Parser());
         } catch (XmlParsingException e) {
             throw e;
Index: trunk/src/org/openstreetmap/josm/io/OsmChangesetParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmChangesetParser.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/OsmChangesetParser.java	(revision 13901)
@@ -20,6 +20,6 @@
 import org.openstreetmap.josm.data.osm.User;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.XmlParsingException;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.openstreetmap.josm.tools.date.DateUtils;
 import org.xml.sax.Attributes;
@@ -280,5 +280,5 @@
             progressMonitor.indeterminateSubTask(tr("Parsing list of changesets..."));
             InputSource inputSource = new InputSource(new InvalidXmlCharacterFilter(new InputStreamReader(source, StandardCharsets.UTF_8)));
-            Utils.parseSafeSAX(inputSource, parser.new Parser());
+            XmlUtils.parseSafeSAX(inputSource, parser.new Parser());
             return parser.getChangesets();
         } catch (ParserConfigurationException | SAXException e) {
Index: trunk/src/org/openstreetmap/josm/io/OsmHistoryReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmHistoryReader.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/OsmHistoryReader.java	(revision 13901)
@@ -17,5 +17,5 @@
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -92,5 +92,5 @@
         progressMonitor.beginTask(tr("Parsing OSM history data ..."));
         try {
-            Utils.parseSafeSAX(inputSource, new Parser());
+            XmlUtils.parseSafeSAX(inputSource, new Parser());
         } catch (ParserConfigurationException e) {
             Logging.error(e); // broken SAXException chaining
Index: trunk/src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 13901)
@@ -17,5 +17,4 @@
 
 import javax.xml.stream.Location;
-import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
@@ -29,5 +28,4 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.DownloadPolicy;
-import org.openstreetmap.josm.data.osm.UploadPolicy;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.NodeData;
@@ -38,4 +36,5 @@
 import org.openstreetmap.josm.data.osm.RelationMemberData;
 import org.openstreetmap.josm.data.osm.Tagged;
+import org.openstreetmap.josm.data.osm.UploadPolicy;
 import org.openstreetmap.josm.data.osm.User;
 import org.openstreetmap.josm.data.osm.Way;
@@ -47,4 +46,5 @@
 import org.openstreetmap.josm.tools.UncheckedParseException;
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.openstreetmap.josm.tools.date.DateUtils;
 
@@ -619,9 +619,5 @@
 
             try (InputStreamReader ir = UTFInputStreamReader.create(source)) {
-                XMLInputFactory factory = XMLInputFactory.newInstance();
-                // do not try to load external entities
-                factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
-                factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
-                setParser(factory.createXMLStreamReader(ir));
+                setParser(XmlUtils.newSafeXMLInputFactory().createXMLStreamReader(ir));
                 parse();
             }
Index: trunk/src/org/openstreetmap/josm/io/OsmServerReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 13901)
@@ -25,4 +25,5 @@
 import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.XmlParsingException;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
@@ -503,5 +504,5 @@
             monitor.indeterminateSubTask(subtask);
             try (InputStream in = getInputStream(api, monitor.createSubTaskMonitor(1, true), reason)) {
-                return parser.parse(Utils.parseSafeDOM(in));
+                return parser.parse(XmlUtils.parseSafeDOM(in));
             }
         } catch (OsmTransferException e) {
Index: trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(revision 13901)
@@ -28,4 +28,5 @@
 import org.openstreetmap.josm.tools.MultiMap;
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -97,5 +98,5 @@
                     .getContentReader()) {
                 InputSource is = new InputSource(in);
-                Utils.parseSafeSAX(is, parser);
+                XmlUtils.parseSafeSAX(is, parser);
                 return parser.entries;
             }
Index: trunk/src/org/openstreetmap/josm/io/session/SessionReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 13901)
@@ -48,4 +48,5 @@
 import org.openstreetmap.josm.tools.MultiMap;
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -742,5 +743,5 @@
 
         try {
-            parseJos(Utils.parseSafeDOM(josIS), progressMonitor);
+            parseJos(XmlUtils.parseSafeDOM(josIS), progressMonitor);
         } catch (SAXException e) {
             throw new IllegalDataException(e);
Index: trunk/src/org/openstreetmap/josm/io/session/SessionWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/SessionWriter.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/io/session/SessionWriter.java	(revision 13901)
@@ -23,5 +23,4 @@
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
@@ -46,4 +45,5 @@
 import org.openstreetmap.josm.tools.MultiMap;
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -206,5 +206,5 @@
         DocumentBuilder builder = null;
         try {
-            builder = Utils.newSafeDOMBuilder();
+            builder = XmlUtils.newSafeDOMBuilder();
         } catch (ParserConfigurationException e) {
             throw new IOException(e);
@@ -311,6 +311,5 @@
             OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
             writer.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
-            TransformerFactory transfac = TransformerFactory.newInstance();
-            Transformer trans = transfac.newTransformer();
+            Transformer trans = XmlUtils.newSafeTransformerFactory().newTransformer();
             trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
             trans.setOutputProperty(OutputKeys.INDENT, "yes");
Index: trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 13901)
@@ -1267,5 +1267,5 @@
     private static String getImgUrlFromWikiInfoPage(final String base, final String fn) {
         try {
-            final XMLReader parser = Utils.newSafeSAXParser().getXMLReader();
+            final XMLReader parser = XmlUtils.newSafeSAXParser().getXMLReader();
             parser.setContentHandler(new DefaultHandler() {
                 @Override
Index: trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 13901)
@@ -67,12 +67,8 @@
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
-import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
 import javax.xml.validation.SchemaFactory;
-import javax.xml.validation.SchemaFactoryConfigurationError;
 
 import org.openstreetmap.josm.spi.preferences.Config;
@@ -1339,21 +1335,10 @@
      * Returns the W3C XML Schema factory implementation. Robust method dealing with ContextClassLoader problems.
      * @return the W3C XML Schema factory implementation
+     * @deprecated Use {@link XmlUtils#newXmlSchemaFactory}
      * @since 13715
      */
+    @Deprecated
     public static SchemaFactory newXmlSchemaFactory() {
-        try {
-            return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-        } catch (SchemaFactoryConfigurationError e) {
-            Logging.debug(e);
-            // Can happen with icedtea-web. Use workaround from https://issues.apache.org/jira/browse/GERONIMO-6185
-            Thread currentThread = Thread.currentThread();
-            ClassLoader old = currentThread.getContextClassLoader();
-            currentThread.setContextClassLoader(null);
-            try {
-                return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-            } finally {
-                currentThread.setContextClassLoader(old);
-            }
-        }
+        return XmlUtils.newXmlSchemaFactory();
     }
 
@@ -1362,12 +1347,10 @@
      * @return a new secure DOM builder, supporting XML namespaces
      * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
+     * @deprecated Use {@link XmlUtils#newSafeDOMBuilder}
      * @since 10404
      */
+    @Deprecated
     public static DocumentBuilder newSafeDOMBuilder() throws ParserConfigurationException {
-        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
-        builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-        builderFactory.setNamespaceAware(true);
-        builderFactory.setValidating(false);
-        return builderFactory.newDocumentBuilder();
+        return XmlUtils.newSafeDOMBuilder();
     }
 
@@ -1381,14 +1364,10 @@
      * @throws IOException if any IO errors occur.
      * @throws SAXException for SAX errors.
+     * @deprecated Use {@link XmlUtils#parseSafeDOM}
      * @since 10404
      */
+    @Deprecated
     public static Document parseSafeDOM(InputStream is) throws ParserConfigurationException, IOException, SAXException {
-        long start = System.currentTimeMillis();
-        Logging.debug("Starting DOM parsing of {0}", is);
-        Document result = newSafeDOMBuilder().parse(is);
-        if (Logging.isDebugEnabled()) {
-            Logging.debug("DOM parsing done in {0}", getDurationString(System.currentTimeMillis() - start));
-        }
-        return result;
+        return XmlUtils.parseSafeDOM(is);
     }
 
@@ -1398,11 +1377,10 @@
      * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
      * @throws SAXException for SAX errors.
+     * @deprecated Use {@link XmlUtils#newSafeSAXParser}
      * @since 8287
      */
+    @Deprecated
     public static SAXParser newSafeSAXParser() throws ParserConfigurationException, SAXException {
-        SAXParserFactory parserFactory = SAXParserFactory.newInstance();
-        parserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-        parserFactory.setNamespaceAware(true);
-        return parserFactory.newSAXParser();
+        return XmlUtils.newSafeSAXParser();
     }
 
@@ -1416,13 +1394,10 @@
      * @throws SAXException for SAX errors.
      * @throws IOException if any IO errors occur.
+     * @deprecated Use {@link XmlUtils#parseSafeSAX}
      * @since 8347
      */
+    @Deprecated
     public static void parseSafeSAX(InputSource is, DefaultHandler dh) throws ParserConfigurationException, SAXException, IOException {
-        long start = System.currentTimeMillis();
-        Logging.debug("Starting SAX parsing of {0} using {1}", is, dh);
-        newSafeSAXParser().parse(is, dh);
-        if (Logging.isDebugEnabled()) {
-            Logging.debug("SAX parsing done in {0}", getDurationString(System.currentTimeMillis() - start));
-        }
+        XmlUtils.parseSafeSAX(is, dh);
     }
 
Index: trunk/src/org/openstreetmap/josm/tools/XmlObjectParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/XmlObjectParser.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/tools/XmlObjectParser.java	(revision 13901)
@@ -245,5 +245,5 @@
     private Iterable<Object> start(final Reader in, final ContentHandler contentHandler) throws SAXException, IOException {
         try {
-            XMLReader reader = Utils.newSafeSAXParser().getXMLReader();
+            XMLReader reader = XmlUtils.newSafeSAXParser().getXMLReader();
             reader.setContentHandler(contentHandler);
             try {
@@ -285,5 +285,5 @@
      */
     public Iterable<Object> startWithValidation(final Reader in, String namespace, String schemaSource) throws SAXException {
-        SchemaFactory factory = Utils.newXmlSchemaFactory();
+        SchemaFactory factory = XmlUtils.newXmlSchemaFactory();
         try (CachedFile cf = new CachedFile(schemaSource); InputStream mis = cf.getInputStream()) {
             Schema schema = factory.newSchema(new StreamSource(mis));
Index: trunk/src/org/openstreetmap/josm/tools/XmlUtils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/XmlUtils.java	(revision 13901)
+++ trunk/src/org/openstreetmap/josm/tools/XmlUtils.java	(revision 13901)
@@ -0,0 +1,143 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.tools;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.SchemaFactoryConfigurationError;
+
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * XML utils, mainly used to construct safe factories.
+ * @since 13901
+ */
+public final class XmlUtils {
+
+    private XmlUtils() {
+        // Hide default constructor for utils classes
+    }
+
+    /**
+     * Returns the W3C XML Schema factory implementation. Robust method dealing with ContextClassLoader problems.
+     * @return the W3C XML Schema factory implementation
+     */
+    public static SchemaFactory newXmlSchemaFactory() {
+        try {
+            return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        } catch (SchemaFactoryConfigurationError e) {
+            Logging.debug(e);
+            // Can happen with icedtea-web. Use workaround from https://issues.apache.org/jira/browse/GERONIMO-6185
+            Thread currentThread = Thread.currentThread();
+            ClassLoader old = currentThread.getContextClassLoader();
+            currentThread.setContextClassLoader(null);
+            try {
+                return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            } finally {
+                currentThread.setContextClassLoader(old);
+            }
+        }
+    }
+
+    /**
+     * Returns a new secure DOM builder, supporting XML namespaces.
+     * @return a new secure DOM builder, supporting XML namespaces
+     * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
+     */
+    public static DocumentBuilder newSafeDOMBuilder() throws ParserConfigurationException {
+        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+        builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        builderFactory.setNamespaceAware(true);
+        builderFactory.setValidating(false);
+        return builderFactory.newDocumentBuilder();
+    }
+
+    /**
+     * Parse the content given {@link InputStream} as XML.
+     * This method uses a secure DOM builder, supporting XML namespaces.
+     *
+     * @param is The InputStream containing the content to be parsed.
+     * @return the result DOM document
+     * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
+     * @throws IOException if any IO errors occur.
+     * @throws SAXException for SAX errors.
+     */
+    public static Document parseSafeDOM(InputStream is) throws ParserConfigurationException, IOException, SAXException {
+        long start = System.currentTimeMillis();
+        Logging.debug("Starting DOM parsing of {0}", is);
+        Document result = newSafeDOMBuilder().parse(is);
+        if (Logging.isDebugEnabled()) {
+            Logging.debug("DOM parsing done in {0}", Utils.getDurationString(System.currentTimeMillis() - start));
+        }
+        return result;
+    }
+
+    /**
+     * Returns a new secure SAX parser, supporting XML namespaces.
+     * @return a new secure SAX parser, supporting XML namespaces
+     * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
+     * @throws SAXException for SAX errors.
+     */
+    public static SAXParser newSafeSAXParser() throws ParserConfigurationException, SAXException {
+        SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+        parserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        parserFactory.setNamespaceAware(true);
+        return parserFactory.newSAXParser();
+    }
+
+    /**
+     * Parse the content given {@link org.xml.sax.InputSource} as XML using the specified {@link org.xml.sax.helpers.DefaultHandler}.
+     * This method uses a secure SAX parser, supporting XML namespaces.
+     *
+     * @param is The InputSource containing the content to be parsed.
+     * @param dh The SAX DefaultHandler to use.
+     * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
+     * @throws SAXException for SAX errors.
+     * @throws IOException if any IO errors occur.
+     */
+    public static void parseSafeSAX(InputSource is, DefaultHandler dh) throws ParserConfigurationException, SAXException, IOException {
+        long start = System.currentTimeMillis();
+        Logging.debug("Starting SAX parsing of {0} using {1}", is, dh);
+        newSafeSAXParser().parse(is, dh);
+        if (Logging.isDebugEnabled()) {
+            Logging.debug("SAX parsing done in {0}", Utils.getDurationString(System.currentTimeMillis() - start));
+        }
+    }
+
+    /**
+     * Returns a new secure {@link XMLInputFactory}.
+     * @return a new secure {@code XMLInputFactory}, for which external entities are not loaded
+     */
+    public static XMLInputFactory newSafeXMLInputFactory() {
+        XMLInputFactory factory = XMLInputFactory.newInstance();
+        // do not try to load external entities, nor validate the XML
+        factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
+        factory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
+        factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+        return factory;
+    }
+
+    /**
+     * Returns a new secure {@link TransformerFactory}.
+     * @return a new secure {@link TransformerFactory}
+     * @throws TransformerConfigurationException if the factory or the Transformers or Templates it creates cannot support this feature.
+     */
+    public static TransformerFactory newSafeTransformerFactory() throws TransformerConfigurationException {
+        TransformerFactory factory = TransformerFactory.newInstance();
+        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        return factory;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportSender.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportSender.java	(revision 13897)
+++ trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportSender.java	(revision 13901)
@@ -22,4 +22,5 @@
 import org.openstreetmap.josm.tools.OpenBrowser;
 import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.XmlUtils;
 import org.w3c.dom.Document;
 import org.xml.sax.SAXException;
@@ -127,5 +128,5 @@
 
             try (InputStream in = connection.getContent()) {
-                return retrieveDebugToken(Utils.parseSafeDOM(in));
+                return retrieveDebugToken(XmlUtils.parseSafeDOM(in));
             }
         } catch (IOException | SAXException | ParserConfigurationException | XPathExpressionException t) {
