¿Cómo puedo saber qué implementación de JAXP está en uso y desde dónde se cargó?


Me gustaría proporcionar información de diagnóstico sobre qué implementación de JAXP está en uso y desde qué archivo JAR se cargó.

Una forma de lograr esto es crear en instancia de, por ejemplo, un DocumentBuilderFactory, y luego inspeccionar las propiedades de esa clase:

private static String GetJaxpImplementation() {
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    Class<? extends DocumentBuilderFactory> c = documentBuilderFactory.getClass();
    Package p = c.getPackage();
    CodeSource source = c.getProtectionDomain().getCodeSource();
    return MessageFormat.format(
            "Using JAXP implementation ''{0}'' ({1}) version {2} ({3}){4}",
            p.getName(),
            p.getImplementationVendor(),
            p.getSpecificationVersion(),
            p.getImplementationVersion(),
            source == null ? "." : " loaded from: " + source.getLocation());
}

¿Hay una mejor manera de lograr esto, tal vez sin tener que crear un DocumentBuilderFactory?

Author: Daniel Fortunov, 2009-11-25

5 answers

Es bastante difícil predecir qué implementación concreta de fábrica de JAXP se cargará sin crear realmente una instancia debido al proceso para seleccionar una implementación.

Del FAQ Oficial del JAXP (Pregunta 14):

Cuando una aplicación quiere crear una nuevo JAXP DocumentBuilderFactory instancia, llama al método staic DocumentBuilderFactory.newInstance(). Esto provoca una búsqueda por el nombre de un subclase de hormigón de DocumentBuilderFactory usando el siguiente orden:

  1. El valor de una propiedad del sistema como javax.xml.parsers.DocumentBuilderFactory si existe y es accesible.
  2. El contenido del archivo $JAVA_HOME/jre/lib/jaxp.properties si existe.
  3. El mecanismo de detección del Proveedor de Servicios Jar especificado en la especificación del archivo Jar. Un archivo jar puede tener un recurso (es decir, un archivo incrustado) como META-INF/services/javax.xml.parsers.DocumentBuilderFactory que contiene el nombre de la clase concreta a instanciar.
  4. La implementación predeterminada de la plataforma de reserva.

Añadiendo a esta complejidad, cada la fábrica individual de JAXP puede tener una implementación independiente especificada. Es común usar una implementación de analizador sintáctico y otra implementación XSLT, pero la granularidad del mecanismo de selección anterior le permite mezclar y combinar en un grado aún mayor.

El siguiente código generará información sobre las cuatro fábricas principales de JAXP:

private static void OutputJaxpImplementationInfo() {
    System.out.println(getJaxpImplementationInfo("DocumentBuilderFactory", DocumentBuilderFactory.newInstance().getClass()));
    System.out.println(getJaxpImplementationInfo("XPathFactory", XPathFactory.newInstance().getClass()));
    System.out.println(getJaxpImplementationInfo("TransformerFactory", TransformerFactory.newInstance().getClass()));
    System.out.println(getJaxpImplementationInfo("SAXParserFactory", SAXParserFactory.newInstance().getClass()));
}

private static String getJaxpImplementationInfo(String componentName, Class componentClass) {
    CodeSource source = componentClass.getProtectionDomain().getCodeSource();
    return MessageFormat.format(
            "{0} implementation: {1} loaded from: {2}",
            componentName,
            componentClass.getName(),
            source == null ? "Java Runtime" : source.getLocation());
}

La siguiente salida de ejemplo ilustra una combinación de tres implementaciones JAXP diferentes (integradas Xerces y tarros externos para Xerces 2.8 y Xalan) trabajando juntos:

DocumentBuilderFactory implementation: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl loaded from: file:/C:/Projects/Scratch/lib/xerces-2.8.0.jar
XPathFactory implementation: com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl loaded from: Java Runtime
TransformerFactory implementation: org.apache.xalan.processor.TransformerFactoryImpl loaded from: file:/C:/Projects/Scratch/lib/xalan.jar
SAXParserFactory implementation: org.apache.xerces.jaxp.SAXParserFactoryImpl loaded from: file:/C:/Projects/Scratch/lib/xerces-2.8.0.jar
 51
Author: Daniel Fortunov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-16 14:51:15

Basta con añadir

-Djaxp.debug=1

A JAVA_OPTS y usted verá dicha información.

Para más detalles: https://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilderFactory.html

 6
Author: trang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-15 12:18:42

Es fácil, usted acaba de establecer

System.setProperty("jaxp.debug", "1");

La pista te dirá qué es impl y qué es el uso de jaxp.

 3
Author: zg_spring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-15 12:18:27

Depende, pero generalmente no.

DocumentBuilderFactory.newInstance() devolverá la implementación de DocumentBuilderFactory que está configurada en la propiedad del sistema "javax.XML.analizador.DocumentBuilderFactory " o la fábrica predeterminada de JRE si la propiedad del sistema no está establecida. Lo más probable es que la fábrica predeterminada esté codificada en la implementación del método newInstance y no sea accesible de otro modo.

Si la propiedad del sistema está establecida, al menos podría usar el método getResource en el cargador de clases relevante para obtener la URL, desde la que el cargador de clases cargaría el archivo de clase correspondiente. Si es de un archivo jar, debería poder extraer el nombre del archivo (o la URL de origen) de la URL jar:. La información detallada del paquete también debería estar disponible si lee manaully los archivos de metadatos desde el classpath.

Si la propiedad del sistema no está establecida, estoy bastante seguro de que no tiene forma de obtener la información que está buscando sin crear una nueva fábrica como ya lo está haciendo.

 1
Author: jarnbjo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-25 18:12:40

Hay otra ubicación que se busca antes de la "implementación predeterminada de la plataforma de reserva" y es el directorio java.endorsed.dirs como se documenta en el Mecanismo de Anulación de Estándares respaldados por Java

El Mecanismo de Anulación de Estándares Aprobados proporciona un medio por el cual las versiones posteriores de clases e interfaces que implementan Estándares Aprobados o Tecnologías Independientes pueden incorporarse a la Plataforma Java.

 1
Author: jwd630,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-20 01:59:58