fillumina / krasa-jaxb-tools

XJC / JAXB plugin for generation of Bean Validation Annotations 2.0 (JSR-380)
Apache License 2.0
6 stars 10 forks source link

Additional @Decimal annotations generated for xs:int #17

Closed Undover closed 1 month ago

Undover commented 1 month ago

Hello,

I'm in the process of migrating a project from javax to jakarta, and I've noticed some changes in how validations are generated for xs:int types.

This is part of the schema used for testing:

    <simpleType name="IntField">
        <restriction base="xs:int">
            <minInclusive value="1"/>
        </restriction>
    </simpleType>

    <simpleType name="LongField">
        <restriction base="xs:long">
            <minInclusive value="1"/>
        </restriction>
    </simpleType>

    <complexType name="ClassWithValidation">
        <sequence>
            <element name="intField" type="tns:IntField" minOccurs="0"/>
            <element name="otherIntField" type="xs:int" minOccurs="0"/>
            <element name="longField" type="tns:LongField" minOccurs="0"/>
            <element name="otherLongField" type="xs:long" minOccurs="0"/>
        </sequence>
    </complexType>

Classes generated with this schema differ between com.github.krasa:krasa-jaxb-tools:1.5 and com.fillumina:krasa-jaxb-tools:2.3.3 (among other dependency upgrades required for jakarta migration).

Before:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ClassWithValidation", namespace = "a", propOrder = {
    "intField",
    "otherIntField",
    "longField",
    "otherLongField"
})
public class ClassWithValidation
    implements Serializable
{

    private final static long serialVersionUID = 1L;
    @XmlElement(namespace = "a")
    @DecimalMin("1")
    protected Integer intField;
    @XmlElement(namespace = "a")
    protected Integer otherIntField;
    @XmlElement(namespace = "a")
    @DecimalMin("1")
    protected Long longField;
    @XmlElement(namespace = "a")
    protected Long otherLongField;
    ...

After:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ClassWithValidation", namespace = "a", propOrder = {
    "intField",
    "otherIntField",
    "longField",
    "otherLongField"
})
public class ClassWithValidation
    implements Serializable
{

    private static final long serialVersionUID = 1L;
    @XmlElement(namespace = "a")
    @DecimalMin(value = "1", inclusive = true)
    @DecimalMax(value = "2147483647", inclusive = true)
    protected Integer intField;
    @XmlElement(namespace = "a")
    @DecimalMin(value = "-2147483648", inclusive = true)
    @DecimalMax(value = "2147483647", inclusive = true)
    protected Integer otherIntField;
    @XmlElement(namespace = "a")
    @DecimalMin(value = "1", inclusive = true)
    protected Long longField;
    @XmlElement(namespace = "a")
    protected Long otherLongField;
    ...

What caught my attention is the generation of @DecimalMin(value = "-2147483648", inclusive = true) and @DecimalMax(value = "2147483647", inclusive = true) whenever a restriction is not specified for xs:int type, which is not the case for xs:long type, so if it's not a bug I assume something's wrong with my configuration.

Used flags for org.apache.cxf.tools.wsdlto.WSDLToJava:

-xjc-enableIntrospection
-Xfluent-api
-Xannotate
-XJsr303Annotations
-XJsr303Annotations:verbose=true
-Xcommons-lang
-verbose
-xjc-XJsr303Annotations:validationAnnotations=jakarta
-xjc-npa
-xjc-Xinheritance
-xjc-Xinject-code
-validate=all

In case of trouble with reproducing the issue, I could provide a sample project.

Thanks in advance

fillumina commented 1 month ago

Hi @Undover , that's a feature to restrict valid values to those allowed by the specs.

The XSD specifications allow for a lot of numeric types which are not present in java (i.e. unsignedShort) so to support them this program adds the necessary restrictions. Because the mechanism is automatic (it copies the restrictions added to the facet) they are added to supported types as well but that shouldn't be a problem.

Please see the numeric test on this package and the generated classes to better understand all the applied restrictions.

Regards

Undover commented 1 month ago

I've looked around and want to clarify things further, the generated Numeric class contains two fields aint and along, which according to the XSD spec should both be constrained (long to +/- 9223372036854775807, ints as they are now). Is the lack of validations for longs unintended then if they are generated for ints? If so, will the generation of those validation annotations be the default non-toggleable behavior in the future?

fillumina commented 1 month ago

The parsing of the XSD is done by the XSOM package invoked by JAXWS, for each defined type it fills the com.sun.xml.xsom.XSFacet class with the needed constraints and other info, which are read by krasa-jaxb-tools to create the needed validation annotations. We have no control over what constraints and info are passed by XSFacet but they should be consistent among other libraries that use the same XSOM package.

fillumina commented 1 month ago

As for the future it's hard to tell but the XSOM library is very mature and the tests present in here will fail if anything should change.

fillumina commented 1 month ago

Hi, to clarify

the generated Numeric class contains two fields aint and along, which according to the XSD spec should both be constrained (long to +/- 9223372036854775807, ints as they are now). Is the lack of validations for longs unintended then if they are generated for ints? If so, will the generation of those validation annotations be the default non-toggleable behavior in the future?

according to the int specs:

int is ·derived· from long by setting the value of ·maxInclusive· to be 2147483647 and ·minInclusive· to be -2147483648.

Because a Java int is a 32 bit signed value (from -2147483648 to 2147483647) it aligns with the XSD int specification so no further constraints are required. Same for xsd:long that is converted into a 64 bit signed Java type.

Krzyshio commented 1 month ago

Hi @fillumina ,

I’m encountering the same issue as @Undover .

As mentioned, the @DecimalMin and @DecimalMax annotations are being generated for int fields but not for long fields, which seems inconsistent. According to the XSD specs, both should have constraints, so it’s puzzling why int has validations while long does not.

You mentioned that no further constraints are required, but the problem is that int does have the validation annotations generated, which is causing confusion and, in my case, is problematic. Is there any way to disable these validation annotations for int fields? If this behavior is not toggleable, it could pose significant issues for us.

Thanks in advance for your help!

Undover commented 1 month ago

Because a Java int is a 32 bit signed value (from -2147483648 to 2147483647) it aligns with the XSD int specification so no further constraints are required. Same for xsd:long that is converted into a 64 bit signed Java type.

This is what's confusing to me, as both xsd:int and xsd:long have the same value ranges as the java int and long types, yet the validation annotations are only generated for ints. My codebase depends on the lack of unnecessary validation annotations; fixing this would require some refactoring and resolving this inconsistency with code gen in either direction would result in not having special cases.

fillumina commented 1 month ago

That's right, I have finally understood the inconsistency between int and long (it was a check made only for long), I am fixing it by removing all default constraints and setting an option to add them back if needed.