Skip to content

Commit b634273

Browse files
authored
[core] Allow oneOf members that declare x-implements (#23577) (#24076)
OneOfImplementorAdditionalData.addToImplementor used putIfAbsent + List.add on the model's x-implements vendor extension. When a oneOf member schema already declares x-implements in the spec, the parsed value is a scalar string or an immutable list, so appending the oneOf interface threw java.lang.UnsupportedOperationException during model post-processing. Normalize the existing value into a fresh mutable list (preserving any user-supplied interfaces) before appending. No behavior change for models without a pre-existing x-implements.
1 parent c7d1e10 commit b634273

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/OneOfImplementorAdditionalData.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,20 @@ public void addFromInterfaceModel(CodegenModel cm, List<Map<String, String>> mod
103103
*/
104104
@SuppressWarnings("unchecked")
105105
public void addToImplementor(CodegenConfig cc, CodegenModel implcm, List<Map<String, String>> implImports, boolean addInterfaceImports) {
106-
implcm.getVendorExtensions().putIfAbsent(X_IMPLEMENTS, new ArrayList<String>());
106+
// The model may already declare x-implements in the spec, in which case the parsed value can be
107+
// a scalar string or an immutable list. Normalize it to a fresh mutable list (preserving any
108+
// existing entries) so the oneOf interfaces below can be appended without failing.
109+
Object existing = implcm.getVendorExtensions().get(X_IMPLEMENTS);
110+
List<String> impl = new ArrayList<>();
111+
if (existing instanceof Collection) {
112+
impl.addAll((Collection<String>) existing);
113+
} else if (existing instanceof String && !((String) existing).isEmpty()) {
114+
impl.add((String) existing);
115+
}
116+
implcm.getVendorExtensions().put(X_IMPLEMENTS, impl);
107117

108118
// Add implemented interfaces
109119
for (String intf : additionalInterfaces) {
110-
List<String> impl = (List<String>) implcm.getVendorExtensions().get(X_IMPLEMENTS);
111120
impl.add(intf);
112121
if (addInterfaceImports) {
113122
// Add imports for interfaces

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7995,6 +7995,19 @@ void oneOf_issue_23577() throws IOException {
79957995
.fileContains("String type;");
79967996
}
79977997

7998+
@Test
7999+
void oneOf_issue_23577_userDefinedXImplements() throws IOException {
8000+
// Default oneOf-interface generation (without REPLACE_ONE_OF_BY_DISCRIMINATOR_MAPPING):
8001+
// a member schema that already declares its own x-implements must still be able to
8002+
// receive the oneOf interface, i.e. the user-supplied x-implements value must remain mutable.
8003+
Map<String, File> files = generateFromContract("src/test/resources/3_0/oneOf_issue_23577.yaml", SPRING_BOOT,
8004+
Map.of(GENERATE_MODEL_DOCS, false, GENERATE_APIS, false, INTERFACE_ONLY, true));
8005+
JavaFileAssert.assertThat(files.get("CreatedEvent.java"))
8006+
.implementsInterfaces("com.example.Notification", "Event");
8007+
JavaFileAssert.assertThat(files.get("UpdatedEvent.java"))
8008+
.implementsInterfaces("Event");
8009+
}
8010+
79988011
@Test
79998012
void oneof_polymorphism_and_inheritance() throws IOException {
80008013
Map<String, File> files = generateFromContract("src/test/resources/3_0/oneof_polymorphism_and_inheritance.yaml", SPRING_BOOT,

0 commit comments

Comments
 (0)