java - grafica - jframe
¿Cómo puedo saber qué implementación de JAXP está en uso y de dónde se cargó? (5)
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, 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 una DocumentBuilderFactory
?
Depende, pero en general no.
DocumentBuilderFactory.newInstance()
devolverá la implementación de DocumentBuilderFactory
que está configurada en la propiedad del sistema "javax.xml.parsers.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 hardware en la implementación del método newInstance y no esté accesible de otra manera.
Si se establece la propiedad del sistema, al menos podría usar el método getResource en el cargador de clases correspondiente para obtener la URL, desde la cual el cargador de clases cargaría el archivo de clases correspondiente. Si proviene de un archivo jar, debería poder extraer el nombre del archivo (o URL de origen) del jar: URL. La información detallada del paquete también debería estar disponible si lee manualmente los metadatos de la ruta de clase.
Si la propiedad del sistema no está establecida, estoy bastante seguro de que no tiene forma de obtener la información que busca sin crear una nueva fábrica como ya lo está haciendo.
Es bastante difícil predecir qué implementación concreta de JAXP Factory se cargará sin crear realmente una instancia debido al proceso para seleccionar una implementación.
De las preguntas frecuentes oficiales de JAXP (pregunta 14):
Cuando una aplicación desea crear una nueva instancia de JAXP
DocumentBuilderFactory
, llama al método básicoDocumentBuilderFactory.newInstance()
. Esto provoca una búsqueda del nombre de una subclase concreta deDocumentBuilderFactory
usando el siguiente orden:
- El valor de una propiedad del sistema como
javax.xml.parsers.DocumentBuilderFactory
si existe y es accesible.- El contenido del archivo
$JAVA_HOME/jre/lib/jaxp.properties
si existe.- El mecanismo de descubrimiento 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
contiene el nombre de la clase concreta para crear una instancia.- La implementación predeterminada de la plataforma alternativa.
Además de esta complejidad, cada fábrica JAXP individual puede tener una implementación independiente especificada. Es común usar una implementación de analizador y otra implementación de 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 dará 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 muestra ilustra una combinación de tres implementaciones JAXP diferentes (Xerces incorporados y JAR 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
Es fácil, solo tienes que configurar
System.setProperty("jaxp.debug", "1");
La pista te dirá qué puedes usar y cómo usar jaxp.
Hay otra ubicación que se busca antes de la "implementación predeterminada de la plataforma alternativa" y es el directorio java.endorsed.dirs
tal como se documenta en el Mecanismo de anulación de estándares endosados de Java
El Mecanismo de anulación de estándares avalados proporciona un medio por el cual las versiones posteriores de clases e interfaces que implementan estándares respaldados o tecnologías independientes pueden incorporarse en la plataforma Java.
Solo agrega
-Djaxp.debug=1
a JAVA_OPTS
y verá dicha información.
Para obtener más detalles, https://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilderFactory.html