Skip to content

Commit

Permalink
avoid unnecessarily formulating special assignability rules for invok…
Browse files Browse the repository at this point in the history
…ers; this commit should be squashed before merging
  • Loading branch information
Ladicek committed Jan 4, 2024
1 parent c1279a0 commit 6a2416e
Showing 1 changed file with 11 additions and 32 deletions.
43 changes: 11 additions & 32 deletions spec/src/main/asciidoc/core/invokers.asciidoc
Expand Up @@ -56,23 +56,27 @@ Whenever a direct invocation of a method on an object is a business method invoc
==== Behavior of `invoke()`

If the target method is `static`, the `instance` is ignored; by convention, it should be `null`.
If the target method returns normally, its return value is returned, unless the target method is declared `void`, in which case `null` is returned.
If the target method throws an exception, it is wrapped into `InvocationTargetException` and that is thrown.

If the target method is not `static` and `instance` is `null`, a `RuntimeException` is thrown.
If the target method is not `static` and the `instance` is not <<invoker_assignability,assignable>> to the target bean, a `RuntimeException` is thrown.
If the target method is not `static` and the class of the `instance` is not a subclass of the bean class of the target bean, a `RuntimeException` is thrown.


Correspondence between given `arguments` and declared parameters of the target method is positional: the Nth element of the `arguments` array is passed as the Nth argument to the target method.
If the target method is a variable arity method, the last element of the `arguments` array corresponds to the variable arity parameter (and therefore must be an array).
When passing an argument to the method, the applicable method invocation conversion is performed.

If the target method declares no parameter, `arguments` are ignored.
If the target method declares any parameter and `arguments` is `null`, `RuntimeException` is thrown.
If the `arguments` array has fewer elements than the number of parameters of the target method, `RuntimeException` is thrown.
If the `arguments` array has more elements than the number of parameters of the target method, the excess elements are ignored.
If some of the `arguments` is not <<invoker_assignability,assignable>> to the corresponding parameter of the target method, `RuntimeException` is thrown.
If a method invocation conversion does not exist from the class of some of the `arguments` (or from the null type if the argument is `null`) to the declared type of the corresponding parameter of the target method, `RuntimeException` is thrown.

NOTE: The type checking and conversion rules are aligned with pre-existing mechanisms for indirect method invocations, the Java reflection API and the method handles API.

If the declared type of a parameter of the target method is a primitive type, an unboxing conversion is performed on the corresponding argument, a widening primitive conversion is performed on the result if needed, and the result is passed.
If the declared type of a parameter of the target method is not a primitive type, the corresponding argument is passed as is.
When the declared type of a parameter of the target method is not a reifiable type, callers of `Invoker.invoke()` must ensure that the corresponding argument is constructed appropriately.
Otherwise, runtime failures are likely to occur.

If the target method returns normally, its return value is returned (after boxing conversion if the target method's return type is a primitive type), unless the target method is declared `void`, in which case `null` is returned.
If the target method throws an exception, it is wrapped into `InvocationTargetException` and that is thrown.

// TODO when the `InvokerBuilder` applies transformations, some of the requirements above are no longer strictly necessary, we should reflect that in this text somehow

Expand Down Expand Up @@ -148,28 +152,3 @@ The target method of the created invoker is the method represented by the `Metho
Calling `InvokerBuilder.build()` produces an opaque token (`InvokerInfo`) that can be passed as a parameter to a `SyntheticBeanBuilder` or `SyntheticObserverBuilder` and materializes as an `Invoker` at application runtime.

// TODO lookups, transformers, wrappers

[[invoker_assignability]]
=== Assignability for invokers

For the purpose of `Invoker.invoke()`, assignability is defined as:

* a non-`null` instance is assignable to the target bean when the class of the instance is a subclass of the bean class of the target bean;
* a `null` argument is assignable to any parameter of the target method that does not declare a primitive type;
* a non-`null` argument is assignable to a parameter of the target method when the class of the argument is assignable to the erasure of the declared type of the parameter, as defined below.

If an argument class is denoted `A` and the erasure of the declared type of a parameter is denoted `P`, then:

* `A` is assignable to a primitive type `P` when `A` is the wrapper class of `P` or when `A` is a wrapper class of a primitive type for which a widening primitive conversion to `P` exists;
* `A` is assignable to a class or interface type `P` when:
** `A` is a class or interface type and `A` is a subclass of `P`, or
** `A` is an array type and `P` is `java.lang.Object`, `java.lang.Cloneable`, or `java.io.Serializable`;
* `A` is assignable to an array type `P` when `A` is an array type and:
** the component type of `P` is a primitive type and the component types of `A` and `P` are identical, or
** the component type of `P` is not a primitive type and the component type of `A` is assignable to the component type of `P` according to these rules.

NOTE: This is a reformulation of the JVM assignability rules as defined by the specification of the `checkcast` and `instanceof` instructions, with addition of primitive types.
It is expected that CDI implementations do not implement these rules and rely on JVM runtime checks.

When the declared type of a parameter of the target method is not a reifiable type, callers of `Invoker.invoke()` must also ensure that the corresponding argument is constructed appropriately.
Otherwise, runtime failures are likely to occur.

0 comments on commit 6a2416e

Please sign in to comment.