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 @@ -9,6 +9,7 @@ use JMS\Serializer\Serializer;
use JMS\Serializer\Visitor\Factory\XmlDeserializationVisitorFactory;
use DateTime;
use RuntimeException;
use JMS\Serializer\Exception\RuntimeException as SerializerRuntimeException;

class JmsSerializer implements SerializerInterface
{
Expand Down Expand Up @@ -122,7 +123,7 @@ class JmsSerializer implements SerializerInterface

$enum = $type::tryFrom($data);
if (!$enum) {
throw new RuntimeException(sprintf("Unknown %s value in %s enum", $data, $type));
throw new SerializerRuntimeException(sprintf("Unknown %s value in %s enum", $data, $type));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if there's a demand to fallback to runtime exception for whatever reasons, we will add an option for the fallback.

}

return $enum;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,76 @@ public void testPetstoreDottedEnumRefQueryParameterUsesShortClassInApiInterface(
output.deleteOnExit();
}

/**
* Guards {@code php-symfony} {@code JmsSerializer.mustache}: invalid query values for a generated PHP
* {@code BackedEnum} are deserialized in {@code JmsSerializer::deserializeString()}. The generated
* {@code DefaultController} wraps {@code deserialize(...)} with {@code catch (SerializerRuntimeException)},
* an alias of {@code JMS\Serializer\Exception\RuntimeException}. Only the unknown-enum branch must throw that
* type; other string-deserialization errors may keep using PHP's global {@code RuntimeException}.
* <p>
* This test asserts the generated {@code JmsSerializer.php} keeps {@code use RuntimeException;} and adds
* {@code use JMS\Serializer\Exception\RuntimeException as SerializerRuntimeException;}, throws
* {@code SerializerRuntimeException} for {@code tryFrom} failure, and that {@code DefaultController.php} still
* catches {@code SerializerRuntimeException}.
* <p>
* Spec: {@code src/test/resources/3_1/php-symfony/jms-enum-query-invalid-deserialization.yaml}. Background:
* {@code fix_jms_enum_ex.md}.
*/
@Test
public void testJmsSerializerUsesJmsRuntimeExceptionForBackedEnumStringDeserializationErrors() throws Exception {
Map<String, Object> properties = new HashMap<>();
properties.put("invokerPackage", "Org\\OpenAPITools\\PetstoreEnum");

File output = Files.createTempDirectory("test").toFile();

final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("php-symfony")
.setAdditionalProperties(properties)
.setInputSpec("src/test/resources/3_1/php-symfony/jms-enum-query-invalid-deserialization.yaml")
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));

final ClientOptInput clientOptInput = configurator.toClientOptInput();
DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(clientOptInput).generate();

File jmsSerializer = files.stream()
.filter(f -> "JmsSerializer.php".equals(f.getName()) && f.getPath().contains("Service" + File.separator))
.findFirst()
.orElseThrow(() -> new AssertionError("JmsSerializer.php not generated"));

String jms = Files.readString(jmsSerializer.toPath(), StandardCharsets.UTF_8);

Assert.assertTrue(
jms.contains("Unknown %s value in %s enum"),
"Expected BackedEnum tryFrom failure message in generated JmsSerializer");
Assert.assertTrue(
Pattern.compile("^use RuntimeException;\\s*$", Pattern.MULTILINE).matcher(jms).find(),
"JmsSerializer should keep use RuntimeException for generic unsupported-type errors");
Assert.assertTrue(
jms.contains("use JMS\\Serializer\\Exception\\RuntimeException as SerializerRuntimeException;"),
"JmsSerializer must alias JMS RuntimeException as SerializerRuntimeException (same as DefaultController)");
Assert.assertTrue(
jms.contains("throw new SerializerRuntimeException(sprintf(\"Unknown %s value in %s enum\", $data, $type));"),
"Invalid BackedEnum tryFrom must throw SerializerRuntimeException so DefaultController catch applies");

File defaultController = files.stream()
.filter(f -> "DefaultController.php".equals(f.getName()) && f.getPath().contains("Controller" + File.separator))
.findFirst()
.orElseThrow(() -> new AssertionError("DefaultController.php not generated"));
String controller = Files.readString(defaultController.toPath(), StandardCharsets.UTF_8);
Assert.assertTrue(
controller.contains("use JMS\\Serializer\\Exception\\RuntimeException as SerializerRuntimeException;"),
"Expected DefaultController to catch SerializerRuntimeException alias");
Assert.assertTrue(
controller.contains("catch (SerializerRuntimeException $exception)"),
"Expected deserialize() to catch SerializerRuntimeException");

assertGeneratedPhpSyntaxValid(jmsSerializer);
assertGeneratedPhpSyntaxValid(defaultController);

output.deleteOnExit();
}

/**
* Optional {@code in: query} parameter: {@code required: false}, schema is an enum {@code $ref} with a valid
* {@code default} (see OpenAPI 3.x). Omitting the query key must be equivalent to sending that default; the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
openapi: 3.1.0
info:
title: php-symfony JMS invalid query enum deserialization
version: '1.0'
paths:
/pets:
get:
operationId: listPets
parameters:
- name: status
in: query
required: false
schema:
$ref: '#/components/schemas/Pet.Model.PetStatus'
responses:
'200':
description: OK
components:
schemas:
Pet.Model.PetStatus:
type: string
enum:
- available
- pending
- sold
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use JMS\Serializer\Visitor\Factory\XmlDeserializationVisitorFactory;
use DateTime;
use RuntimeException;
use JMS\Serializer\Exception\RuntimeException as SerializerRuntimeException;

class JmsSerializer implements SerializerInterface
{
Expand Down Expand Up @@ -122,7 +123,7 @@ private function deserializeString($data, string $type)

$enum = $type::tryFrom($data);
if (!$enum) {
throw new RuntimeException(sprintf("Unknown %s value in %s enum", $data, $type));
throw new SerializerRuntimeException(sprintf("Unknown %s value in %s enum", $data, $type));
}

return $enum;
Expand Down
Loading