[normalizer] Preserve AnyType for typeless OAS 3.0 schemas in referenced files
Fixes #25412
Summary
When an OpenAPI 3.0 specification references an external file (such as a PathItem, ApiResponse, Parameter, RequestBody, or a whole-file schema $ref such as sailpoint-oss/api-specs), swagger-parser's ResolverCache.loadRef deserializes the external node via Jackson (ModelDeserializer). Because ModelDeserializer.useArbitrarySchema defaults to false, ModelDeserializer.deserializeArbitraryOrObjectSchema instantiates typeless schemas (description: ... with no type, properties, or additionalProperties) as ObjectSchema (type: "object"), while storing the raw parsed JSON/YAML map in schema.getJsonSchema() (where !schema.getJsonSchema().containsKey("type")).
By contrast, the same typeless schema in the root OpenAPI 3.0 document is parsed by OpenAPIDeserializer via SchemaTypeUtil.createSchemaByType(node) into a base Schema instance (type == null), which OpenAPI Generator maps to AnyType.
Changes
OpenAPINormalizer.java:- In
normalizeSimpleSchema(Schema schema, Set<Schema> visitedSchemas)(reached only after confirming the schema is not an array, not aComposedSchema, has noproperties, and has noSchemaadditionalProperties), check whether anObjectSchemahas a rawjsonSchemamap without"type"or"properties"keys and no object-specific constraints (schema instanceof ObjectSchema && schema.getJsonSchema() != null && !schema.getJsonSchema().containsKey("type") && !schema.getJsonSchema().containsKey("properties") && schema.getProperties() == null && schema.getAdditionalProperties() == null && schema.getRequired() == null && schema.getMinProperties() == null && schema.getMaxProperties() == null && schema.getPatternProperties() == null && schema.getDiscriminator() == null && schema.getEnum() == null) and convert it to a basenew Schema<>()(type == null) with metadata and validation fields copied viaModelUtils.copyMetadata(schema, sc)(pluspattern,format,multipleOf,uniqueItems,exclusiveMinimum,exclusiveMaximum,exclusiveMinimumValue,exclusiveMaximumValue,not,xml,externalDocs, andjsonSchema), matching the OAS 3.1AnyTypehandling inprocessNormalize31Spec. - In
normalizeSchema's array and map branches, assignresult.setItems(normalizeSchema(result.getItems(), visitedSchemas))andresult.setAdditionalProperties(normalized)so normalized arrayitemsand mapadditionalPropertiesschemas are not discarded.
- In
OpenAPINormalizerTest.java:- Real-world multi-file spec check (sailpoint-oss/api-specs, OAS 3.0): Verified against referenced PathItem schemas that omit type for arbitrary variable values. Resolved schemas and generated Python models now preserve AnyType instead of coercing to
type: object. - Add
testTypelessSchemaInReferencedFileRemainsAnyTypeverifying that typeless schemas in referenced files (via aPathItemresponse, a whole-file schema$ref, and an arrayitems$ref) normalize toAnyType(type == null,isObjectSchema == false,isFreeFormObject == false) while explicittype: objectandrequired: [id]schemas in referenced files preserve their object semantics and constraints.
cc @OpenAPITools/generator-core-team
- Real-world multi-file spec check (sailpoint-oss/api-specs, OAS 3.0): Verified against referenced PathItem schemas that omit type for arbitrary variable values. Resolved schemas and generated Python models now preserve AnyType instead of coercing to
PR checklist
- Read the contribution guidelines.
- Run the following to build the project and update samples:
./mvnw clean package || exit ./bin/generate-samples.sh ./bin/configs/*.yaml || exit ./bin/utils/export_docs_generators.sh || exit - If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.