[java][okhttp-gson] Add typed constructors and is<Member>() checks to oneOf and anyOf models
Summary
okhttp-gson oneOf/anyOf models only have an Object constructor and a getActualInstance() that returns Object, so nothing in the API says which types a union accepts, and reading a value takes an instanceof check against each member. The native library already generates one constructor per member. This adds the same constructors to okhttp-gson, plus an is<Member>() check next to each get<Member>().
For example, a pet status that accepts the known values and any status the server adds later:
PetStatus:
type: string
enum: [available, pending, sold]
OpenPetStatus:
anyOf:
- $ref: '#/components/schemas/PetStatus'
- type: string
Pet:
type: object
required: [status]
properties:
status:
$ref: '#/components/schemas/OpenPetStatus'
// before
Pet pet = new Pet().status(new OpenPetStatus(PetStatus.AVAILABLE)); // OpenPetStatus(Object)
OpenPetStatus status = pet.getStatus();
if (status.getActualInstance() instanceof PetStatus) {
PetStatus known = status.getPetStatus();
} else if (status.getActualInstance() instanceof String) {
String unknown = status.getString();
}
// after
Pet pet = new Pet().status(new OpenPetStatus(PetStatus.AVAILABLE)); // OpenPetStatus(PetStatus)
Pet adopted = new Pet().status(new OpenPetStatus("adopted")); // OpenPetStatus(String)
OpenPetStatus status = pet.getStatus();
if (status.isPetStatus()) {
PetStatus known = status.getPetStatus();
} else if (status.isString()) {
String unknown = status.getString();
}
The generated additions for OpenPetStatus:
public class OpenPetStatus extends AbstractOpenApiSchema {
public OpenPetStatus(Object o) { ... }
+ public OpenPetStatus(PetStatus o) { this(); setActualInstance(o); }
+ public OpenPetStatus(String o) { this(); setActualInstance(o); }
public PetStatus getPetStatus() throws ClassCastException { ... }
+ public boolean isPetStatus() { return super.getActualInstance() instanceof PetStatus; }
public String getString() throws ClassCastException { ... }
+ public boolean isString() { return super.getActualInstance() instanceof String; }
Members skip what would clash or mislead:
- Constructors: a member with the same erasure as an earlier one (
List<Integer>afterList<BigDecimal>) gets none, as innative(x-duplicated-data-type). Free-form and any-type members get none either, because their type isObjectand the existing constructor already covers them. is<Member>(): container members get none, becauseinstanceof Listcan't tellList<Pet>from another list. Free-form and any-type members get none either, because every value is anObject. A member namedNullablegets none, becauseAbstractOpenApiSchemaalready declaresBoolean isNullable().
The Object constructor stays, so existing code keeps compiling, and a wrong type still fails at runtime in setActualInstance as before.
Evidence
- Both snippets above compile and run against clients generated from the schema above, before (7.27.0) and after.
"available"reads asPetStatus.AVAILABLE,"adopted"reads as the string, and both write back unchanged. - New
testOkHttpGsonOneOfAnyOfTypedConstructorswith spec3_0/java/okhttp-gson-composed-typed-constructors.yaml, covering enum and string, numeric and boolean, model and list, same-erasure lists, free-form, any-type and nullable members, and a member model namedNullable.JavaClientCodegenTest: 321 passed. - A client generated from that spec resolves overloads and checks to the right member:
new Scalar(5)isisInteger(),new Scalar(5L)isisLong(), andnew PetOrPets(List.of(pet)).isPet()isfalse. ./bin/generate-samples.sh ./bin/configs/*.yamlchanges 32 files in 5okhttp-gsonsamples, all of them additions. All 5 samples passmvn test-compile.
Merge Danger
Door: two-way. Templates only.
Blast Radius: okhttp-gson unions.
Additive, with one source-compatibility edge: when a model has two or more typed constructors, new X(null) with an untyped null no longer compiles because the call is ambiguous. new X() or a cast such as (String) null works.
PR checklist
- Read the contribution guidelines.
- Run the following to build the project and update samples:
Commit all changed files../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.
@bbdouglas @sreeshas @jfiala @lukoyanov @cbornet @jeff9finger @karismann @Zomzog @lwlee2608 @martin-mfg @KannaKim: review requested for the Java okhttp-gson template change.