diff --git a/modello-plugins/modello-plugin-xsd/src/main/java/org/codehaus/modello/plugin/xsd/XsdGenerator.java b/modello-plugins/modello-plugin-xsd/src/main/java/org/codehaus/modello/plugin/xsd/XsdGenerator.java index 21efc9dd8..99af81981 100644 --- a/modello-plugins/modello-plugin-xsd/src/main/java/org/codehaus/modello/plugin/xsd/XsdGenerator.java +++ b/modello-plugins/modello-plugin-xsd/src/main/java/org/codehaus/modello/plugin/xsd/XsdGenerator.java @@ -87,6 +87,8 @@ private void generateXsd(Map parameters) throws IOException, Mod // we assume parameters not null String xsdFileName = (String) parameters.get(ModelloParameterConstants.OUTPUT_XSD_FILE_NAME); + // enforceMandatoryElements parameter is kept for backward compatibility but is no longer used. + // Required fields are now always enforced based on field.isRequired() value. boolean enforceMandatoryElements = Boolean.parseBoolean((String) parameters.get(ModelloParameterConstants.XSD_ENFORCE_MANDATORY_ELEMENTS)); @@ -232,9 +234,7 @@ private void writeComplexTypeDescriptor( } w.startElement("xs:element"); - 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 + if (!field.isRequired()) { w.addAttribute("minOccurs", "0"); } } diff --git a/modello-plugins/modello-plugin-xsd/src/test/java/org/codehaus/modello/plugin/xsd/RequiredFieldXsdGeneratorTest.java b/modello-plugins/modello-plugin-xsd/src/test/java/org/codehaus/modello/plugin/xsd/RequiredFieldXsdGeneratorTest.java new file mode 100644 index 000000000..fe0298870 --- /dev/null +++ b/modello-plugins/modello-plugin-xsd/src/test/java/org/codehaus/modello/plugin/xsd/RequiredFieldXsdGeneratorTest.java @@ -0,0 +1,107 @@ +package org.codehaus.modello.plugin.xsd; + +/* + * Copyright (c) 2004, Codehaus.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import javax.inject.Inject; +import javax.xml.XMLConstants; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import java.io.File; +import java.io.StringReader; +import java.util.Map; + +import org.codehaus.modello.AbstractModelloGeneratorTest; +import org.codehaus.modello.core.ModelloCore; +import org.codehaus.modello.model.Model; +import org.codehaus.plexus.testing.PlexusTest; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXParseException; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * Test that verifies required fields are properly enforced in generated XSD schemas + * without needing the XSD_ENFORCE_MANDATORY_ELEMENTS parameter. + * + * @author Modello Team + */ +@PlexusTest +public class RequiredFieldXsdGeneratorTest extends AbstractModelloGeneratorTest { + @Inject + private ModelloCore modello; + + public RequiredFieldXsdGeneratorTest() { + super("required-field"); + } + + @Test + public void testRequiredFieldsEnforcedWithoutParameter() throws Throwable { + Model model = modello.loadModel(getXmlResourceReader("/required-field.mdo")); + + // Generate XSD WITHOUT the XSD_ENFORCE_MANDATORY_ELEMENTS parameter + Map parameters = getModelloParameters("1.0.0"); + // Note: NOT setting XSD_ENFORCE_MANDATORY_ELEMENTS parameter + + modello.generate(model, "xsd", parameters); + + SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = sf.newSchema(new StreamSource(new File(getOutputDirectory(), "test-1.0.0.xsd"))); + Validator validator = schema.newValidator(); + + // Test 1: Valid XML with all required fields should pass + String validXml = "\n" + + "\n" + + " value\n" + + ""; + + validator.validate(new StreamSource(new StringReader(validXml))); + + // Test 2: XML missing required field should fail + String missingRequiredXml = "\n" + + "\n" + + " value\n" + + ""; + + try { + validator.validate(new StreamSource(new StringReader(missingRequiredXml))); + fail("Validation should have failed for XML missing required field"); + } catch (SAXParseException e) { + // Expected - the error should mention the required field + assertTrue( + e.getMessage().contains("requiredField") || e.getMessage().contains("expected"), + "Error message should indicate missing required field: " + e.getMessage()); + } + + // Test 3: XML with optional field omitted should pass + String withoutOptionalXml = "\n" + + "\n" + + " value\n" + + ""; + + validator.validate(new StreamSource(new StringReader(withoutOptionalXml))); + } +} diff --git a/modello-plugins/modello-plugin-xsd/src/test/resources/required-field.mdo b/modello-plugins/modello-plugin-xsd/src/test/resources/required-field.mdo new file mode 100644 index 000000000..3dcfea125 --- /dev/null +++ b/modello-plugins/modello-plugin-xsd/src/test/resources/required-field.mdo @@ -0,0 +1,42 @@ + + + test + Test + + Simple test model for required field validation. + + + + package + org.codehaus.modello.test + + + + + TestModel + 1.0.0+ + + A simple model to test required field enforcement. + + + + requiredField + 1.0.0+ + true + String + This field is required and must be present. + + + optionalField + 1.0.0+ + String + This field is optional and may be omitted. + + + + + diff --git a/src/main/mdo/modello.mdo b/src/main/mdo/modello.mdo index ce792f471..a01bda070 100644 --- a/src/main/mdo/modello.mdo +++ b/src/main/mdo/modello.mdo @@ -672,7 +672,6 @@ type 1.0.0+ - true String boolean, byte,