Skip to content

Commit e98cde5

Browse files
authored
Optionally enforce required elements in XSDs (#263)
This closes #162
1 parent 394178a commit e98cde5

File tree

7 files changed

+52
-10
lines changed

7 files changed

+52
-10
lines changed

modello-core/src/main/java/org/codehaus/modello/ModelloParameterConstants.java

+7
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ public class ModelloParameterConstants
7171
*/
7272
public static final String EXTENDED_CLASSNAME_SUFFIX = "modello.xpp3.extended.suffix";
7373

74+
/**
75+
* Boolean flag enforcing existence of mandatory elements in the XSD.
76+
* 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)
77+
* where mandatory elements might be contributed by sources outside the XML.
78+
* @since 2.1
79+
*/
80+
public static final String XSD_ENFORCE_MANDATORY_ELEMENTS = "modello.xsd.enforce.mandatory.element";
7481
private ModelloParameterConstants()
7582
{
7683
}

modello-maven-plugin/src/main/java/org/codehaus/modello/maven/ModelloXsdMojo.java

+10
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ public class ModelloXsdMojo
4545
@Parameter( defaultValue = "${project.build.directory}/generated-site/resources/xsd", required = true )
4646
private File outputDirectory;
4747

48+
/**
49+
* Boolean flag to enforce mandatory elements in the XML schema.
50+
* 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).
51+
* The default value is {@code false} for backwards compatibility reasons, but should be set to {@code true} for most cases.
52+
* @since 2.1.0
53+
*/
54+
@Parameter( defaultValue = "false")
55+
private boolean enforceMandatoryElements;
56+
4857
/**
4958
*
5059
* @since 1.0-alpha-21
@@ -65,6 +74,7 @@ protected void customizeParameters( Properties parameters )
6574
{
6675
parameters.put( ModelloParameterConstants.OUTPUT_XSD_FILE_NAME, xsdFileName );
6776
}
77+
parameters.put( ModelloParameterConstants.XSD_ENFORCE_MANDATORY_ELEMENTS, enforceMandatoryElements );
6878
}
6979

7080
protected boolean producesCompilableResult()

modello-plugins/modello-plugin-xsd/src/main/java/org/codehaus/modello/plugin/xsd/XsdGenerator.java

+11-6
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ private void generateXsd( Properties parameters )
8787

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

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

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

142144
w.endElement();
143145
}
@@ -184,7 +186,7 @@ private static void writeDocumentation( XMLWriter w, String version, String desc
184186
}
185187

186188
private void writeComplexTypeDescriptor( XMLWriter w, Model objectModel, ModelClass modelClass,
187-
Set<ModelClass> written )
189+
Set<ModelClass> written, boolean enforceMandatoryElements )
188190
{
189191
written.add( modelClass );
190192

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

245-
// Usually, would only do this if the field is not "required", but due to inheritance, it may be
246-
// present, even if not here, so we need to let it slide
247-
w.addAttribute( "minOccurs", "0" );
247+
if ( !enforceMandatoryElements || !field.isRequired() )
248+
{
249+
// Usually, would only do this if the field is not "required", but due to inheritance, it may be
250+
// present, even if not here, so we need to let it slide
251+
w.addAttribute( "minOccurs", "0" );
252+
}
248253
}
249254

250255
String xsdType = getXsdType( field.getType() );
@@ -428,7 +433,7 @@ else if ( xsdType == null )
428433
{
429434
if ( !written.contains( fieldModelClass ) )
430435
{
431-
writeComplexTypeDescriptor( w, objectModel, fieldModelClass, written );
436+
writeComplexTypeDescriptor( w, objectModel, fieldModelClass, written, enforceMandatoryElements );
432437
}
433438
}
434439
}

modello-plugins/modello-plugin-xsd/src/test/java/org/codehaus/modello/plugin/xsd/FeaturesXsdGeneratorTest.java

+17-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import org.codehaus.modello.AbstractModelloGeneratorTest;
2626
import org.codehaus.modello.ModelloException;
27+
import org.codehaus.modello.ModelloParameterConstants;
2728
import org.codehaus.modello.core.ModelloCore;
2829
import org.codehaus.modello.model.Model;
2930
import org.xml.sax.SAXParseException;
@@ -56,7 +57,8 @@ public void testXsdGenerator()
5657
Model model = modello.loadModel( getXmlResourceReader( "/features.mdo" ) );
5758

5859
Properties parameters = getModelloParameters( "1.0.0" );
59-
60+
parameters.setProperty( ModelloParameterConstants.XSD_ENFORCE_MANDATORY_ELEMENTS, "true" );
61+
6062
modello.generate( model, "xsd", parameters );
6163

6264
SchemaFactory sf = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
@@ -80,7 +82,19 @@ public void testXsdGenerator()
8082
catch ( SAXParseException e )
8183
{
8284
// ok, expected exception
83-
assertTrue( String.valueOf( e.getMessage() ).contains( "invalidElement" ) );
85+
assertTrue( e.getMessage().contains( "invalidElement" ) );
86+
}
87+
88+
try
89+
{
90+
validator.validate( new StreamSource( getClass().getResourceAsStream( "/features-missing-required.xml" ) ) );
91+
fail( "parsing of features-invalid.xml should have failed" );
92+
}
93+
catch ( SAXParseException e )
94+
{
95+
// ok, expected exception
96+
assertTrue( e.getMessage().contains( "description" ) );
97+
assertTrue( e.getMessage().endsWith(" is expected."));
8498
}
8599

86100
try
@@ -91,7 +105,7 @@ public void testXsdGenerator()
91105
catch ( SAXParseException e )
92106
{
93107
// ok, expected exception
94-
assertTrue( String.valueOf( e.getMessage() ).contains( "transientString" ) );
108+
assertTrue( e.getMessage().contains( "transientString" ) );
95109
}
96110
}
97111
}

modello-plugins/modello-plugin-xsd/src/test/java/org/codehaus/modello/plugin/xsd/ModelloXsdGeneratorTest.java

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
import org.codehaus.modello.AbstractModelloGeneratorTest;
26+
import org.codehaus.modello.ModelloParameterConstants;
2627
import org.codehaus.modello.core.ModelloCore;
2728
import org.codehaus.modello.model.Model;
2829
import org.xml.sax.SAXException;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0"?>
2+
3+
<features-demo xmlns="http://codehaus-plexus.github.io/FEATURES/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://codehaus-plexus.github.io/FEATURES/1.0.0 http://codehaus-plexus.github.io/features-1.0.0.xsd">
5+
</features-demo>

modello-test/src/main/resources/features.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<features-demo xmlns="http://codehaus-plexus.github.io/FEATURES/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
44
xsi:schemaLocation="http://codehaus-plexus.github.io/FEATURES/1.0.0 http://codehaus-plexus.github.io/features-1.0.0.xsd">
55
<versionField>1.0.0</versionField>
6-
<!--required></required--><!-- TODO: this field is marked required but not set in the XML, should fail... -->
6+
<required></required>
77
<identifier>id</identifier>
88
<identifierPart2><id>reference</id></identifierPart2>
99

0 commit comments

Comments
 (0)