Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,34 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
Object deserialized = null;
JsonElement jsonElement = elementAdapter.read(in);

{{#useOneOfDiscriminatorLookup}}
{{#discriminator}}
// non-object payloads can still match a non-object anyOf schema below
if (jsonElement.isJsonObject()) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonElement discriminatorElement = jsonObject.get("{{{propertyBaseName}}}");

// use discriminator value for faster anyOf lookup
{{classname}} new{{classname}} = new {{classname}}();
if (discriminatorElement == null || !discriminatorElement.isJsonPrimitive()) {
log.log(Level.WARNING, "Failed to lookup discriminator value for {{classname}} as `{{{propertyBaseName}}}` is missing or is not a primitive type in the payload.");
} else {
// look up the discriminator value in the field `{{{propertyBaseName}}}`
switch (discriminatorElement.getAsString()) {
{{#mappedModels}}
case "{{{mappingName}}}":
deserialized = adapter{{modelName}}.fromJsonTree(jsonObject);
new{{classname}}.setActualInstance(deserialized);
return new{{classname}};
{{/mappedModels}}
default:
log.log(Level.WARNING, String.format(java.util.Locale.ROOT, "Failed to lookup discriminator value `%s` for {{classname}}. Possible values:{{#mappedModels}} {{{mappingName}}}{{/mappedModels}}", discriminatorElement.getAsString()));
}
}
}

{{/discriminator}}
{{/useOneOfDiscriminatorLookup}}
ArrayList<String> errorMessages = new ArrayList<>();
TypeAdapter actualAdapter = elementAdapter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,36 @@ public MammalAnyof read(JsonReader in) throws IOException {
Object deserialized = null;
JsonElement jsonElement = elementAdapter.read(in);

// non-object payloads can still match a non-object anyOf schema below
if (jsonElement.isJsonObject()) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonElement discriminatorElement = jsonObject.get("className");

// use discriminator value for faster anyOf lookup
MammalAnyof newMammalAnyof = new MammalAnyof();
if (discriminatorElement == null || !discriminatorElement.isJsonPrimitive()) {
log.log(Level.WARNING, "Failed to lookup discriminator value for MammalAnyof as `className` is missing or is not a primitive type in the payload.");
} else {
// look up the discriminator value in the field `className`
switch (discriminatorElement.getAsString()) {
case "Pig":
deserialized = adapterPig.fromJsonTree(jsonObject);
newMammalAnyof.setActualInstance(deserialized);
return newMammalAnyof;
case "whale":
deserialized = adapterWhale.fromJsonTree(jsonObject);
newMammalAnyof.setActualInstance(deserialized);
return newMammalAnyof;
case "zebra":
deserialized = adapterZebra.fromJsonTree(jsonObject);
newMammalAnyof.setActualInstance(deserialized);
return newMammalAnyof;
default:
log.log(Level.WARNING, String.format(java.util.Locale.ROOT, "Failed to lookup discriminator value `%s` for MammalAnyof. Possible values: Pig whale zebra", discriminatorElement.getAsString()));
}
}
}

ArrayList<String> errorMessages = new ArrayList<>();
TypeAdapter actualAdapter = elementAdapter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,59 @@ public void testOneOfSchemaWithDiscriminator() throws Exception {
}
}

/**
* Validate an anyOf schema can be deserialized into the expected class.
* The anyOf schema has a discriminator.
*/
@Test
public void testAnyOfSchemaWithDiscriminator() throws Exception {
{
// Zebra is listed after Whale in anyOf, and a zebra payload also satisfies Whale
// (className is Whale's only required field), so without the discriminator lookup
// this deserializes as Whale.
String str = "{ \"className\": \"zebra\", \"type\": \"plains\" }";

MammalAnyof o = json.getGson().fromJson(str, MammalAnyof.class);
assertTrue(o.getActualInstance() instanceof Zebra);
Zebra inst = (Zebra) o.getActualInstance();
assertEquals(inst.getClassName(), "zebra");
assertEquals(inst.toJson(), "{\"type\":\"plains\",\"className\":\"zebra\"}");
assertEquals(o.toJson(), "{\"type\":\"plains\",\"className\":\"zebra\"}");
}
{
String str = "{ \"className\": \"whale\", \"hasBaleen\": false, \"hasTeeth\": false }";

MammalAnyof o = json.getGson().fromJson(str, MammalAnyof.class);
assertTrue(o.getActualInstance() instanceof Whale);
Whale inst = (Whale) o.getActualInstance();
assertEquals(inst.getClassName(), "whale");
assertEquals(inst.getHasBaleen(), false);
assertEquals(inst.getHasTeeth(), false);
assertEquals(inst.toJson(), "{\"hasBaleen\":false,\"hasTeeth\":false,\"className\":\"whale\"}");
assertEquals(json.getGson().toJson(o), "{\"hasBaleen\":false,\"hasTeeth\":false,\"className\":\"whale\"}");
assertEquals(o.toJson(), "{\"hasBaleen\":false,\"hasTeeth\":false,\"className\":\"whale\"}");
}
{
// an unmapped discriminator value falls back to matching the anyOf schemas in order
String str = "{ \"className\": \"dolphin\", \"hasBaleen\": true }";

MammalAnyof o = json.getGson().fromJson(str, MammalAnyof.class);
assertTrue(o.getActualInstance() instanceof Whale);
Whale inst = (Whale) o.getActualInstance();
assertEquals(inst.getClassName(), "dolphin");
assertEquals(inst.getHasBaleen(), true);
}
{
// Try to deserialize empty object. This should fail 'anyOf' because none will match
// whale, zebra or Pig.
String str = "{ }";
Exception exception = assertThrows(com.google.gson.JsonSyntaxException.class, () -> {
json.getGson().fromJson(str, MammalAnyof.class);
});
assertTrue(exception.getMessage().contains("java.io.IOException: Failed deserialization for MammalAnyof"));
}
}

/**
* Test JSON validation method
*/
Expand Down
Loading