This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch coheigea/unresolvable in repository https://gitbox.apache.org/repos/asf/ws-xmlschema.git
commit b8210e775c53059eecad92935de4a67eef7dc042 Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Thu Sep 17 09:36:11 2026 +0100 Report unresolvable and complex-where-simple type references as XmlSchemaException --- .../ws/commons/schema/walker/XmlSchemaScope.java | 52 +++++--- .../schema/walker/UnresolvableSimpleTypeTest.java | 144 +++++++++++++++++++++ 2 files changed, 180 insertions(+), 16 deletions(-) diff --git a/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java b/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java index c05349a5..24cd4dd8 100644 --- a/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java +++ b/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java @@ -160,6 +160,25 @@ final class XmlSchemaScope { return anyAttr; } + /** + * Resolves a named type reference that the schema requires to be a simple type. A reference + * that does not resolve, or resolves to a complex type, is a defect in the schema: the core + * parser does not check either, so both reach here. + */ + private XmlSchemaSimpleType simpleTypeByName(QName typeName, String role, String owner) { + final XmlSchemaType type = + (typeName == null) ? null : schemasByNamespace.getTypeByName(typeName); + if (type == null) { + throw new XmlSchemaException("The " + role + " " + owner + " (" + typeName + + ") does not resolve to a type in this collection."); + } + if (!(type instanceof XmlSchemaSimpleType)) { + throw new XmlSchemaException("The " + role + " " + owner + " (" + typeName + + ") resolves to a complex type; a simple type is required."); + } + return (XmlSchemaSimpleType)type; + } + private void walk(XmlSchemaType type) { if (type instanceof XmlSchemaSimpleType) { walk((XmlSchemaSimpleType)type); @@ -185,11 +204,8 @@ final class XmlSchemaScope { XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList)content; XmlSchemaSimpleType listType = list.getItemType(); if (listType == null) { - listType = (XmlSchemaSimpleType)schemasByNamespace.getTypeByName(list.getItemTypeName()); - } - if (listType == null) { - throw new IllegalArgumentException("Unrecognized schema type for list " - + getName(simpleType, "{Anonymous List Type}")); + listType = simpleTypeByName(list.getItemTypeName(), "item type of list", + getName(simpleType, "{Anonymous List Type}")); } XmlSchemaScope parentScope = getScope(listType); @@ -199,8 +215,11 @@ final class XmlSchemaScope { case ATOMIC: break; default: - throw new IllegalStateException("Attempted to create a list from a " - + parentScope.getTypeInfo().getType() + " type."); + throw new XmlSchemaException("The list " + + getName(simpleType, "{Anonymous List Type}") + + " has an item type of " + + parentScope.getTypeInfo().getType() + + "; a list item must be atomic or a union."); } typeInfo = new XmlSchemaTypeInfo(parentScope.getTypeInfo()); @@ -216,10 +235,8 @@ final class XmlSchemaScope { } for (QName namedBaseType : namedBaseTypes) { - XmlSchemaSimpleType baseType = (XmlSchemaSimpleType)schemasByNamespace.getTypeByName(namedBaseType); - if (baseType != null) { - baseTypes.add(baseType); - } + baseTypes.add(simpleTypeByName(namedBaseType, "member type of union", + getName(simpleType, "{Anonymous Union Type}"))); } } @@ -228,8 +245,9 @@ final class XmlSchemaScope { * types. */ if ((baseTypes == null) || baseTypes.isEmpty()) { - throw new IllegalArgumentException("Unrecognized base types for union " - + getName(simpleType, "{Anonymous Union Type}")); + throw new XmlSchemaException("The union " + + getName(simpleType, "{Anonymous Union Type}") + + " has no member types."); } List<XmlSchemaTypeInfo> childTypes = new ArrayList<XmlSchemaTypeInfo>(baseTypes.size()); @@ -260,7 +278,8 @@ final class XmlSchemaScope { } else { XmlSchemaSimpleType baseType = restr.getBaseType(); if (baseType == null) { - baseType = (XmlSchemaSimpleType)schemasByNamespace.getTypeByName(restr.getBaseTypeName()); + baseType = simpleTypeByName(restr.getBaseTypeName(), "base type of restriction", + getName(simpleType, "{Anonymous Simple Type}")); } if (baseType != null) { @@ -599,7 +618,8 @@ final class XmlSchemaScope { if (schemaType == null) { final QName typeQName = globalAttr.getSchemaTypeName(); if (typeQName != null) { - schemaType = (XmlSchemaSimpleType) schemasByNamespace.getTypeByName(typeQName); + schemaType = simpleTypeByName(typeQName, "type of attribute", + String.valueOf(globalAttr.getQName())); } } @@ -850,7 +870,7 @@ final class XmlSchemaScope { typeInfo = new XmlSchemaTypeInfo(parentTypeInfo.getBaseType(), facets); break; default: - throw new IllegalStateException("Cannot restrict on a " + parentTypeInfo.getType() + " type."); + throw new XmlSchemaException("Cannot restrict on a " + parentTypeInfo.getType() + " type."); } if (parentTypeInfo.getUserRecognizedType() != null) { diff --git a/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/walker/UnresolvableSimpleTypeTest.java b/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/walker/UnresolvableSimpleTypeTest.java new file mode 100644 index 00000000..4d48439b --- /dev/null +++ b/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/walker/UnresolvableSimpleTypeTest.java @@ -0,0 +1,144 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ws.commons.schema.walker; + +import java.io.StringReader; + +import javax.xml.namespace.QName; + +import org.apache.ws.commons.schema.XmlSchemaCollection; +import org.apache.ws.commons.schema.XmlSchemaElement; +import org.apache.ws.commons.schema.XmlSchemaException; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Where a schema names a type that must be simple, the core parser checks neither that the + * name resolves nor that what it resolves to is simple, so both reach the walker. + */ +public class UnresolvableSimpleTypeTest extends Assert { + + private static final String COMPLEX_TYPE = + "<xs:complexType name=\"ct\"><xs:sequence/></xs:complexType>"; + + private static void walk(String body) { + XmlSchemaCollection collection = new XmlSchemaCollection(); + collection.read(new StringReader( + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:t=\"urn:t\"" + + " targetNamespace=\"urn:t\" elementFormDefault=\"qualified\">" + + body + "</xs:schema>")); + XmlSchemaElement root = collection.getElementByQName(new QName("urn:t", "root")); + assertNotNull(root); + new XmlSchemaWalker(collection).walk(root); + } + + private static void assertRejected(String body, String expectedFragment) { + try { + walk(body); + fail("expected the unusable type reference to be rejected"); + } catch (XmlSchemaException expected) { + assertTrue(expected.getMessage(), expected.getMessage().contains(expectedFragment)); + } + } + + @Test + public void testListItemTypeThatDoesNotResolve() { + assertRejected("<xs:simpleType name=\"l\"><xs:list itemType=\"t:missing\"/></xs:simpleType>" + + "<xs:element name=\"root\" type=\"t:l\"/>", + "does not resolve"); + } + + @Test + public void testListItemTypeThatIsComplex() { + assertRejected(COMPLEX_TYPE + + "<xs:simpleType name=\"l\"><xs:list itemType=\"t:ct\"/></xs:simpleType>" + + "<xs:element name=\"root\" type=\"t:l\"/>", + "complex type"); + } + + @Test + public void testListOfListIsRejected() { + assertRejected("<xs:simpleType name=\"l1\"><xs:list itemType=\"xs:int\"/></xs:simpleType>" + + "<xs:simpleType name=\"l2\"><xs:list itemType=\"t:l1\"/></xs:simpleType>" + + "<xs:element name=\"root\" type=\"t:l2\"/>", + "atomic or a union"); + } + + @Test + public void testUnionMemberThatDoesNotResolve() { + assertRejected("<xs:simpleType name=\"u\"><xs:union memberTypes=\"t:missing\"/></xs:simpleType>" + + "<xs:element name=\"root\" type=\"t:u\"/>", + "does not resolve"); + } + + @Test + public void testUnionMemberThatIsComplex() { + assertRejected(COMPLEX_TYPE + + "<xs:simpleType name=\"u\"><xs:union memberTypes=\"xs:int t:ct\"/></xs:simpleType>" + + "<xs:element name=\"root\" type=\"t:u\"/>", + "complex type"); + } + + @Test + public void testRestrictionBaseThatDoesNotResolve() { + assertRejected("<xs:simpleType name=\"s\"><xs:restriction base=\"t:missing\"/></xs:simpleType>" + + "<xs:element name=\"root\" type=\"t:s\"/>", + "does not resolve"); + } + + @Test + public void testRestrictionBaseThatIsComplex() { + assertRejected(COMPLEX_TYPE + + "<xs:simpleType name=\"s\"><xs:restriction base=\"t:ct\"/></xs:simpleType>" + + "<xs:element name=\"root\" type=\"t:s\"/>", + "complex type"); + } + + @Test + public void testAttributeTypedByAComplexType() { + assertRejected(COMPLEX_TYPE + + "<xs:element name=\"root\"><xs:complexType>" + + "<xs:attribute name=\"a\" type=\"t:ct\"/></xs:complexType></xs:element>", + "complex type"); + } + + @Test + public void testSimpleContentRestrictionOfAComplexBase() { + assertRejected("<xs:complexType name=\"b\"><xs:complexContent>" + + "<xs:restriction base=\"xs:anyType\"><xs:sequence/></xs:restriction>" + + "</xs:complexContent></xs:complexType>" + + "<xs:complexType name=\"ct2\"><xs:simpleContent>" + + "<xs:restriction base=\"t:b\"/></xs:simpleContent></xs:complexType>" + + "<xs:element name=\"root\" type=\"t:ct2\"/>", + "Cannot restrict"); + } + + @Test + public void testWellFormedSimpleTypesStillWalk() { + walk("<xs:simpleType name=\"u\"><xs:union memberTypes=\"xs:int xs:string\"/></xs:simpleType>" + + "<xs:simpleType name=\"l\"><xs:list itemType=\"t:u\"/></xs:simpleType>" + + "<xs:simpleType name=\"r\"><xs:restriction base=\"xs:string\">" + + "<xs:maxLength value=\"8\"/></xs:restriction></xs:simpleType>" + + "<xs:element name=\"root\"><xs:complexType><xs:sequence>" + + "<xs:element name=\"a\" type=\"t:l\"/><xs:element name=\"b\" type=\"t:r\"/>" + + "</xs:sequence><xs:attribute name=\"c\" type=\"t:u\"/></xs:complexType></xs:element>"); + } +}
