-
Notifications
You must be signed in to change notification settings - Fork 7
wip: Decoupling argument injection from store business #31
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| <?php | ||
|
|
||
| /* | ||
| * This file is part of the StepArgumentInjectorBehatExtension project. | ||
| * | ||
| * (c) Rodrigue Villetard <[email protected]> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Gorghoa\StepArgumentInjectorBehatExtension\Annotation; | ||
|
|
||
| /** | ||
| * @author Rodrigue Villetard <[email protected]> | ||
| */ | ||
| interface StepInjectorArgument | ||
| { | ||
| /** | ||
| * @return string | ||
| */ | ||
| public function getName(); | ||
|
|
||
| /** | ||
| * @return string | ||
| */ | ||
| public function getArgument(); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,47 +1,48 @@ | ||
| <?php | ||
|
|
||
| /* | ||
| * This file is part of the ScenarioStateBehatExtension project. | ||
| * This file is part of the StepArgumentInjectorBehatExtension project. | ||
| * | ||
| * (c) Rodrigue Villetard <[email protected]> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Gorghoa\ScenarioStateBehatExtension\Argument; | ||
| namespace Gorghoa\StepArgumentInjectorBehatExtension\Argument; | ||
|
|
||
| use Behat\Testwork\Argument\ArgumentOrganiser; | ||
| use Behat\Testwork\Argument\ArgumentOrganiser as BehatArgumentOrganiser; | ||
| use Doctrine\Common\Annotations\Reader; | ||
| use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; | ||
| use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; | ||
| use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepArgumentInjectorArgument; | ||
| use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; | ||
| // use Gorghoa\StepArgumentInjectorBehatExtension\Context\Initializer\StepArgumentInjectorInitializer; | ||
| use ReflectionFunctionAbstract; | ||
|
|
||
| /** | ||
| * @author Rodrigue Villetard <[email protected]> | ||
| * @author Vincent Chalamon <[email protected]> | ||
| */ | ||
| final class ScenarioStateArgumentOrganiser implements ArgumentOrganiser | ||
| final class ArgumentOrganiser implements BehatArgumentOrganiser | ||
| { | ||
| /** | ||
| * @var ArgumentOrganiser | ||
| * @var BehatArgumentOrganiser | ||
| */ | ||
| private $baseOrganiser; | ||
|
|
||
| /** | ||
| * @var ScenarioStateInitializer | ||
| * @var StepArgumentInjectorInitializer | ||
| */ | ||
| private $store; | ||
| private $hookers; | ||
|
||
|
|
||
| /** | ||
| * @var Reader | ||
| */ | ||
| private $reader; | ||
|
|
||
| public function __construct(ArgumentOrganiser $organiser, ScenarioStateInitializer $store, Reader $reader) | ||
| public function __construct(BehatArgumentOrganiser $organiser, array $hookers, Reader $reader) | ||
| { | ||
| $this->baseOrganiser = $organiser; | ||
| $this->store = $store; | ||
| $this->hookers = $hookers; | ||
| $this->reader = $reader; | ||
| } | ||
|
|
||
|
|
@@ -59,16 +60,21 @@ public function organiseArguments(ReflectionFunctionAbstract $function, array $m | |
| return $this->baseOrganiser->organiseArguments($function, $match); | ||
| } | ||
|
|
||
| /** @var ScenarioStateArgument[] $annotations */ | ||
| /** @var StepArgumentInjectorArgument[] $annotations */ | ||
|
||
| $annotations = $this->reader->getMethodAnnotations($function); | ||
| $store = $this->store->getStore(); | ||
|
|
||
| foreach ($annotations as $annotation) { | ||
| if ($annotation instanceof ScenarioStateArgument && | ||
| in_array($annotation->getArgument(), $paramsKeys) && | ||
| $store->hasStateFragment($annotation->getName()) | ||
| if ($annotation instanceof StepInjectorArgument && | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if (!$annotation instanceof StepInjectorArgument ||
!in_array($argument = $annotation->getArgument(), $paramsKeys)
) {
continue;
} |
||
| in_array($annotation->getArgument(), $paramsKeys) | ||
| ) { | ||
| $match[$annotation->getArgument()] = $store->getStateFragment($annotation->getName()); | ||
| $match[strval(++$i)] = $store->getStateFragment($annotation->getName()); | ||
| foreach ($this->hookers as $hooker) { | ||
| if ($hooker->hasStepArgumentFor($annotation->getName())) { | ||
|
||
| $match[$annotation->getArgument()] | ||
| = $match[strval(++$i)] | ||
| = $hooker->getStepArgumentFor($annotation->getName()) | ||
| ; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| <?php | ||
|
|
||
| /* | ||
| * This file is part of the StepArgumentInjectorBehatExtension project. | ||
| * | ||
| * (c) Rodrigue Villetard <[email protected]> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Gorghoa\StepArgumentInjectorBehatExtension\Argument; | ||
|
|
||
| /** | ||
| * @author Rodrigue Villetard <[email protected]> | ||
| */ | ||
| interface StepArgumentHolder | ||
| { | ||
| public function hasStepArgumentFor($key); | ||
|
||
|
|
||
| public function getStepArgumentFor($key); | ||
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,22 +1,22 @@ | ||
| <?php | ||
|
|
||
| /* | ||
| * This file is part of the ScenarioStateBehatExtension project. | ||
| * This file is part of the StepArgumentInjectorBehatExtension project. | ||
| * | ||
| * (c) Rodrigue Villetard <[email protected]> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Gorghoa\ScenarioStateBehatExtension\Call\Handler; | ||
| namespace Gorghoa\StepArgumentInjectorBehatExtension\Call\Handler; | ||
|
|
||
| use Behat\Behat\Transformation\Call\TransformationCall; | ||
| use Behat\Testwork\Call\Call; | ||
| use Behat\Testwork\Call\Handler\CallHandler; | ||
| use Behat\Testwork\Environment\Call\EnvironmentCall; | ||
| use Behat\Testwork\Hook\Call\HookCall; | ||
| use Gorghoa\ScenarioStateBehatExtension\Resolver\ArgumentsResolver; | ||
| use Gorghoa\StepArgumentInjectorBehatExtension\Resolver\ArgumentsResolver; | ||
|
|
||
| /** | ||
| * @author Vincent Chalamon <[email protected]> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,42 +1,40 @@ | ||
| <?php | ||
|
|
||
| /* | ||
| * This file is part of the ScenarioStateBehatExtension project. | ||
| * This file is part of the StepArgumentInjectorBehatExtension project. | ||
| * | ||
| * (c) Rodrigue Villetard <[email protected]> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Gorghoa\ScenarioStateBehatExtension\Resolver; | ||
| namespace Gorghoa\StepArgumentInjectorBehatExtension\Resolver; | ||
|
|
||
| use Doctrine\Common\Annotations\Reader; | ||
| use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; | ||
| use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; | ||
| use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; | ||
|
|
||
| /** | ||
| * @author Vincent Chalamon <[email protected]> | ||
| */ | ||
| class ArgumentsResolver | ||
| { | ||
| /** | ||
| * @var ScenarioStateInitializer | ||
| * @var Reader | ||
| */ | ||
| private $store; | ||
| private $reader; | ||
|
|
||
| /** | ||
| * @var Reader | ||
| * @var array | ||
| */ | ||
| private $reader; | ||
| private $hookers; | ||
|
||
|
|
||
| /** | ||
| * @param ScenarioStateInitializer $store | ||
| * @param Reader $reader | ||
| * @param Reader $reader | ||
| */ | ||
| public function __construct(ScenarioStateInitializer $store, Reader $reader) | ||
| public function __construct(array $hookers, Reader $reader) | ||
| { | ||
| $this->store = $store; | ||
| $this->hookers = $hookers; | ||
| $this->reader = $reader; | ||
| } | ||
|
|
||
|
|
@@ -48,25 +46,27 @@ public function __construct(ScenarioStateInitializer $store, Reader $reader) | |
| */ | ||
| public function resolve(\ReflectionMethod $function, array $arguments) | ||
| { | ||
| // No `@ScenarioStateArgument` annotation found | ||
| if (null === $this->reader->getMethodAnnotation($function, ScenarioStateArgument::class)) { | ||
| // No `@StepArgumentInjectorArgument` annotation found | ||
| if (null === $this->reader->getMethodAnnotation($function, StepInjectorArgument::class)) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| return $arguments; | ||
| } | ||
|
|
||
| $paramsKeys = array_map(function (\ReflectionParameter $element) { | ||
| return $element->getName(); | ||
| }, $function->getParameters()); | ||
| $store = $this->store->getStore(); | ||
|
|
||
| // Prepare arguments from annotations | ||
| /** @var ScenarioStateArgument[] $annotations */ | ||
| /** @var StepArgumentInjectorArgument[] $annotations */ | ||
| $annotations = $this->reader->getMethodAnnotations($function); | ||
| foreach ($annotations as $annotation) { | ||
| if ($annotation instanceof ScenarioStateArgument && | ||
| in_array($annotation->getArgument(), $paramsKeys) && | ||
| $store->hasStateFragment($annotation->getName()) | ||
| if ($annotation instanceof StepInjectorArgument && | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if (!$annotation instanceof StepInjectorArgument ||
!in_array($argument = $annotation->getArgument(), $paramsKeys)
) {
continue;
}There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicated code from ArgumentOrganiser |
||
| in_array($annotation->getArgument(), $paramsKeys) | ||
| ) { | ||
| $arguments[$annotation->getArgument()] = $store->getStateFragment($annotation->getName()); | ||
| foreach ($this->hookers as $hooker) { | ||
| if ($hooker->hasStepArgumentFor($annotation->getName())) { | ||
|
||
| $arguments[$annotation->getArgument()] = $hooker->getStepArgumentFor($annotation->getName()); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| <?php | ||
|
|
||
| /* | ||
| * This file is part of the StepArgumentInjectorBehatExtension project. | ||
| * | ||
| * (c) Rodrigue Villetard <[email protected]> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
|
|
||
| namespace Gorghoa\StepArgumentInjectorBehatExtension\ServiceContainer; | ||
|
|
||
| use Behat\Testwork\Argument\ServiceContainer\ArgumentExtension; | ||
| use Behat\Testwork\Call\ServiceContainer\CallExtension; | ||
| use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface; | ||
| use Behat\Testwork\ServiceContainer\ExtensionManager; | ||
| use Doctrine\Common\Annotations\AnnotationReader; | ||
| use Gorghoa\StepArgumentInjectorBehatExtension\Argument\ArgumentOrganiser; | ||
| use Gorghoa\StepArgumentInjectorBehatExtension\Call\Handler\RuntimeCallHandler; | ||
| use Gorghoa\StepArgumentInjectorBehatExtension\Resolver\ArgumentsResolver; | ||
| use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; | ||
| use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
| use Symfony\Component\DependencyInjection\Reference; | ||
|
|
||
| /** | ||
| * Behat store for Behat contexts. | ||
| * | ||
| * @author Rodrigue Villetard <[email protected]> | ||
| * @author Vincent Chalamon <[email protected]> | ||
| */ | ||
| class StepArgumentInjectorExtension implements ExtensionInterface | ||
| { | ||
| const STEP_ARGUMENT_INJECTOR_ARGUMENT_ORGANISER_ID = 'argument.step_argument_injector.organiser'; | ||
| const STEP_ARGUMENT_INJECTOR_DISPATCHER_ID = 'hook.step_argument_injector.dispatcher'; | ||
| const STEP_ARGUMENT_INJECTOR_TESTER_ID = 'tester.step_argument_injector.wrapper'; | ||
| const STEP_ARGUMENT_INJECTOR_CALL_HANDLER_ID = 'call.step_argument_injector.call_handler'; | ||
| const STEP_ARGUMENT_INJECTOR_ARGUMENTS_RESOLVER_ID = 'step_argument_injector.arguments_resolver'; | ||
| const STEP_ARGUMENT_INJECTOR_STORE_ID = 'behatstore.context_initializer.store_aware'; | ||
| const STEP_ARGUMENT_INJECTOR_DOCTRINE_READER_ID = 'doctrine.reader.annotation'; | ||
| const STEP_ARGUMENT_INJECTOR_HOOK_TAG_ID = 'step_argument_injector.hook_tag_id'; | ||
|
|
||
| /** | ||
| * {@inheritdoc} | ||
| */ | ||
| public function getConfigKey() | ||
| { | ||
| return 'stepargumentinjector'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
|
|
||
| /** | ||
| * {@inheritdoc} | ||
| */ | ||
| public function initialize(ExtensionManager $extensionManager) | ||
| { | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritdoc} | ||
| */ | ||
| public function configure(ArrayNodeDefinition $builder) | ||
| { | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritdoc} | ||
| */ | ||
| public function load(ContainerBuilder $container, array $config) | ||
| { | ||
| // Declare Doctrine annotation reader as service | ||
| $container->register(self::STEP_ARGUMENT_INJECTOR_DOCTRINE_READER_ID, AnnotationReader::class) | ||
| // Ignore Behat annotations in reader | ||
| ->addMethodCall('addGlobalIgnoredName', ['Given']) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to #32 (comment), you should also ignore lowercase |
||
| ->addMethodCall('addGlobalIgnoredName', ['When']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['Then']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['Transform']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['BeforeStep']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['BeforeScenario']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['BeforeFeature']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['BeforeSuite']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['AfterStep']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['AfterScenario']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['AfterFeature']) | ||
| ->addMethodCall('addGlobalIgnoredName', ['AfterSuite']); | ||
|
|
||
| $taggedServices = array_map(function ($serviceId) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a local variable, you can name it as you want (but please not a too long variable name 😉 ) |
||
| return new Reference($serviceId); | ||
| }, array_keys($container->findTaggedServiceIds(self::STEP_ARGUMENT_INJECTOR_HOOK_TAG_ID))); | ||
|
|
||
| // Arguments resolver: resolve StepArgumentInjector arguments from annotation | ||
| $container->register(self::STEP_ARGUMENT_INJECTOR_ARGUMENTS_RESOLVER_ID, ArgumentsResolver::class) | ||
| ->setArguments([ | ||
| $taggedServices, | ||
| new Reference(self::STEP_ARGUMENT_INJECTOR_DOCTRINE_READER_ID), | ||
| ]); | ||
|
|
||
| // Argument organiser | ||
| $container->register(self::STEP_ARGUMENT_INJECTOR_ARGUMENT_ORGANISER_ID, ArgumentOrganiser::class) | ||
| ->setDecoratedService(ArgumentExtension::PREG_MATCH_ARGUMENT_ORGANISER_ID) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should find a better way to extend Behat without decorating its kernel services. |
||
| ->setPublic(false) | ||
| ->setArguments([ | ||
| new Reference(sprintf('%s.inner', self::STEP_ARGUMENT_INJECTOR_ARGUMENT_ORGANISER_ID)), | ||
| $taggedServices, | ||
| new Reference(self::STEP_ARGUMENT_INJECTOR_DOCTRINE_READER_ID), | ||
| new Reference(self::STEP_ARGUMENT_INJECTOR_ARGUMENTS_RESOLVER_ID), | ||
| ]); | ||
|
|
||
| // Override calls process | ||
| $container->register(self::STEP_ARGUMENT_INJECTOR_CALL_HANDLER_ID, RuntimeCallHandler::class) | ||
| ->setDecoratedService(CallExtension::CALL_HANDLER_TAG.'.runtime') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same |
||
| ->setArguments([ | ||
| new Reference(self::STEP_ARGUMENT_INJECTOR_CALL_HANDLER_ID.'.inner'), | ||
| new Reference(self::STEP_ARGUMENT_INJECTOR_ARGUMENTS_RESOLVER_ID), | ||
| ]); | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritdoc} | ||
| */ | ||
| public function process(ContainerBuilder $container) | ||
| { | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"php":"7.1.7-1+0~20170711133214.5+stretch~1.gbp5284f4","version":"2.4.0:v2.4.0#63661f3add3609e90e4ab8115113e189ae547bb4","rules":{"binary_operator_spaces":{"align_double_arrow":false,"align_equals":false},"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["return"]},"braces":{"allow_single_line_closure":true},"cast_spaces":true,"class_definition":{"singleLine":true},"concat_space":{"spacing":"none"},"declare_equal_normalize":true,"function_typehint_space":true,"hash_to_slash_comment":true,"include":true,"lowercase_cast":true,"magic_constant_casing":true,"method_argument_space":true,"method_separation":true,"native_function_casing":true,"new_with_braces":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_empty_comment":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_consecutive_blank_lines":{"tokens":["curly_brace_block","extra","parenthesis_brace_block","square_brace_block","throw","use"]},"no_leading_import_slash":true,"no_leading_namespace_whitespace":true,"no_mixed_echo_print":{"use":"echo"},"no_multiline_whitespace_around_double_arrow":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_around_offset":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_unneeded_control_parentheses":true,"no_unused_imports":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"object_operator_without_whitespace":true,"php_unit_fqcn_annotation":true,"phpdoc_align":true,"phpdoc_annotation_without_dot":true,"phpdoc_indent":true,"phpdoc_inline_tag":true,"phpdoc_no_access":true,"phpdoc_no_alias_tag":true,"phpdoc_no_empty_return":true,"phpdoc_no_package":true,"phpdoc_no_useless_inheritdoc":true,"phpdoc_return_self_reference":true,"phpdoc_scalar":true,"phpdoc_separation":true,"phpdoc_single_line_var_spacing":true,"phpdoc_summary":true,"phpdoc_to_comment":true,"phpdoc_trim":true,"phpdoc_types":true,"phpdoc_var_without_name":true,"pre_increment":true,"protected_to_private":true,"return_type_declaration":true,"self_accessor":true,"short_scalar_cast":true,"single_blank_line_before_namespace":true,"single_class_element_per_statement":true,"single_quote":true,"space_after_semicolon":true,"standardize_not_equals":true,"ternary_operator_spaces":true,"trailing_comma_in_multiline_array":true,"trim_array_spaces":true,"unary_operator_spaces":true,"whitespace_after_comma_in_array":true,"blank_line_after_namespace":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"encoding":true,"full_opening_tag":true},"hashes":{"\/ScenarioStateInterface.php":2824836438,"\/Annotation\/ScenarioStateArgument.php":2979727378,"\/Context\/Initializer\/ScenarioStateInitializer.php":781987277,"\/Context\/ScenarioStateAwareTrait.php":2441401241,"\/Context\/ScenarioStateAwareContext.php":1438795547,"\/ScenarioState.php":3549039778,"\/ServiceContainer\/ScenarioStateExtension.php":1698856486,"\/Exception\/MissingStateException.php":1656618837}} | ||
|
||

Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This interface may still be too related with the state sharing business 🤔
Why on earth should we force the annotation to deal with the
getName?getArgumentmay be enough, but does it? Maybe we could get rid of it too…