Skip to content

Commit

Permalink
attempt to resolve most open questions; this commit should be squashe…
Browse files Browse the repository at this point in the history
…d before merging
  • Loading branch information
Ladicek committed Dec 13, 2023
1 parent 3ae55d9 commit 3db2e81
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 18 deletions.
7 changes: 5 additions & 2 deletions api/src/main/java/jakarta/enterprise/invoke/Invoker.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

package jakarta.enterprise.invoke;

import java.lang.reflect.InvocationTargetException;

/**
* An invoker allows indirect invocation of its target method on an instance of its target
* bean.
Expand Down Expand Up @@ -50,7 +52,7 @@ public interface Invoker<T, R> {
* given {@code arguments}. If the target method returns normally, this method returns
* its return value, unless the target method is declared {@code void}, in which case
* this method returns {@code null}. If the target method throws an exception, this
* method rethrows it directly.
* method wraps it into an {@code InvocationTargetException} and throws that.
* <p>
* The {@code instance} must be assignable to the target bean. Each of the {@code arguments}
* must be assignable to the corresponding parameter of the target method.
Expand All @@ -61,6 +63,7 @@ public interface Invoker<T, R> {
* if the target method declares no parameter
* @return return value of the target method, or {@code null} if the target method
* is declared {@code void}
* @throws InvocationTargetException when the target method throws an exception
*/
R invoke(T instance, Object[] arguments); // TODO throws Exception ?
R invoke(T instance, Object[] arguments) throws InvocationTargetException;
}
26 changes: 10 additions & 16 deletions spec/src/main/asciidoc/core/invokers.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The `Invoker` interface contains a single method:
[source,java]
----
public interface Invoker<T, R> {
R invoke(T instance, Object[] arguments);
R invoke(T instance, Object[] arguments) throws InvocationTargetException;
}
----

Expand All @@ -57,27 +57,21 @@ Whenever a direct invocation of a method on an object is a business method invoc

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 rethrown.
The `invoke()` method does not declare any checked exception; implementations are supposed to use the "sneaky throw" idiom.
// TODO maybe change that?
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 `NullPointerException` is thrown.
If the target method is not `static` and the `instance` is not <<invoker_assignability,assignable>> to the target bean, a `ClassCastException` 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.

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).

If the target method declares no parameter, `arguments` are ignored.
If the target method declares any parameter and `arguments` is `null`, `NullPointerException` is thrown.
If the `arguments` array has fewer elements than the number of parameters of the target method, `ArrayIndexOutOfBoundsException` is thrown.
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, `ClassCastException` is thrown.

If the declared type of a parameter of the target method is a primitive type, then:

* if the corresponding argument is `null`, the default value of the primitive type is passed;
* if the corresponding argument is not `null`, unboxing conversion is performed on the argument and the result is passed.
If some of the `arguments` is not <<invoker_assignability,assignable>> to the corresponding parameter of the target method, `RuntimeException` is thrown.

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.

// 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 @@ -161,12 +155,12 @@ Calling `InvokerBuilder.build()` produces an opaque token (`InvokerInfo`) that c
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;
* 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 primitive wrapper class of `P`;
* `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`;
Expand Down

0 comments on commit 3db2e81

Please sign in to comment.