org.docx4j.jaxb.NamespacePrefixMapperUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of docx4j Show documentation
Show all versions of docx4j Show documentation
docx4j is a library which helps you to work with the Office Open
XML file format as used in docx
documents, pptx presentations, and xlsx spreadsheets.
The newest version!
package org.docx4j.jaxb;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
public class NamespacePrefixMapperUtils {
private static Logger log = LoggerFactory.getLogger(NamespacePrefixMapperUtils.class);
/*
* As from 2010 08 26,
* both com.sun.xml.bind.marshaller.NamespacePrefixMapper
* and com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper
* are provided in the jar JAXB-NamespacePrefixMapperInterfaces.jar
* so that people can build docx4j without needing both JAXB
* implementations.
*
* But if that jar is on their classpath, testing for either
* of these classes will always succeed.
*
* So, we have to test for something else. The following will do:
*
* com.sun.xml.bind.marshaller.MinimumEscapeHandler
* com.sun.xml.internal.bind.marshaller.MinimumEscapeHandler
*/
private static JAXBContext testContext;
private static Object prefixMapper;
private static Object prefixMapperRels;
private static boolean haveTried = false;
public static boolean isJava9orLater() {
return (System.getProperty("java.version").startsWith("9")
|| System.getProperty("java.version").startsWith("10")
|| System.getProperty("java.version").startsWith("11") );
}
public static Object getPrefixMapper() throws JAXBException {
if (prefixMapper!=null) return prefixMapper;
if (haveTried) return null;
// will be true soon..
haveTried = true;
if (Context.getJaxbImplementation() == JAXBImplementation.ECLIPSELINK_MOXy) {
// since 6.1.0
log.info("Using MOXy NamespacePrefixMapper");
prefixMapper = new NamespacePrefixMapperMOXy();
return prefixMapper;
}
if (testContext==null) {
java.lang.ClassLoader classLoader = NamespacePrefixMapperUtils.class.getClassLoader();
testContext = JAXBContext.newInstance("org.docx4j.relationships",classLoader );
}
if (testContext==null) {
throw new JAXBException("Couldn't create context for org.docx4j.relationships. Everything is broken!");
}
Marshaller m=testContext.createMarshaller();
if (isJava9orLater()) {
return tryUsingRI(m);
}
// (new Throwable()).printStackTrace();
if (System.getProperty("java.vendor").contains("Android")) {
log.info("Android .. assuming RI."); // Avoid unwanted Android logging; art logs the full ClassNotFoundException
return tryUsingRI(m);
}
try {
// Assume use of Java 6 implementation (ie not RI)
Class c = Class.forName("org.docx4j.jaxb.NamespacePrefixMapperSunInternal");
m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", c.newInstance() );
log.info("Using NamespacePrefixMapperSunInternal, which is suitable for Java 6");
prefixMapper = c.newInstance();
return prefixMapper;
} catch (java.lang.NoClassDefFoundError notJava6) {
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryUsingRI(m);
} catch (javax.xml.bind.PropertyException notJava6) {
// OpenJDK (1.6.0_23) does this
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryUsingRI(m);
} catch (ClassNotFoundException notJava6) {
// We shouldn't get here on Android, but we may using RI elsewhere
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryUsingRI(m);
} catch (InstantiationException notJava6) {
// We shouldn't get here since Class.forName will have already thrown an exception
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryUsingRI(m);
} catch (IllegalAccessException notJava6) {
// We shouldn't get here since Class.forName will have already thrown an exception
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryUsingRI(m);
}
}
private static Object tryUsingRI(Marshaller m)
throws JAXBException {
try {
// Try RI suitable one
m.setProperty("com.sun.xml.bind.namespacePrefixMapper",
new NamespacePrefixMapper() );
log.info("Using NamespacePrefixMapper, which is suitable for the JAXB RI");
prefixMapper = new NamespacePrefixMapper();
return prefixMapper;
} catch (java.lang.NoClassDefFoundError notRIEither) {
notRIEither.printStackTrace();
log.error("JAXB: neither Reference Implementation nor Java 6 implementation present?", notRIEither);
throw new JAXBException("JAXB: neither Reference Implementation nor Java 6 implementation present?");
} catch (javax.xml.bind.PropertyException notRIEither) {
notRIEither.printStackTrace();
log.error("JAXB: neither Reference Implementation nor Java 6 implementation present?", notRIEither);
throw new JAXBException("JAXB: neither Reference Implementation nor Java 6 implementation present?");
}
}
public static Object getPrefixMapperRelationshipsPart() throws JAXBException {
if (prefixMapperRels!=null) return prefixMapperRels;
if (Context.getJaxbImplementation() == JAXBImplementation.ECLIPSELINK_MOXy) {
// since 6.1.0
log.info("Using MOXy NamespacePrefixMapper");
prefixMapperRels = new NamespacePrefixMapperRelationshipsPartMOXy();
return prefixMapperRels;
}
if (testContext==null) {
java.lang.ClassLoader classLoader = NamespacePrefixMapperUtils.class.getClassLoader();
testContext = JAXBContext.newInstance("org.docx4j.relationships",classLoader );
}
Marshaller m=testContext.createMarshaller();
if (isJava9orLater()) {
return tryRIforRelationshipsPart(m);
}
// (new Throwable()).printStackTrace();
try {
// Assume use of Java 6 implementation (ie not RI)
Class c = Class.forName("org.docx4j.jaxb.NamespacePrefixMapperRelationshipsPartSunInternal");
m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", c.newInstance() );
log.info("Using NamespacePrefixMapperRelationshipsPartSunInternal, which is suitable for Java 6");
prefixMapperRels = c.newInstance();
return prefixMapperRels;
} catch (java.lang.NoClassDefFoundError notJava6) {
// javax.xml.bind.PropertyException
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryRIforRelationshipsPart(m);
} catch (javax.xml.bind.PropertyException notJava6) {
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryRIforRelationshipsPart(m);
} catch (ClassNotFoundException notJava6) {
// We shouldn't get here on Android, but we may using RI elsewhere
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryRIforRelationshipsPart(m);
} catch (InstantiationException notJava6) {
// We shouldn't get here since Class.forName will have already thrown an exception
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryRIforRelationshipsPart(m);
} catch (IllegalAccessException notJava6) {
// We shouldn't get here since Class.forName will have already thrown an exception
log.warn(notJava6.getMessage() + " .. trying RI.");
return tryRIforRelationshipsPart(m);
} }
private static Object tryRIforRelationshipsPart(Marshaller m)
throws JAXBException {
try {
// Try RI suitable one
m.setProperty("com.sun.xml.bind.namespacePrefixMapper",
new NamespacePrefixMapperRelationshipsPart() );
log.info("Using NamespacePrefixMapperRelationshipsPart, which is suitable for the JAXB RI");
prefixMapperRels = new NamespacePrefixMapperRelationshipsPart();
return prefixMapperRels;
} catch (java.lang.NoClassDefFoundError notRIEither) {
notRIEither.printStackTrace();
log.error("JAXB: neither Reference Implementation nor Java 6 implementation present?", notRIEither);
throw new JAXBException("JAXB: neither Reference Implementation nor Java 6 implementation present?");
} catch (javax.xml.bind.PropertyException notRIEither) {
notRIEither.printStackTrace();
log.error("JAXB: neither Reference Implementation nor Java 6 implementation present?", notRIEither);
throw new JAXBException("JAXB: neither Reference Implementation nor Java 6 implementation present?");
}
}
/**
* setProperty on 'com.sun.xml.bind.namespacePrefixMapper' or
* 'com.sun.xml.internal.bind.namespacePrefixMapper', as appropriate,
* depending on whether JAXB reference implementation, or Java 6
* implementation is being used.
*
* @param marshaller
* @param namespacePrefixMapper
* @throws JAXBException
*/
public static void setProperty(Marshaller marshaller, Object namespacePrefixMapper) throws JAXBException {
log.debug("attempting to setProperty on marshaller " + marshaller.getClass().getName() );
try {
if (Context.getJaxbImplementation() == JAXBImplementation.ECLIPSELINK_MOXy) {
marshaller.setProperty("eclipselink.namespace-prefix-mapper",
namespacePrefixMapper );
log.debug("setProperty: eclipselink.namespace-prefix-mapper");
} else if ( namespacePrefixMapper.getClass().getName().equals(
"org.docx4j.jaxb.NamespacePrefixMapper")
|| namespacePrefixMapper.getClass().getName().equals(
"org.docx4j.jaxb.NamespacePrefixMapperRelationshipsPart") ) {
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",
namespacePrefixMapper );
// Reference implementation appears to be present (in endorsed dir?)
log.debug("setProperty: com.sun.xml.bind.namespacePrefixMapper");
// System.out.println("setProperty: com.sun.xml.bind.namespacePrefixMapper");
} else {
// Use JAXB distributed in Java 6 - note 'internal'
// Switch to other mapper
log.debug("attempting to setProperty: com.sun.xml.INTERNAL.bind.namespacePrefixMapper");
marshaller.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", namespacePrefixMapper);
// System.out.println("setProperty: com.sun.xml.INTERNAL.bind.namespacePrefixMapper");
}
} catch (javax.xml.bind.PropertyException e) {
log.error("Couldn't setProperty on marshaller " + marshaller.getClass().getName() );
log.error(e.getMessage(), e);
throw e;
}
}
public static String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) throws JAXBException {
NamespacePrefixMapperInterface namespacePrefixMapper = (NamespacePrefixMapperInterface)getPrefixMapper();
return namespacePrefixMapper.getPreferredPrefix(namespaceUri, suggestion, requirePrefix);
}
private static final String[] EMPTY_STRING = new String[0];
public static String[] getPreDeclaredNamespaceUris(String mcIgnorable) {
if (mcIgnorable==null) {
return EMPTY_STRING;
}
Set entries = new HashSet();
StringTokenizer st = new StringTokenizer(mcIgnorable, " ");
while (st.hasMoreTokens()) {
String prefix = (String) st.nextToken();
String uri = NamespacePrefixMappings.getNamespaceURIStatic(prefix);
if (uri==null) {
log.warn("No mapping for prefix '" + prefix + "'");
} else {
// { "prefix1", "namespace1", "prefix2", "namespace2", ... }
//entries.add(prefix);
entries.add(uri);
}
}
return entries.toArray(new String[entries.size()]);
}
public static Map getPreDeclaredNamespaceMap(String mcIgnorable) {
Map entries = new HashMap();
if (mcIgnorable==null) {
return entries;
}
StringTokenizer st = new StringTokenizer(mcIgnorable, " ");
while (st.hasMoreTokens()) {
String prefix = (String) st.nextToken();
String uri = NamespacePrefixMappings.getNamespaceURIStatic(prefix);
if (uri==null) {
log.warn("No mapping for prefix '" + prefix + "'");
} else {
// { "prefix1", "namespace1", "prefix2", "namespace2", ... }
//entries.add(prefix);
entries.put(prefix, uri);
}
}
return entries;
}
/**
* Word requires all mcIgnorable prefixes to be declared at the document level.
*
* @param mcIgnorable
* @param doc
*/
public static void declareNamespaces(String mcIgnorable, Document doc) {
if (mcIgnorable==null) return;
StringTokenizer st = new StringTokenizer(mcIgnorable, " ");
while (st.hasMoreTokens()) {
String prefix = (String) st.nextToken();
String uri = NamespacePrefixMappings.getNamespaceURIStatic(prefix);
if (uri==null) {
log.warn("No mapping for prefix '" + prefix + "'");
} else {
doc.getDocumentElement().setAttributeNS("http://www.w3.org/2000/xmlns/" ,
"xmlns:" + prefix, uri);
}
}
}
}