diff --git a/src/main/java/org/apache/xmlbeans/impl/values/JavaNotationHolderEx.java b/src/main/java/org/apache/xmlbeans/impl/values/JavaNotationHolderEx.java index 6dbbd4871..ad04d4d09 100644 --- a/src/main/java/org/apache/xmlbeans/impl/values/JavaNotationHolderEx.java +++ b/src/main/java/org/apache/xmlbeans/impl/values/JavaNotationHolderEx.java @@ -27,7 +27,7 @@ public abstract class JavaNotationHolderEx extends JavaNotationHolder { - private SchemaType _schemaType; + private final SchemaType _schemaType; public SchemaType schemaType() @@ -89,7 +89,35 @@ public static QName validateLexical(String v, SchemaType sType, ValidationContex } } - check(v, sType); + // check against length + XmlObject len = sType.getFacet(SchemaType.FACET_LENGTH); + if (len != null) + { + int m = ((XmlObjectBase)len).getBigIntegerValue().intValue(); + if (v.length() != m) + context.invalid(XmlErrorCodes.DATATYPE_LENGTH_VALID$STRING, + new Object[] { "NOTATION", v.length(), m, QNameHelper.readable(sType) }); + } + + // check against min length + XmlObject min = sType.getFacet(SchemaType.FACET_MIN_LENGTH); + if (min != null) + { + int m = ((XmlObjectBase)min).getBigIntegerValue().intValue(); + if (v.length() < m) + context.invalid(XmlErrorCodes.DATATYPE_MIN_LENGTH_VALID$STRING, + new Object[] { "NOTATION", v.length(), m, QNameHelper.readable(sType) }); + } + + // check against max length + XmlObject max = sType.getFacet(SchemaType.FACET_MAX_LENGTH); + if (max != null) + { + int m = ((XmlObjectBase)max).getBigIntegerValue().intValue(); + if (v.length() > m) + context.invalid(XmlErrorCodes.DATATYPE_MAX_LENGTH_VALID$STRING, + new Object[] { "NOTATION", v.length(), m, QNameHelper.readable(sType) }); + } return name; } @@ -119,8 +147,7 @@ private static boolean check(String v, SchemaType sType) if (max != null) { int m = ((XmlObjectBase)max).getBigIntegerValue().intValue(); - if (!(v.length() <= m)) - return false; + return v.length() <= m; } return true; diff --git a/src/main/java/org/apache/xmlbeans/impl/values/NamespaceContext.java b/src/main/java/org/apache/xmlbeans/impl/values/NamespaceContext.java index 293acd33d..19a3ced78 100644 --- a/src/main/java/org/apache/xmlbeans/impl/values/NamespaceContext.java +++ b/src/main/java/org/apache/xmlbeans/impl/values/NamespaceContext.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Map; import java.lang.reflect.Proxy; -import java.lang.ref.SoftReference; import org.apache.xmlbeans.xml.stream.StartElement; @@ -35,8 +34,8 @@ public class NamespaceContext implements PrefixResolver private static final int START_ELEMENT = 4; private static final int RESOLVER = 5; - private Object _obj; - private int _code; + private final Object _obj; + private final int _code; public NamespaceContext(Map prefixToUriMap) { @@ -88,7 +87,8 @@ final void pop() } } - private static ThreadLocal tl_namespaceContextStack = new ThreadLocal(); + private static final ThreadLocal tl_namespaceContextStack = + new ThreadLocal<>(); public static void clearThreadLocals() { tl_namespaceContextStack.remove(); @@ -96,7 +96,7 @@ public static void clearThreadLocals() { private static NamespaceContextStack getNamespaceContextStack() { - NamespaceContextStack namespaceContextStack = (NamespaceContextStack) tl_namespaceContextStack.get(); + NamespaceContextStack namespaceContextStack = tl_namespaceContextStack.get(); if (namespaceContextStack==null) { namespaceContextStack = new NamespaceContextStack(); @@ -115,7 +115,7 @@ public static void pop() NamespaceContextStack nsContextStack = getNamespaceContextStack(); nsContextStack.pop(); - if (nsContextStack.stack.size()==0) + if (nsContextStack.stack.isEmpty()) tl_namespaceContextStack.set(null); } diff --git a/src/main/java/org/apache/xmlbeans/impl/values/XmlAnySimpleTypeImpl.java b/src/main/java/org/apache/xmlbeans/impl/values/XmlAnySimpleTypeImpl.java index 99e00a8e4..d8f1a176f 100644 --- a/src/main/java/org/apache/xmlbeans/impl/values/XmlAnySimpleTypeImpl.java +++ b/src/main/java/org/apache/xmlbeans/impl/values/XmlAnySimpleTypeImpl.java @@ -67,7 +67,7 @@ protected boolean equal_to(XmlObject obj) { } protected int value_hash_code() { - // matches JavaStringHolder's value_hash_code, so we can be hased against strings + // matches JavaStringHolder's value_hash_code, so we can be hashed against strings return (_textvalue == null ? 0 : _textvalue.hashCode()); } } diff --git a/src/main/java/org/apache/xmlbeans/impl/values/XmlAnySimpleTypeRestriction.java b/src/main/java/org/apache/xmlbeans/impl/values/XmlAnySimpleTypeRestriction.java index 4629cb693..72f0be4cf 100644 --- a/src/main/java/org/apache/xmlbeans/impl/values/XmlAnySimpleTypeRestriction.java +++ b/src/main/java/org/apache/xmlbeans/impl/values/XmlAnySimpleTypeRestriction.java @@ -19,11 +19,15 @@ public class XmlAnySimpleTypeRestriction extends XmlAnySimpleTypeImpl { - public XmlAnySimpleTypeRestriction(SchemaType type, boolean complex) - { _schemaType = type; initComplexType(complex, false); } + private final SchemaType _schemaType; - private SchemaType _schemaType; + public XmlAnySimpleTypeRestriction(SchemaType type, boolean complex) { + _schemaType = type; + initComplexType(complex, false); + } - public SchemaType schemaType() - { return _schemaType; } + + public SchemaType schemaType() { + return _schemaType; + } } diff --git a/src/main/java/org/apache/xmlbeans/impl/values/XmlBase64BinaryImpl.java b/src/main/java/org/apache/xmlbeans/impl/values/XmlBase64BinaryImpl.java index 3d4e34409..680adb0f1 100644 --- a/src/main/java/org/apache/xmlbeans/impl/values/XmlBase64BinaryImpl.java +++ b/src/main/java/org/apache/xmlbeans/impl/values/XmlBase64BinaryImpl.java @@ -15,7 +15,6 @@ package org.apache.xmlbeans.impl.values; -import org.apache.xmlbeans.SchemaType; import org.apache.xmlbeans.XmlBase64Binary; diff --git a/src/main/java/org/apache/xmlbeans/impl/values/XmlComplexContentImpl.java b/src/main/java/org/apache/xmlbeans/impl/values/XmlComplexContentImpl.java index 2407c785e..eb2c76c76 100644 --- a/src/main/java/org/apache/xmlbeans/impl/values/XmlComplexContentImpl.java +++ b/src/main/java/org/apache/xmlbeans/impl/values/XmlComplexContentImpl.java @@ -69,12 +69,9 @@ public void set_nil() { /* BUGBUG: what to do? */ } // LEFT public boolean equal_to(XmlObject complexObject) { - if (!_schemaType.equals(complexObject.schemaType())) { - return false; - } + return _schemaType.equals(complexObject.schemaType()); // BUGBUG: by-value structure comparison undone - return true; } // LEFT diff --git a/src/main/java/org/apache/xmlbeans/impl/values/XmlObjectBase.java b/src/main/java/org/apache/xmlbeans/impl/values/XmlObjectBase.java index 93424f790..d08c50641 100644 --- a/src/main/java/org/apache/xmlbeans/impl/values/XmlObjectBase.java +++ b/src/main/java/org/apache/xmlbeans/impl/values/XmlObjectBase.java @@ -15,7 +15,6 @@ package org.apache.xmlbeans.impl.values; -import net.sf.saxon.expr.Component; import org.apache.xmlbeans.*; import org.apache.xmlbeans.impl.common.*; import org.apache.xmlbeans.impl.schema.SchemaTypeImpl; @@ -1098,7 +1097,7 @@ private void update_from_wscanon_text(String v) { if ((_flags & FLAG_HASDEFAULT) != 0 && (_flags & FLAG_SETTINGDEFAULT) == 0) { // This isn't quite correct since the .equals("") test should be // done on the actual text, not the wscanon text - if ((_flags & FLAG_ATTRIBUTE) == 0 && v.equals("")) { + if ((_flags & FLAG_ATTRIBUTE) == 0 && v.isEmpty()) { String def = get_store().compute_default_text(); if (def == null) { throw new XmlValueOutOfRangeException(); @@ -1817,13 +1816,6 @@ public final void set_newValue(XmlObject obj) { synchronized (monitor()) { assert (instanceType.getSimpleVariety() == SchemaType.ATOMIC); switch (instanceType.getPrimitiveType().getBuiltinTypeCode()) { - default: - assert (false) : "encountered nonprimitive type."; - // case SchemaType.BTC_ANY_SIMPLE: This is handled below... - // but we eventually want to handle it with a treecopy, so - // eventually we should break here. - break primitive; - case SchemaType.BTC_BOOLEAN: { boolean bool = ((SimpleValue) v).getBooleanValue(); set_prepare(); @@ -1892,16 +1884,16 @@ public final void set_newValue(XmlObject obj) { set_BigInteger(bi); break; } - default: { - assert (false) : "invalid numeric bit count"; - // fallthrough - } case SchemaType.SIZE_BIG_DECIMAL: { BigDecimal bd = ((SimpleValue) v).getBigDecimalValue(); set_prepare(); set_BigDecimal(bd); break; } + default: { + assert (false) : "invalid numeric bit count"; + // fallthrough + } } break; } @@ -1958,6 +1950,12 @@ public final void set_newValue(XmlObject obj) { } break; } + default: + assert (false) : "encountered nonprimitive type."; + // case SchemaType.BTC_ANY_SIMPLE: This is handled below... + // but we eventually want to handle it with a treecopy, so + // eventually we should break here. + break primitive; } set_commit(); return; // primitive node tree copy handled. @@ -2986,8 +2984,7 @@ private XmlObject objectAtDistance(int count) { // System.out.println("Count: " + count + " " + cur.currentTokenType().toString() + " " + QName.pretty(cur.getName())); } } - XmlObject result = cur.getObject(); - return result; + return cur.getObject(); } } } @@ -3045,11 +3042,11 @@ protected static Object java_value(XmlObject obj) { case SchemaType.SIZE_BIG_INTEGER: return base.getBigIntegerValue(); + case SchemaType.SIZE_BIG_DECIMAL: + return base.getBigDecimalValue(); default: assert (false) : "invalid numeric bit count"; // fallthrough - case SchemaType.SIZE_BIG_DECIMAL: - return base.getBigDecimalValue(); } } case SchemaType.BTC_ANY_URI: @@ -3067,19 +3064,19 @@ protected static Object java_value(XmlObject obj) { case SchemaType.BTC_G_DAY: case SchemaType.BTC_G_MONTH: return base.getCalendarValue(); - + case SchemaType.BTC_NOTATION: + case SchemaType.BTC_STRING: + case SchemaType.BTC_ANY_SIMPLE: + // return base.getStringValue(); + return base.getStringValue(); default: assert (false) : "encountered nonprimitive type."; // fallthrough // NB: for string enums we just do java.lang.String // when in the context of unions. It's easier on users. - case SchemaType.BTC_NOTATION: - case SchemaType.BTC_STRING: - case SchemaType.BTC_ANY_SIMPLE: - // return base.getStringValue(); - return base.getStringValue(); } + return null; } /** diff --git a/src/test/java/misc/checkin/NotationLengthFacetValidateTest.java b/src/test/java/misc/checkin/NotationLengthFacetValidateTest.java new file mode 100644 index 000000000..c91157770 --- /dev/null +++ b/src/test/java/misc/checkin/NotationLengthFacetValidateTest.java @@ -0,0 +1,77 @@ +/* Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package misc.checkin; + +import org.apache.xmlbeans.SchemaTypeLoader; +import org.apache.xmlbeans.XmlBeans; +import org.apache.xmlbeans.XmlError; +import org.apache.xmlbeans.XmlObject; +import org.apache.xmlbeans.XmlOptions; +import org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class NotationLengthFacetValidateTest { + + // A maxLength facet is applied to a NOTATION type whose inherited enumeration + // still admits a longer member, so the enumeration check alone does not catch + // the length violation. + private static final String XSD = + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""; + + private static boolean validate(String notationValue) throws Exception { + SchemaTypeLoader loader = XmlBeans.loadXsd(new XmlObject[]{SchemaDocument.Factory.parse(XSD)}); + XmlObject doc = loader.parse( + "" + notationValue + "", null, null); + List errors = new ArrayList<>(); + return doc.validate(new XmlOptions().setErrorListener(errors)); + } + + @Test + void notationWithinMaxLengthValidates() throws Exception { + // 't:a' is in the enumeration and its lexical length (3) matches maxLength + assertTrue(validate("t:a")); + } + + @Test + void notationViolatingMaxLengthIsInvalid() throws Exception { + // 't:bcdefgh' is in the inherited enumeration but its lexical length (9) + // exceeds maxLength=3, so document validation must reject it + assertFalse(validate("t:bcdefgh")); + } +}