Skip to content

Commit

Permalink
Optionally enforce required elements in XSDs (#263)
Browse files Browse the repository at this point in the history
This closes #162
  • Loading branch information
kwin committed Dec 29, 2022
1 parent 394178a commit e98cde5
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ public class ModelloParameterConstants
*/
public static final String EXTENDED_CLASSNAME_SUFFIX = "modello.xpp3.extended.suffix";

/**
* Boolean flag enforcing existence of mandatory elements in the XSD.
* If set to {@code false} will not require mandatory elements in the XML which can be useful if the XML is post processed (e.g. POM merging with parents)
* where mandatory elements might be contributed by sources outside the XML.
* @since 2.1
*/
public static final String XSD_ENFORCE_MANDATORY_ELEMENTS = "modello.xsd.enforce.mandatory.element";
private ModelloParameterConstants()
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ public class ModelloXsdMojo
@Parameter( defaultValue = "${project.build.directory}/generated-site/resources/xsd", required = true )
private File outputDirectory;

/**
* Boolean flag to enforce mandatory elements in the XML schema.
* If set to {@code false} the XSD won't enforce mandatory elements in the XML which can be useful if the XML is post processed (e.g. POM merging with parents).
* The default value is {@code false} for backwards compatibility reasons, but should be set to {@code true} for most cases.
* @since 2.1.0
*/
@Parameter( defaultValue = "false")
private boolean enforceMandatoryElements;

/**
*
* @since 1.0-alpha-21
Expand All @@ -65,6 +74,7 @@ protected void customizeParameters( Properties parameters )
{
parameters.put( ModelloParameterConstants.OUTPUT_XSD_FILE_NAME, xsdFileName );
}
parameters.put( ModelloParameterConstants.XSD_ENFORCE_MANDATORY_ELEMENTS, enforceMandatoryElements );
}

protected boolean producesCompilableResult()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ private void generateXsd( Properties parameters )

// we assume parameters not null
String xsdFileName = parameters.getProperty( ModelloParameterConstants.OUTPUT_XSD_FILE_NAME );
boolean enforceMandatoryElements = Boolean.parseBoolean( parameters.getProperty( ModelloParameterConstants.XSD_ENFORCE_MANDATORY_ELEMENTS ) );

File f = new File( directory, objectModel.getId() + "-" + getGeneratedVersion() + ".xsd" );

Expand Down Expand Up @@ -137,7 +138,8 @@ private void generateXsd( Properties parameters )
// Element descriptors
// Traverse from root so "abstract" models aren't included
int initialCapacity = objectModel.getClasses( getGeneratedVersion() ).size();
writeComplexTypeDescriptor( w, objectModel, root, new HashSet<ModelClass>( initialCapacity ) );
writeComplexTypeDescriptor( w, objectModel, root, new HashSet<ModelClass>( initialCapacity ),
enforceMandatoryElements );

w.endElement();
}
Expand Down Expand Up @@ -184,7 +186,7 @@ private static void writeDocumentation( XMLWriter w, String version, String desc
}

private void writeComplexTypeDescriptor( XMLWriter w, Model objectModel, ModelClass modelClass,
Set<ModelClass> written )
Set<ModelClass> written, boolean enforceMandatoryElements )
{
written.add( modelClass );

Expand Down Expand Up @@ -242,9 +244,12 @@ private void writeComplexTypeDescriptor( XMLWriter w, Model objectModel, ModelCl
{
w.startElement( "xs:element" );

// Usually, would only do this if the field is not "required", but due to inheritance, it may be
// present, even if not here, so we need to let it slide
w.addAttribute( "minOccurs", "0" );
if ( !enforceMandatoryElements || !field.isRequired() )
{
// Usually, would only do this if the field is not "required", but due to inheritance, it may be
// present, even if not here, so we need to let it slide
w.addAttribute( "minOccurs", "0" );
}
}

String xsdType = getXsdType( field.getType() );
Expand Down Expand Up @@ -428,7 +433,7 @@ else if ( xsdType == null )
{
if ( !written.contains( fieldModelClass ) )
{
writeComplexTypeDescriptor( w, objectModel, fieldModelClass, written );
writeComplexTypeDescriptor( w, objectModel, fieldModelClass, written, enforceMandatoryElements );
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import org.codehaus.modello.AbstractModelloGeneratorTest;
import org.codehaus.modello.ModelloException;
import org.codehaus.modello.ModelloParameterConstants;
import org.codehaus.modello.core.ModelloCore;
import org.codehaus.modello.model.Model;
import org.xml.sax.SAXParseException;
Expand Down Expand Up @@ -56,7 +57,8 @@ public void testXsdGenerator()
Model model = modello.loadModel( getXmlResourceReader( "/features.mdo" ) );

Properties parameters = getModelloParameters( "1.0.0" );

parameters.setProperty( ModelloParameterConstants.XSD_ENFORCE_MANDATORY_ELEMENTS, "true" );

modello.generate( model, "xsd", parameters );

SchemaFactory sf = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
Expand All @@ -80,7 +82,19 @@ public void testXsdGenerator()
catch ( SAXParseException e )
{
// ok, expected exception
assertTrue( String.valueOf( e.getMessage() ).contains( "invalidElement" ) );
assertTrue( e.getMessage().contains( "invalidElement" ) );
}

try
{
validator.validate( new StreamSource( getClass().getResourceAsStream( "/features-missing-required.xml" ) ) );
fail( "parsing of features-invalid.xml should have failed" );
}
catch ( SAXParseException e )
{
// ok, expected exception
assertTrue( e.getMessage().contains( "description" ) );
assertTrue( e.getMessage().endsWith(" is expected."));
}

try
Expand All @@ -91,7 +105,7 @@ public void testXsdGenerator()
catch ( SAXParseException e )
{
// ok, expected exception
assertTrue( String.valueOf( e.getMessage() ).contains( "transientString" ) );
assertTrue( e.getMessage().contains( "transientString" ) );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

import org.codehaus.modello.AbstractModelloGeneratorTest;
import org.codehaus.modello.ModelloParameterConstants;
import org.codehaus.modello.core.ModelloCore;
import org.codehaus.modello.model.Model;
import org.xml.sax.SAXException;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0"?>

<features-demo xmlns="http://codehaus-plexus.github.io/FEATURES/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://codehaus-plexus.github.io/FEATURES/1.0.0 http://codehaus-plexus.github.io/features-1.0.0.xsd">
</features-demo>
2 changes: 1 addition & 1 deletion modello-test/src/main/resources/features.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<features-demo xmlns="http://codehaus-plexus.github.io/FEATURES/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://codehaus-plexus.github.io/FEATURES/1.0.0 http://codehaus-plexus.github.io/features-1.0.0.xsd">
<versionField>1.0.0</versionField>
<!--required></required--><!-- TODO: this field is marked required but not set in the XML, should fail... -->
<required></required>
<identifier>id</identifier>
<identifierPart2><id>reference</id></identifierPart2>

Expand Down

0 comments on commit e98cde5

Please sign in to comment.