Skip to content

Commit a3383fb

Browse files
committed
fix oneof methods name
When there is a oneof with at least two similar type, ie List<string> and List<int> this cause some conflict.
1 parent 3b91626 commit a3383fb

File tree

3 files changed

+92
-10
lines changed

3 files changed

+92
-10
lines changed

.generator/src/generator/cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def cli(specs, output):
6868
env.globals["get_default"] = openapi.get_default
6969
env.globals["get_container_type"] = openapi.get_container_type
7070
env.globals["get_security_names"] = openapi.get_security_names
71+
env.globals["prepare_oneof_methods"] = formatter.prepare_oneof_methods
7172

7273
api_j2 = env.get_template("Api.j2")
7374
model_j2 = env.get_template("model.j2")

.generator/src/generator/formatter.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,3 +650,76 @@ def get_response_type(schema, version):
650650

651651
def attribute_path(attribute):
652652
return ".".join(attribute_name(a) for a in attribute.split("."))
653+
654+
655+
def prepare_oneof_methods(model, get_type_func):
656+
"""
657+
Pre-compute method information for oneOf types to handle erasure collisions.
658+
659+
Returns a list of dicts with:
660+
- schema: the original oneOf schema
661+
- param_type: full parameterized type (e.g., "List<String>")
662+
- unparam_type: unparameterized type (e.g., "List")
663+
- use_factory: True if factory method needed (collision detected)
664+
- constructor_name: name for constructor/factory method
665+
- getter_name: name for getter method
666+
"""
667+
# Handle both dict-style and object-style access
668+
if isinstance(model, dict):
669+
one_of = model.get('oneOf', [])
670+
elif hasattr(model, 'oneOf'):
671+
one_of = model.oneOf
672+
elif hasattr(model, 'get'):
673+
one_of = model.get('oneOf', [])
674+
else:
675+
return []
676+
677+
if not one_of:
678+
return []
679+
680+
# First pass: count unparameterized types
681+
unparam_counts = {}
682+
for oneOf in one_of:
683+
param_type = get_type_func(oneOf)
684+
unparam_type = un_parameterize_type(param_type)
685+
unparam_counts[unparam_type] = unparam_counts.get(unparam_type, 0) + 1
686+
687+
# Second pass: compute method names
688+
result = []
689+
for oneOf in one_of:
690+
param_type = get_type_func(oneOf)
691+
unparam_type = un_parameterize_type(param_type)
692+
has_collision = unparam_counts[unparam_type] > 1
693+
694+
# Compute constructor/factory method name
695+
if has_collision:
696+
if param_type.startswith('List<'):
697+
inner_type = param_type[5:-1]
698+
constructor_name = f"from{inner_type}List"
699+
else:
700+
safe_type = param_type.replace('<', '').replace('>', '').replace(' ', '').replace(',', '')
701+
constructor_name = f"from{safe_type}"
702+
else:
703+
constructor_name = None # Regular constructor
704+
705+
# Compute getter method name
706+
if has_collision:
707+
if param_type.startswith('List<'):
708+
inner_type = param_type[5:-1]
709+
getter_name = f"get{inner_type}List"
710+
else:
711+
safe_type = param_type.replace('<', '').replace('>', '').replace(' ', '').replace(',', '')
712+
getter_name = f"get{safe_type}"
713+
else:
714+
getter_name = f"get{unparam_type}"
715+
716+
result.append({
717+
'schema': oneOf,
718+
'param_type': param_type,
719+
'unparam_type': unparam_type,
720+
'use_factory': has_collision,
721+
'constructor_name': constructor_name,
722+
'getter_name': getter_name,
723+
})
724+
725+
return result

.generator/src/generator/templates/modelOneOf.j2

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,20 @@ public class {{ name }} extends AbstractOpenApiSchema {
139139
super("oneOf", Boolean.{{ "TRUE" if model.nullable else "FALSE" }});
140140
}
141141

142-
{%- for oneOf in model.oneOf %}
143-
public {{ name }}({{ get_type(oneOf) }} o) {
142+
{%- set oneof_methods = prepare_oneof_methods(model, get_type) %}
143+
{%- for method_info in oneof_methods %}
144+
{%- if method_info.use_factory %}
145+
public static {{ name }} {{ method_info.constructor_name }}({{ method_info.param_type }} o) {
146+
{{ name }} instance = new {{ name }}();
147+
instance.setActualInstance(o);
148+
return instance;
149+
}
150+
{%- else %}
151+
public {{ name }}({{ method_info.param_type }} o) {
144152
super("oneOf", Boolean.{{ "TRUE" if model.nullable else "FALSE" }});
145153
setActualInstance(o);
146154
}
155+
{%- endif %}
147156
{%- endfor %}
148157

149158
static {
@@ -204,19 +213,18 @@ public class {{ name }} extends AbstractOpenApiSchema {
204213
return super.getActualInstance();
205214
}
206215

207-
{%- for oneOf in model.oneOf %}
208-
{%- set dataType = get_type(oneOf) %}
209-
{%- set unParameterizedDataType = get_type(oneOf)|un_parameterize_type %}
216+
{%- set oneof_methods = prepare_oneof_methods(model, get_type) %}
217+
{%- for method_info in oneof_methods %}
210218

211219
/**
212-
* Get the actual instance of `{{ dataType|escape_html }}`. If the actual instance is not `{{ dataType|escape_html }}`,
220+
* Get the actual instance of `{{ method_info.param_type|escape_html }}`. If the actual instance is not `{{ method_info.param_type|escape_html }}`,
213221
* the ClassCastException will be thrown.
214222
*
215-
* @return The actual instance of `{{ dataType|escape_html }}`
216-
* @throws ClassCastException if the instance is not `{{ dataType|escape_html }}`
223+
* @return The actual instance of `{{ method_info.param_type|escape_html }}`
224+
* @throws ClassCastException if the instance is not `{{ method_info.param_type|escape_html }}`
217225
*/
218-
public {{ dataType }} get{{ unParameterizedDataType }}() throws ClassCastException {
219-
return ({{ dataType }})super.getActualInstance();
226+
public {{ method_info.param_type }} {{ method_info.getter_name }}() throws ClassCastException {
227+
return ({{ method_info.param_type }})super.getActualInstance();
220228
}
221229

222230
{%- endfor %}

0 commit comments

Comments
 (0)