[jdom-interest] Schema validation with JAXP 1.2 and JDOM

Laurent Bihanic laurent.bihanic at atosorigin.com
Mon Mar 17 07:37:41 PST 2003


Hi,

Attached is a SAXBuilder patch that fixes the schema validation issues when 
using JAXP 1.2 and Xerces 2.3 (see mail below).

This patch moves the JAXP code into a new class JAXPParserFactory to remove 
most of the reflection code from SAXBuilder. This new class also takes care of 
setting the JAXP 1.2 schema-related properties directly on the JAXP SAXParser 
object, as required per JAXP and the Xerces implementation.

SAXBuilder still needs to use some reflection code (to access the new class) 
to allow being loaded even when the JAXP classes are not in the class path 
(Jason's requirement). In this latter case, SAXBuilder receives a 
NoClassDefFoundError when trying to access JAXPParserFactory and revert to 
using SAX XMLReaderFactory.

Laurent


Laurent Bihanic wrote:
> 
> Some tips for everyone interested in schema validation...
> 
> While upgrading to Xerces 2.3.0, I tried to shift from Xerces' specific 
> properties for schema validation to the properties defined by JAXP 1.2.
> 
> Well... it doesn't work because Xerces XMLReader implementation requires 
> the "http://apache.org/xml/features/validation/schema" feature to be set 
> to true to take into account the JAXP 1.2 properties.
> 
> When using JAXP (i.e. without JDOM), setting the JAXP 1.2 properties 
> shall be done on the JAXP SAXParser object, not on the XMLReader. The 
> Xerces implementation of SAXParser takes care of setting the 
> "http://apache.org/xml/features/validation/schema" feature when the 
> schema language property is being set.
> 
> Unfortunately, JDOM's SAXBuilder does not perform any operation on the 
> SAXParser object and deals only with the XMLReader.
> 
> Qestion: Now that JAXP is standard, i.e. part of the JDK since 1.4 and 
> delivered with nearly every parser, why not remove this reflection code 
> from SAXBuilder and make plain Java calls to the JAXP API (the way the 
> transform package already does) ?
> 
> Once this done, JAXP schema validation properties could be set through 
> the SAXParser.
> 
> Opinions?
> 
> Laurent
-------------- next part --------------
Index: SAXBuilder.java
===================================================================
RCS file: /home/cvspublic/jdom/src/java/org/jdom/input/SAXBuilder.java,v
retrieving revision 1.72
diff -r1.72 SAXBuilder.java
439,440c439,442
<               parser = XMLReaderFactory.createXMLReader(saxDriverClass);
<               // System.out.println("using specific " + saxDriverClass);
---
>                 parser = XMLReaderFactory.createXMLReader(saxDriverClass);
> 
>                 // Configure parser
>                 setFeaturesAndProperties(parser, true);
450a453
>                 // Get factory class and method.
452c455,464
<                     Class.forName("javax.xml.parsers.SAXParserFactory");
---
>                     Class.forName("org.jdom.input.JAXPParserFactory");
> 
>                 Method createParser = 
>                     factoryClass.getMethod("createParser",
>                         new Class[] { boolean.class, Map.class, Map.class });
> 
>                 // Create SAX parser.
>                 parser = (XMLReader)createParser.invoke(null,
>                                 new Object[] { new Boolean(validate),
>                                                features, properties });
454,486c466,479
<                 // factory = SAXParserFactory.newInstance();
<                 Method newParserInstance = 
<                     factoryClass.getMethod("newInstance", null);
<                 Object factory = newParserInstance.invoke(null, null);
< 
<                 // factory.setValidating(validate);
<                 Method setValidating = 
<                     factoryClass.getMethod("setValidating", 
<                                            new Class[]{boolean.class});
<                 setValidating.invoke(factory, 
<                                      new Object[]{new Boolean(validate)});
< 
<                 // jaxpParser = factory.newSAXParser();
<                 Method newSAXParser = 
<                     factoryClass.getMethod("newSAXParser", null);
<                 Object jaxpParser  = newSAXParser.invoke(factory, null);
< 
<                 // parser = jaxpParser.getXMLReader();
<                 Class parserClass = jaxpParser.getClass();
<                 Method getXMLReader = 
<                     parserClass.getMethod("getXMLReader", null);
<                 parser = (XMLReader)getXMLReader.invoke(jaxpParser, null);
< 
<                 // System.out.println("Using jaxp " +
<                 //   parser.getClass().getName());
<             } catch (ClassNotFoundException e) {
<                 //e.printStackTrace();
<             } catch (InvocationTargetException e) {
<                 //e.printStackTrace();
<             } catch (NoSuchMethodException e) {
<                 //e.printStackTrace();
<             } catch (IllegalAccessException e) {
<                 //e.printStackTrace();
---
>                 // Configure parser
>                 setFeaturesAndProperties(parser, false);
>             }
>             catch (JDOMException e) {
>                 throw e;
>             }
>             catch (NoClassDefFoundError e) {
>                 // The class loader failed to resolve the dependencies
>                 // of org.jdom.input.JAXPParserFactory. This probably means
>                 // that no JAXP parser is present in its class path.
>                 // => Ignore and try allocating default SAX parser instance.
>             }
>             catch (Exception e) {
>                 // Ignore and try allocating default SAX parser instance.
496a490,492
> 
>                 // Configure parser
>                 setFeaturesAndProperties(parser, true);
541,556d536
<         // Set any user-specified features on the parser.
<         Iterator iter = features.keySet().iterator();
<         while(iter.hasNext()) {
<             String name = (String)iter.next();
<             Boolean value = (Boolean)features.get(name);
<             internalSetFeature(parser, name, value.booleanValue(), name);
<         }
< 
<         // Set any user-specified properties on the parser.
<         Iterator iter2 = properties.keySet().iterator();
<         while(iter2.hasNext()) {
<             String name = (String)iter2.next();
<             Object value = properties.get(name);
<             internalSetProperty(parser, name, value, name);
<         }
< 
594a575
>     }
596,604c577,585
<         // Set validation.
<         try {
<             internalSetFeature(parser, "http://xml.org/sax/features/validation", 
<                     validate, "Validation");
<         } catch (JDOMException e) {
<             // If validation is not supported, and the user is requesting
<             // that we don't validate, that's fine - don't throw an exception.
<             if (validate)
<                 throw e;
---
>     private void setFeaturesAndProperties(XMLReader parser,
>                                           boolean coreFeatures)
>                                                         throws JDOMException {
>         // Set any user-specified features on the parser.
>         Iterator iter = features.keySet().iterator();
>         while (iter.hasNext()) {
>             String  name  = (String)iter.next();
>             Boolean value = (Boolean)features.get(name);
>             internalSetFeature(parser, name, value.booleanValue(), name);
607,611c588,616
<         // Setup some namespace features.
<         internalSetFeature(parser, "http://xml.org/sax/features/namespaces", 
<                 true, "Namespaces");
<         internalSetFeature(parser, "http://xml.org/sax/features/namespace-prefixes", 
<                 false, "Namespace prefixes");
---
>         // Set any user-specified properties on the parser.
>         iter = properties.keySet().iterator();
>         while (iter.hasNext()) {
>             String name = (String)iter.next();
>             internalSetProperty(parser, name, properties.get(name), name);
>         }
> 
>         if (coreFeatures) {
>             // Set validation.
>             try {
>                 internalSetFeature(parser,
>                         "http://xml.org/sax/features/validation",
>                         validate, "Validation");
>             } catch (JDOMException e) {
>                 // If validation is not supported, and the user is requesting
>                 // that we don't validate, that's fine - don't throw an
>                 // exception.
>                 if (validate)
>                     throw e;
>             }
> 
>             // Setup some namespace features.
>             internalSetFeature(parser,
>                         "http://xml.org/sax/features/namespaces",
>                         true, "Namespaces");
>             internalSetFeature(parser,
>                         "http://xml.org/sax/features/namespace-prefixes", 
>                         false, "Namespace prefixes");
>         }
624,640d628
< 
<         }
<         catch (SAXNotRecognizedException e) {
<         /*
<             // No entity expansion available
<             throw new JDOMException(
<               "Entity expansion feature not recognized by " + 
<               parser.getClass().getName());
<         */
<         }
<         catch (SAXNotSupportedException e) {
<         /*
<             // No entity expansion available
<             throw new JDOMException(
<               "Entity expansion feature not supported by " +
<               parser.getClass().getName());
<         */
641a630,631
>         catch (SAXNotRecognizedException e) { /* Ignore... */ }
>         catch (SAXNotSupportedException  e) { /* Ignore... */ }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: JAXPParserFactory.java
Type: text/x-java
Size: 6420 bytes
Desc: not available
Url : http://jdom.org/pipermail/jdom-interest/attachments/20030317/0cc5b48e/JAXPParserFactory.bin


More information about the jdom-interest mailing list